From 0137be2a2eab38381b5760c760139427ecd649b3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 27 Jul 2018 12:08:54 +0200 Subject: tcp: avoid collapses in tcp_prune_queue() if possible [ Upstream commit f4a3313d8e2ca9fd8d8f45e40a2903ba782607e7 ] Right after a TCP flow is created, receiving tiny out of order packets allways hit the condition : if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) tcp_clamp_window(sk); tcp_clamp_window() increases sk_rcvbuf to match sk_rmem_alloc (guarded by tcp_rmem[2]) Calling tcp_collapse_ofo_queue() in this case is not useful, and offers a O(N^2) surface attack to malicious peers. Better not attempt anything before full queue capacity is reached, forcing attacker to spend lots of resource and allow us to more easily detect the abuse. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 667a2573317f..c757a74b2916 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4866,6 +4866,9 @@ static int tcp_prune_queue(struct sock *sk) else if (tcp_under_memory_pressure(sk)) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); + if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) + return 0; + tcp_collapse_ofo_queue(sk); if (!skb_queue_empty(&sk->sk_receive_queue)) tcp_collapse(sk, &sk->sk_receive_queue, -- cgit v1.2.3 From 14e0533779770031121dd695807c9f55525c61e9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 27 Jul 2018 12:08:55 +0200 Subject: tcp: detect malicious patterns in tcp_collapse_ofo_queue() [ Upstream commit 3d4bf93ac12003f9b8e1e2de37fe27983deebdcf ] In case an attacker feeds tiny packets completely out of order, tcp_collapse_ofo_queue() might scan the whole rb-tree, performing expensive copies, but not changing socket memory usage at all. 1) Do not attempt to collapse tiny skbs. 2) Add logic to exit early when too many tiny skbs are detected. We prefer not doing aggressive collapsing (which copies packets) for pathological flows, and revert to tcp_prune_ofo_queue() which will be less expensive. In the future, we might add the possibility of terminating flows that are proven to be malicious. Signed-off-by: Eric Dumazet Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c757a74b2916..cc9874d7f223 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4780,6 +4780,7 @@ restart: static void tcp_collapse_ofo_queue(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); + u32 range_truesize, sum_tiny = 0; struct sk_buff *skb = skb_peek(&tp->out_of_order_queue); struct sk_buff *head; u32 start, end; @@ -4789,6 +4790,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk) start = TCP_SKB_CB(skb)->seq; end = TCP_SKB_CB(skb)->end_seq; + range_truesize = skb->truesize; head = skb; for (;;) { @@ -4803,8 +4805,17 @@ static void tcp_collapse_ofo_queue(struct sock *sk) if (!skb || after(TCP_SKB_CB(skb)->seq, end) || before(TCP_SKB_CB(skb)->end_seq, start)) { - tcp_collapse(sk, &tp->out_of_order_queue, - head, skb, start, end); + /* Do not attempt collapsing tiny skbs */ + if (range_truesize != head->truesize || + end - start >= SKB_WITH_OVERHEAD(SK_MEM_QUANTUM)) { + tcp_collapse(sk, &tp->out_of_order_queue, + head, skb, start, end); + } else { + sum_tiny += range_truesize; + if (sum_tiny > sk->sk_rcvbuf >> 3) + return; + } + head = skb; if (!skb) break; -- cgit v1.2.3 From c4067f44efd01ef002d88d7c70c90373c1b358fe Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 27 Jul 2018 13:58:53 +0200 Subject: Fix backport of "tcp: detect malicious patterns in tcp_collapse_ofo_queue()" Based on review from Eric Dumazet, my backport of commit 3d4bf93ac12003f9b8e1e2de37fe27983deebdcf to older kernels was a bit incorrect. This patch fixes this. Reported-by: Eric Dumazet Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index cc9874d7f223..d3b7172b9ee0 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4822,6 +4822,7 @@ static void tcp_collapse_ofo_queue(struct sock *sk) /* Start new segment */ start = TCP_SKB_CB(skb)->seq; end = TCP_SKB_CB(skb)->end_seq; + range_truesize = skb->truesize; } else { if (before(TCP_SKB_CB(skb)->seq, start)) start = TCP_SKB_CB(skb)->seq; -- cgit v1.2.3 From 676efbc954887ea35e34c68d59205740d887c594 Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Wed, 5 Sep 2018 09:39:22 -0700 Subject: ANDROID: arm64: mm: fix 4.4.154 merge android-4.4 contains an out-of-tree backport of 68709f45385a ("arm64: only consider memblocks with NOMAP cleared for linear mapping"), so it should use the 4.9.y implementation of pfn_valid() that calls memblock_is_map_memory(). Reported-by: Nathan Chancellor Signed-off-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/mm/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 17393bad19eb..60e113a7c5db 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -134,7 +134,7 @@ int pfn_valid(unsigned long pfn) if ((addr >> PAGE_SHIFT) != pfn) return 0; - return memblock_is_memory(addr); + return memblock_is_map_memory(addr); } EXPORT_SYMBOL(pfn_valid); #endif -- cgit v1.2.3 From 0cb3f9f0b8ee04a809279018f5408efdd13f418e Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 8 Jun 2017 16:44:22 -0700 Subject: arm64/vdso: Fix nsec handling for CLOCK_MONOTONIC_RAW commit dbb236c1ceb697a559e0694ac4c9e7b9131d0b16 upstream. Recently vDSO support for CLOCK_MONOTONIC_RAW was added in 49eea433b326 ("arm64: Add support for CLOCK_MONOTONIC_RAW in clock_gettime() vDSO"). Noticing that the core timekeeping code never set tkr_raw.xtime_nsec, the vDSO implementation didn't bother exposing it via the data page and instead took the unshifted tk->raw_time.tv_nsec value which was then immediately shifted left in the vDSO code. Unfortunately, by accellerating the MONOTONIC_RAW clockid, it uncovered potential 1ns time inconsistencies caused by the timekeeping core not handing sub-ns resolution. Now that the core code has been fixed and is actually setting tkr_raw.xtime_nsec, we need to take that into account in the vDSO by adding it to the shifted raw_time value, in order to fix the user-visible inconsistency. Rather than do that at each use (and expand the data page in the process), instead perform the shift/addition operation when populating the data page and remove the shift from the vDSO code entirely. [jstultz: minor whitespace tweak, tried to improve commit message to make it more clear this fixes a regression] Reported-by: John Stultz Signed-off-by: Will Deacon Signed-off-by: John Stultz Tested-by: Daniel Mentz Acked-by: Kevin Brodsky Cc: Prarit Bhargava Cc: Richard Cochran Cc: Stephen Boyd Cc: Miroslav Lichvar Link: http://lkml.kernel.org/r/1496965462-20003-4-git-send-email-john.stultz@linaro.org Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman Change-Id: I51b5ebd994635eb091ad6a084ddfa12074f27d81 Tested-by: Freddy Hsin Signed-off-by: Miles Chen --- arch/arm64/kernel/vdso.c | 1 - arch/arm64/kernel/vdso/gettimeofday.S | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index 7e9dd94452bb..46fa4de29fb1 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c @@ -222,7 +222,6 @@ void update_vsyscall(struct timekeeper *tk) vdso_data->raw_time_nsec = tk->tkr_raw.xtime_nsec; vdso_data->xtime_clock_sec = tk->xtime_sec; vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec; - /* tkr_raw.xtime_nsec == 0 */ vdso_data->cs_mono_mult = tk->tkr_mono.mult; vdso_data->cs_raw_mult = tk->tkr_raw.mult; /* tkr_mono.shift == tkr_raw.shift */ diff --git a/arch/arm64/kernel/vdso/gettimeofday.S b/arch/arm64/kernel/vdso/gettimeofday.S index c97ce91cf023..c39872a7b03c 100644 --- a/arch/arm64/kernel/vdso/gettimeofday.S +++ b/arch/arm64/kernel/vdso/gettimeofday.S @@ -256,7 +256,6 @@ monotonic_raw: seqcnt_check fail=monotonic_raw /* All computations are done with left-shifted nsecs. */ - lsl x14, x14, x12 get_nsec_per_sec res=x9 lsl x9, x9, x12 -- cgit v1.2.3 From 4f4c0eed53749781796e3cb4f70f9346982ea4c5 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 19 Jul 2018 18:08:35 -0700 Subject: ANDROID: sdcardfs: Don't use OVERRIDE_CRED macro The macro hides some control flow, making it easier to run into bugs. bug: 111642636 Change-Id: I37ec207c277d97c4e7f1e8381bc9ae743ad78435 Reported-by: Jann Horn Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/file.c | 24 ++++-- fs/sdcardfs/inode.c | 198 ++++++++++--------------------------------------- fs/sdcardfs/lookup.c | 9 ++- fs/sdcardfs/sdcardfs.h | 25 ------- 4 files changed, 66 insertions(+), 190 deletions(-) diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 1461254f301d..271c4c4cb760 100644 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -118,7 +118,11 @@ static long sdcardfs_unlocked_ioctl(struct file *file, unsigned int cmd, goto out; /* save current_cred and override it */ - OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(file_inode(file))); + saved_cred = override_fsids(sbi, SDCARDFS_I(file_inode(file))->data); + if (!saved_cred) { + err = -ENOMEM; + goto out; + } if (lower_file->f_op->unlocked_ioctl) err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg); @@ -127,7 +131,7 @@ static long sdcardfs_unlocked_ioctl(struct file *file, unsigned int cmd, if (!err) sdcardfs_copy_and_fix_attrs(file_inode(file), file_inode(lower_file)); - REVERT_CRED(saved_cred); + revert_fsids(saved_cred); out: return err; } @@ -149,12 +153,16 @@ static long sdcardfs_compat_ioctl(struct file *file, unsigned int cmd, goto out; /* save current_cred and override it */ - OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(file_inode(file))); + saved_cred = override_fsids(sbi, SDCARDFS_I(file_inode(file))->data); + if (!saved_cred) { + err = -ENOMEM; + goto out; + } if (lower_file->f_op->compat_ioctl) err = lower_file->f_op->compat_ioctl(lower_file, cmd, arg); - REVERT_CRED(saved_cred); + revert_fsids(saved_cred); out: return err; } @@ -241,7 +249,11 @@ static int sdcardfs_open(struct inode *inode, struct file *file) } /* save current_cred and override it */ - OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(inode)); + saved_cred = override_fsids(sbi, SDCARDFS_I(inode)->data); + if (!saved_cred) { + err = -ENOMEM; + goto out_err; + } file->private_data = kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL); @@ -271,7 +283,7 @@ static int sdcardfs_open(struct inode *inode, struct file *file) sdcardfs_copy_and_fix_attrs(inode, sdcardfs_lower_inode(inode)); out_revert_cred: - REVERT_CRED(saved_cred); + revert_fsids(saved_cred); out_err: dput(parent); return err; diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 75a8ab2ce5a8..0b9c345cd01c 100644 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -22,7 +22,6 @@ #include #include -/* Do not directly use this function. Use OVERRIDE_CRED() instead. */ const struct cred *override_fsids(struct sdcardfs_sb_info *sbi, struct sdcardfs_inode_data *data) { @@ -50,7 +49,6 @@ const struct cred *override_fsids(struct sdcardfs_sb_info *sbi, return old_cred; } -/* Do not directly use this function, use REVERT_CRED() instead. */ void revert_fsids(const struct cred *old_cred) { const struct cred *cur_cred; @@ -78,7 +76,10 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, } /* save current_cred and override it */ - OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); + saved_cred = override_fsids(SDCARDFS_SB(dir->i_sb), + SDCARDFS_I(dir)->data); + if (!saved_cred) + return -ENOMEM; sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; @@ -115,53 +116,11 @@ out: out_unlock: unlock_dir(lower_parent_dentry); sdcardfs_put_lower_path(dentry, &lower_path); - REVERT_CRED(saved_cred); + revert_fsids(saved_cred); out_eacces: return err; } -#if 0 -static int sdcardfs_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *new_dentry) -{ - struct dentry *lower_old_dentry; - struct dentry *lower_new_dentry; - struct dentry *lower_dir_dentry; - u64 file_size_save; - int err; - struct path lower_old_path, lower_new_path; - - OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb)); - - file_size_save = i_size_read(d_inode(old_dentry)); - sdcardfs_get_lower_path(old_dentry, &lower_old_path); - sdcardfs_get_lower_path(new_dentry, &lower_new_path); - lower_old_dentry = lower_old_path.dentry; - lower_new_dentry = lower_new_path.dentry; - lower_dir_dentry = lock_parent(lower_new_dentry); - - err = vfs_link(lower_old_dentry, d_inode(lower_dir_dentry), - lower_new_dentry, NULL); - if (err || !d_inode(lower_new_dentry)) - goto out; - - err = sdcardfs_interpose(new_dentry, dir->i_sb, &lower_new_path); - if (err) - goto out; - fsstack_copy_attr_times(dir, d_inode(lower_new_dentry)); - fsstack_copy_inode_size(dir, d_inode(lower_new_dentry)); - set_nlink(d_inode(old_dentry), - sdcardfs_lower_inode(d_inode(old_dentry))->i_nlink); - i_size_write(d_inode(new_dentry), file_size_save); -out: - unlock_dir(lower_dir_dentry); - sdcardfs_put_lower_path(old_dentry, &lower_old_path); - sdcardfs_put_lower_path(new_dentry, &lower_new_path); - REVERT_CRED(); - return err; -} -#endif - static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) { int err; @@ -178,7 +137,10 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry) } /* save current_cred and override it */ - OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); + saved_cred = override_fsids(SDCARDFS_SB(dir->i_sb), + SDCARDFS_I(dir)->data); + if (!saved_cred) + return -ENOMEM; sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; @@ -209,43 +171,11 @@ out: unlock_dir(lower_dir_dentry); dput(lower_dentry); sdcardfs_put_lower_path(dentry, &lower_path); - REVERT_CRED(saved_cred); + revert_fsids(saved_cred); out_eacces: return err; } -#if 0 -static int sdcardfs_symlink(struct inode *dir, struct dentry *dentry, - const char *symname) -{ - int err; - struct dentry *lower_dentry; - struct dentry *lower_parent_dentry = NULL; - struct path lower_path; - - OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb)); - - sdcardfs_get_lower_path(dentry, &lower_path); - lower_dentry = lower_path.dentry; - lower_parent_dentry = lock_parent(lower_dentry); - - err = vfs_symlink(d_inode(lower_parent_dentry), lower_dentry, symname); - if (err) - goto out; - err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path); - if (err) - goto out; - fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); - fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry)); - -out: - unlock_dir(lower_parent_dentry); - sdcardfs_put_lower_path(dentry, &lower_path); - REVERT_CRED(); - return err; -} -#endif - static int touch(char *abs_path, mode_t mode) { struct file *filp = filp_open(abs_path, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, mode); @@ -287,7 +217,10 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode } /* save current_cred and override it */ - OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); + saved_cred = override_fsids(SDCARDFS_SB(dir->i_sb), + SDCARDFS_I(dir)->data); + if (!saved_cred) + return -ENOMEM; /* check disk space */ parent_dentry = dget_parent(dentry); @@ -366,13 +299,21 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode if (make_nomedia_in_obb || ((pd->perm == PERM_ANDROID) && (qstr_case_eq(&dentry->d_name, &q_data)))) { - REVERT_CRED(saved_cred); - OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(d_inode(dentry))); + revert_fsids(saved_cred); + saved_cred = override_fsids(sbi, + SDCARDFS_I(d_inode(dentry))->data); + if (!saved_cred) { + pr_err("sdcardfs: failed to set up .nomedia in %s: %d\n", + lower_path.dentry->d_name.name, + -ENOMEM); + goto out; + } set_fs_pwd(current->fs, &lower_path); touch_err = touch(".nomedia", 0664); if (touch_err) { pr_err("sdcardfs: failed to create .nomedia in %s: %d\n", - lower_path.dentry->d_name.name, touch_err); + lower_path.dentry->d_name.name, + touch_err); goto out; } } @@ -382,7 +323,7 @@ out: out_unlock: sdcardfs_put_lower_path(dentry, &lower_path); out_revert: - REVERT_CRED(saved_cred); + revert_fsids(saved_cred); out_eacces: return err; } @@ -402,7 +343,10 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) } /* save current_cred and override it */ - OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); + saved_cred = override_fsids(SDCARDFS_SB(dir->i_sb), + SDCARDFS_I(dir)->data); + if (!saved_cred) + return -ENOMEM; /* sdcardfs_get_real_lower(): in case of remove an user's obb dentry * the dentry on the original path should be deleted. @@ -427,44 +371,11 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry) out: unlock_dir(lower_dir_dentry); sdcardfs_put_real_lower(dentry, &lower_path); - REVERT_CRED(saved_cred); + revert_fsids(saved_cred); out_eacces: return err; } -#if 0 -static int sdcardfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, - dev_t dev) -{ - int err; - struct dentry *lower_dentry; - struct dentry *lower_parent_dentry = NULL; - struct path lower_path; - - OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb)); - - sdcardfs_get_lower_path(dentry, &lower_path); - lower_dentry = lower_path.dentry; - lower_parent_dentry = lock_parent(lower_dentry); - - err = vfs_mknod(d_inode(lower_parent_dentry), lower_dentry, mode, dev); - if (err) - goto out; - - err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path); - if (err) - goto out; - fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir)); - fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry)); - -out: - unlock_dir(lower_parent_dentry); - sdcardfs_put_lower_path(dentry, &lower_path); - REVERT_CRED(); - return err; -} -#endif - /* * The locking rules in sdcardfs_rename are complex. We could use a simpler * superblock-level name-space lock for renames and copy-ups. @@ -489,7 +400,10 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry, } /* save current_cred and override it */ - OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred, SDCARDFS_I(new_dir)); + saved_cred = override_fsids(SDCARDFS_SB(old_dir->i_sb), + SDCARDFS_I(new_dir)->data); + if (!saved_cred) + return -ENOMEM; sdcardfs_get_real_lower(old_dentry, &lower_old_path); sdcardfs_get_lower_path(new_dentry, &lower_new_path); @@ -536,7 +450,7 @@ out: dput(lower_new_dir_dentry); sdcardfs_put_real_lower(old_dentry, &lower_old_path); sdcardfs_put_lower_path(new_dentry, &lower_new_path); - REVERT_CRED(saved_cred); + revert_fsids(saved_cred); out_eacces: return err; } @@ -655,33 +569,7 @@ static int sdcardfs_permission(struct vfsmount *mnt, struct inode *inode, int ma if (IS_POSIXACL(inode)) pr_warn("%s: This may be undefined behavior...\n", __func__); err = generic_permission(&tmp, mask); - /* XXX - * Original sdcardfs code calls inode_permission(lower_inode,.. ) - * for checking inode permission. But doing such things here seems - * duplicated work, because the functions called after this func, - * such as vfs_create, vfs_unlink, vfs_rename, and etc, - * does exactly same thing, i.e., they calls inode_permission(). - * So we just let they do the things. - * If there are any security hole, just uncomment following if block. - */ -#if 0 - if (!err) { - /* - * Permission check on lower_inode(=EXT4). - * we check it with AID_MEDIA_RW permission - */ - struct inode *lower_inode; - - OVERRIDE_CRED(SDCARDFS_SB(inode->sb)); - - lower_inode = sdcardfs_lower_inode(inode); - err = inode_permission(lower_inode, mask); - - REVERT_CRED(); - } -#endif return err; - } static int sdcardfs_setattr_wrn(struct dentry *dentry, struct iattr *ia) @@ -756,7 +644,10 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct goto out_err; /* save current_cred and override it */ - OVERRIDE_CRED(SDCARDFS_SB(dentry->d_sb), saved_cred, SDCARDFS_I(inode)); + saved_cred = override_fsids(SDCARDFS_SB(dentry->d_sb), + SDCARDFS_I(inode)->data); + if (!saved_cred) + return -ENOMEM; sdcardfs_get_lower_path(dentry, &lower_path); lower_dentry = lower_path.dentry; @@ -815,7 +706,7 @@ static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct out: sdcardfs_put_lower_path(dentry, &lower_path); - REVERT_CRED(saved_cred); + revert_fsids(saved_cred); out_err: return err; } @@ -898,13 +789,6 @@ const struct inode_operations sdcardfs_dir_iops = { .setattr = sdcardfs_setattr_wrn, .setattr2 = sdcardfs_setattr, .getattr = sdcardfs_getattr, - /* XXX Following operations are implemented, - * but FUSE(sdcard) or FAT does not support them - * These methods are *NOT* perfectly tested. - .symlink = sdcardfs_symlink, - .link = sdcardfs_link, - .mknod = sdcardfs_mknod, - */ }; const struct inode_operations sdcardfs_main_iops = { diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index 206f8cbc7d7d..a671ae2338ea 100644 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -426,7 +426,12 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, } /* save current_cred and override it */ - OVERRIDE_CRED_PTR(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); + saved_cred = override_fsids(SDCARDFS_SB(dir->i_sb), + SDCARDFS_I(dir)->data); + if (!saved_cred) { + ret = ERR_PTR(-ENOMEM); + goto out_err; + } sdcardfs_get_lower_path(parent, &lower_parent_path); @@ -457,7 +462,7 @@ struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry, out: sdcardfs_put_lower_path(parent, &lower_parent_path); - REVERT_CRED(saved_cred); + revert_fsids(saved_cred); out_err: dput(parent); return ret; diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 055e413509e4..99227a07a8d6 100644 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -88,31 +88,6 @@ (x)->i_mode = ((x)->i_mode & S_IFMT) | 0775;\ } while (0) -/* OVERRIDE_CRED() and REVERT_CRED() - * OVERRIDE_CRED() - * backup original task->cred - * and modifies task->cred->fsuid/fsgid to specified value. - * REVERT_CRED() - * restore original task->cred->fsuid/fsgid. - * These two macro should be used in pair, and OVERRIDE_CRED() should be - * placed at the beginning of a function, right after variable declaration. - */ -#define OVERRIDE_CRED(sdcardfs_sbi, saved_cred, info) \ - do { \ - saved_cred = override_fsids(sdcardfs_sbi, info->data); \ - if (!saved_cred) \ - return -ENOMEM; \ - } while (0) - -#define OVERRIDE_CRED_PTR(sdcardfs_sbi, saved_cred, info) \ - do { \ - saved_cred = override_fsids(sdcardfs_sbi, info->data); \ - if (!saved_cred) \ - return ERR_PTR(-ENOMEM); \ - } while (0) - -#define REVERT_CRED(saved_cred) revert_fsids(saved_cred) - /* Android 5.0 support */ /* Permission mode for a specific node. Controls how file permissions -- cgit v1.2.3 From a781f653bacbaa06195cb846df7735a1559d4427 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 20 Jul 2018 16:11:40 -0700 Subject: ANDROID: sdcardfs: Change current->fs under lock bug: 111641492 Change-Id: I79e9894f94880048edaf0f7cfa2d180f65cbcf3b Reported-by: Jann Horn Signed-off-by: Daniel Rosenberg --- fs/sdcardfs/inode.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index 0b9c345cd01c..6c0039284ae0 100644 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -96,8 +96,11 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, err = -ENOMEM; goto out_unlock; } + copied_fs->umask = 0; + task_lock(current); current->fs = copied_fs; - current->fs->umask = 0; + task_unlock(current); + err = vfs_create2(lower_dentry_mnt, d_inode(lower_parent_dentry), lower_dentry, mode, want_excl); if (err) goto out; @@ -111,7 +114,9 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry, fixup_lower_ownership(dentry, dentry->d_name.name); out: + task_lock(current); current->fs = saved_fs; + task_unlock(current); free_fs_struct(copied_fs); out_unlock: unlock_dir(lower_parent_dentry); @@ -249,8 +254,11 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode unlock_dir(lower_parent_dentry); goto out_unlock; } + copied_fs->umask = 0; + task_lock(current); current->fs = copied_fs; - current->fs->umask = 0; + task_unlock(current); + err = vfs_mkdir2(lower_mnt, d_inode(lower_parent_dentry), lower_dentry, mode); if (err) { @@ -318,7 +326,10 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode } } out: + task_lock(current); current->fs = saved_fs; + task_unlock(current); + free_fs_struct(copied_fs); out_unlock: sdcardfs_put_lower_path(dentry, &lower_path); -- cgit v1.2.3 From 9c1e797a182550b049888d95fa48041d85fc6024 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 27 Nov 2018 10:22:46 -0700 Subject: Makefile: Tidy up 4.4.165 merge Some parts of commit c630d13c9806 ("kbuild: Set KBUILD_CFLAGS before incl. arch Makefile") and its follow up fixes/improvements and commit cfbabf536f6b ("kbuild: clang: disable unused variable warnings only when constant") were not fully applied. Additionally, commit f0907aa15ed9 ("ANDROID: Kbuild, LLVMLinux: allow overriding clang target triple") is reapplied in the new CLANG_TARGET location. Change-Id: Id6332daac607e49213c9a5a594af015830e10d29 Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- Makefile | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index f98a680be7e8..6b0e7d0c984d 100644 --- a/Makefile +++ b/Makefile @@ -611,7 +611,8 @@ all: vmlinux ifeq ($(cc-name),clang) ifneq ($(CROSS_COMPILE),) -CLANG_TARGET := --target=$(notdir $(CROSS_COMPILE:%-=%)) +CLANG_TRIPLE ?= $(CROSS_COMPILE) +CLANG_TARGET := --target=$(notdir $(CLANG_TRIPLE:%-=%)) GCC_TOOLCHAIN_DIR := $(dir $(shell which $(LD))) CLANG_PREFIX := --prefix=$(GCC_TOOLCHAIN_DIR) GCC_TOOLCHAIN := $(realpath $(GCC_TOOLCHAIN_DIR)/..) @@ -719,18 +720,7 @@ ifdef CONFIG_KCOV endif ifeq ($(cc-name),clang) -ifneq ($(CROSS_COMPILE),) -CLANG_TRIPLE ?= $(CROSS_COMPILE) -CLANG_TARGET := --target=$(notdir $(CLANG_TRIPLE:%-=%)) -GCC_TOOLCHAIN := $(realpath $(dir $(shell which $(LD)))/..) -endif -ifneq ($(GCC_TOOLCHAIN),) -CLANG_GCC_TC := --gcc-toolchain=$(GCC_TOOLCHAIN) -endif -KBUILD_CFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC) -KBUILD_AFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC) KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,) -KBUILD_CFLAGS += $(call cc-disable-warning, unused-variable) KBUILD_CFLAGS += $(call cc-disable-warning, format-invalid-specifier) KBUILD_CFLAGS += $(call cc-disable-warning, gnu) KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member) @@ -742,8 +732,6 @@ KBUILD_CFLAGS += $(call cc-disable-warning, tautological-compare) # See modpost pattern 2 KBUILD_CFLAGS += $(call cc-option, -mno-global-merge,) KBUILD_CFLAGS += $(call cc-option, -fcatch-undefined-behavior) -KBUILD_CFLAGS += $(call cc-option, -no-integrated-as) -KBUILD_AFLAGS += $(call cc-option, -no-integrated-as) else # These warnings generated too much noise in a regular build. -- cgit v1.2.3 From 8250e54af25dadfe8de0a86ca0d3a60d9da7b8dc Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Tue, 6 Nov 2018 15:55:32 -0800 Subject: UPSTREAM: binder: fix race that allows malicious free of live buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7bada55ab50697861eee6bb7d60b41e68a961a9c upstream Malicious code can attempt to free buffers using the BC_FREE_BUFFER ioctl to binder. There are protections against a user freeing a buffer while in use by the kernel, however there was a window where BC_FREE_BUFFER could be used to free a recently allocated buffer that was not completely initialized. This resulted in a use-after-free detected by KASAN with a malicious test program. This window is closed by setting the buffer's allow_user_free attribute to 0 when the buffer is allocated or when the user has previously freed it instead of waiting for the caller to set it. The problem was that when the struct buffer was recycled, allow_user_free was stale and set to 1 allowing a free to go through. Bug: 116855682 Change-Id: I0b38089f6fdb1adbf7e1102747e4119c9a05b191 Signed-off-by: Todd Kjos Acked-by: Arve Hjønnevåg Cc: stable # 4.14 Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 21 ++++++++++++--------- drivers/android/binder_alloc.c | 14 ++++++-------- drivers/android/binder_alloc.h | 3 +-- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index e0c46ce312d7..9294574c8251 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3138,7 +3138,6 @@ static void binder_transaction(struct binder_proc *proc, t->buffer = NULL; goto err_binder_alloc_buf_failed; } - t->buffer->allow_user_free = 0; t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; t->buffer->target_node = target_node; @@ -3634,14 +3633,18 @@ static int binder_thread_write(struct binder_proc *proc, buffer = binder_alloc_prepare_to_free(&proc->alloc, data_ptr); - if (buffer == NULL) { - binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", - proc->pid, thread->pid, (u64)data_ptr); - break; - } - if (!buffer->allow_user_free) { - binder_user_error("%d:%d BC_FREE_BUFFER u%016llx matched unreturned buffer\n", - proc->pid, thread->pid, (u64)data_ptr); + if (IS_ERR_OR_NULL(buffer)) { + if (PTR_ERR(buffer) == -EPERM) { + binder_user_error( + "%d:%d BC_FREE_BUFFER u%016llx matched unreturned or currently freeing buffer\n", + proc->pid, thread->pid, + (u64)data_ptr); + } else { + binder_user_error( + "%d:%d BC_FREE_BUFFER u%016llx no match\n", + proc->pid, thread->pid, + (u64)data_ptr); + } break; } binder_debug(BINDER_DEBUG_FREE_BUFFER, diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 1d9db2ef26bd..baecb4bf9d9b 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -149,14 +149,12 @@ static struct binder_buffer *binder_alloc_prepare_to_free_locked( else { /* * Guard against user threads attempting to - * free the buffer twice + * free the buffer when in use by kernel or + * after it's already been freed. */ - if (buffer->free_in_progress) { - pr_err("%d:%d FREE_BUFFER u%016llx user freed buffer twice\n", - alloc->pid, current->pid, (u64)user_ptr); - return NULL; - } - buffer->free_in_progress = 1; + if (!buffer->allow_user_free) + return ERR_PTR(-EPERM); + buffer->allow_user_free = 0; return buffer; } } @@ -463,7 +461,7 @@ static struct binder_buffer *binder_alloc_new_buf_locked( rb_erase(best_fit, &alloc->free_buffers); buffer->free = 0; - buffer->free_in_progress = 0; + buffer->allow_user_free = 0; binder_insert_allocated_buffer_locked(alloc, buffer); binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, "%d: binder_alloc_buf size %zd got %pK\n", diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 9ef64e563856..fb3238c74c8a 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -50,8 +50,7 @@ struct binder_buffer { unsigned free:1; unsigned allow_user_free:1; unsigned async_transaction:1; - unsigned free_in_progress:1; - unsigned debug_id:28; + unsigned debug_id:29; struct binder_transaction *transaction; -- cgit v1.2.3 From e623751cb9e3cdd98661e2412b8448a519b45689 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Wed, 7 Mar 2018 14:11:03 -0800 Subject: ANDROID: uid_sys_stats: Copy task_struct comm field to bigger buffer get_task_comm() currently checks if buf_size != TASK_COMM_LEN and fails even if sizeof(buf) > TASK_COMM_LEN. Change-Id: Icb3e9c172607534ef1db10baf5d626083db73498 Signed-off-by: Dmitry Shmidt --- drivers/misc/uid_sys_stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index cda32366cc7e..99230369f3ed 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -129,7 +129,7 @@ static void get_full_task_comm(struct task_entry *task_entry, struct mm_struct *mm = task->mm; /* fill the first TASK_COMM_LEN bytes with thread name */ - get_task_comm(task_entry->comm, task); + __get_task_comm(task_entry->comm, TASK_COMM_LEN, task); i = strlen(task_entry->comm); while (i < TASK_COMM_LEN) task_entry->comm[i++] = ' '; -- cgit v1.2.3 From 80eb28557a8b3c5cb675f7696fef360080d3dab2 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Fri, 9 Sep 2016 15:32:34 -0700 Subject: ion: Disable ION_HEAP_TYPE_SYSTEM_CONTIG Bug: 30400942 Change-Id: I19fa5bf6e5c66b532b842180b2cf0ae04ddca337 Signed-off-by: Daniel Rosenberg --- drivers/staging/android/ion/ion_heap.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index 13a9b4c42b26..ac331c898f5e 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -321,8 +321,9 @@ struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data) switch (heap_data->type) { case ION_HEAP_TYPE_SYSTEM_CONTIG: - heap = ion_system_contig_heap_create(heap_data); - break; + pr_err("%s: Heap type is disabled: %d\n", __func__, + heap_data->type); + return ERR_PTR(-EINVAL); case ION_HEAP_TYPE_SYSTEM: heap = ion_system_heap_create(heap_data); break; @@ -361,7 +362,8 @@ void ion_heap_destroy(struct ion_heap *heap) switch (heap->type) { case ION_HEAP_TYPE_SYSTEM_CONTIG: - ion_system_contig_heap_destroy(heap); + pr_err("%s: Heap type is disabled: %d\n", __func__, + heap->type); break; case ION_HEAP_TYPE_SYSTEM: ion_system_heap_destroy(heap); -- cgit v1.2.3 From 181243d59e981b2bb3e5b88d9e261f316e4583a1 Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Mon, 14 Jan 2019 09:10:21 -0800 Subject: FROMGIT: binder: create node flag to request sender's security context To allow servers to verify client identity, allow a node flag to be set that causes the sender's security context to be delivered with the transaction. The BR_TRANSACTION command is extended in BR_TRANSACTION_SEC_CTX to contain a pointer to the security context string. Signed-off-by: Todd Kjos Reviewed-by: Joel Fernandes (Google) Signed-off-by: Greg Kroah-Hartman (cherry picked from commit ec74136ded792deed80780a2f8baf3521eeb72f9 https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master) Change-Id: I44496546e2d0dc0022f818a45cd52feb1c1a92cb Signed-off-by: Todd Kjos --- drivers/android/binder.c | 105 ++++++++++++++++++++++++++++-------- include/uapi/linux/android/binder.h | 19 +++++++ 2 files changed, 101 insertions(+), 23 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 9294574c8251..ae222e5ad2e2 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -356,6 +356,7 @@ struct binder_error { * @min_priority: minimum scheduling priority * (invariant after initialized) * @inherit_rt: inherit RT scheduling policy from caller + * @txn_security_ctx: require sender's security context * (invariant after initialized) * @async_todo: list of async work items * (protected by @proc->inner_lock) @@ -395,6 +396,7 @@ struct binder_node { u8 sched_policy:2; u8 inherit_rt:1; u8 accept_fds:1; + u8 txn_security_ctx:1; u8 min_priority; }; bool has_async_transaction; @@ -652,6 +654,7 @@ struct binder_transaction { struct binder_priority saved_priority; bool set_priority_called; kuid_t sender_euid; + binder_uintptr_t security_ctx; /** * @lock: protects @from, @to_proc, and @to_thread * @@ -1361,6 +1364,7 @@ static struct binder_node *binder_init_node_ilocked( node->min_priority = to_kernel_prio(node->sched_policy, priority); node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); node->inherit_rt = !!(flags & FLAT_BINDER_FLAG_INHERIT_RT); + node->txn_security_ctx = !!(flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX); spin_lock_init(&node->lock); INIT_LIST_HEAD(&node->work.entry); INIT_LIST_HEAD(&node->async_todo); @@ -2899,6 +2903,8 @@ static void binder_transaction(struct binder_proc *proc, binder_size_t last_fixup_min_off = 0; struct binder_context *context = proc->context; int t_debug_id = atomic_inc_return(&binder_last_id); + char *secctx = NULL; + u32 secctx_sz = 0; e = binder_transaction_log_add(&binder_transaction_log); e->debug_id = t_debug_id; @@ -3122,6 +3128,20 @@ static void binder_transaction(struct binder_proc *proc, t->priority = target_proc->default_priority; } + if (target_node && target_node->txn_security_ctx) { + u32 secid; + + security_task_getsecid(proc->tsk, &secid); + ret = security_secid_to_secctx(secid, &secctx, &secctx_sz); + if (ret) { + return_error = BR_FAILED_REPLY; + return_error_param = ret; + return_error_line = __LINE__; + goto err_get_secctx_failed; + } + extra_buffers_size += ALIGN(secctx_sz, sizeof(u64)); + } + trace_binder_transaction(reply, t, target_node); t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size, @@ -3138,6 +3158,19 @@ static void binder_transaction(struct binder_proc *proc, t->buffer = NULL; goto err_binder_alloc_buf_failed; } + if (secctx) { + size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) + + ALIGN(tr->offsets_size, sizeof(void *)) + + ALIGN(extra_buffers_size, sizeof(void *)) - + ALIGN(secctx_sz, sizeof(u64)); + char *kptr = t->buffer->data + buf_offset; + + t->security_ctx = (uintptr_t)kptr + + binder_alloc_get_user_buffer_offset(&target_proc->alloc); + memcpy(kptr, secctx, secctx_sz); + security_release_secctx(secctx, secctx_sz); + secctx = NULL; + } t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; t->buffer->target_node = target_node; @@ -3408,6 +3441,9 @@ err_copy_data_failed: t->buffer->transaction = NULL; binder_alloc_free_buf(&target_proc->alloc, t->buffer); err_binder_alloc_buf_failed: + if (secctx) + security_release_secctx(secctx, secctx_sz); +err_get_secctx_failed: kfree(tcomplete); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); err_alloc_tcomplete_failed: @@ -4054,11 +4090,13 @@ retry: while (1) { uint32_t cmd; - struct binder_transaction_data tr; + struct binder_transaction_data_secctx tr; + struct binder_transaction_data *trd = &tr.transaction_data; struct binder_work *w = NULL; struct list_head *list = NULL; struct binder_transaction *t = NULL; struct binder_thread *t_from; + size_t trsize = sizeof(*trd); binder_inner_proc_lock(proc); if (!binder_worklist_empty_ilocked(&thread->todo)) @@ -4254,41 +4292,47 @@ retry: struct binder_node *target_node = t->buffer->target_node; struct binder_priority node_prio; - tr.target.ptr = target_node->ptr; - tr.cookie = target_node->cookie; + trd->target.ptr = target_node->ptr; + trd->cookie = target_node->cookie; node_prio.sched_policy = target_node->sched_policy; node_prio.prio = target_node->min_priority; binder_transaction_priority(current, t, node_prio, target_node->inherit_rt); cmd = BR_TRANSACTION; } else { - tr.target.ptr = 0; - tr.cookie = 0; + trd->target.ptr = 0; + trd->cookie = 0; cmd = BR_REPLY; } - tr.code = t->code; - tr.flags = t->flags; - tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid); + trd->code = t->code; + trd->flags = t->flags; + trd->sender_euid = from_kuid(current_user_ns(), t->sender_euid); t_from = binder_get_txn_from(t); if (t_from) { struct task_struct *sender = t_from->proc->tsk; - tr.sender_pid = task_tgid_nr_ns(sender, - task_active_pid_ns(current)); + trd->sender_pid = + task_tgid_nr_ns(sender, + task_active_pid_ns(current)); } else { - tr.sender_pid = 0; + trd->sender_pid = 0; } - tr.data_size = t->buffer->data_size; - tr.offsets_size = t->buffer->offsets_size; - tr.data.ptr.buffer = (binder_uintptr_t) + trd->data_size = t->buffer->data_size; + trd->offsets_size = t->buffer->offsets_size; + trd->data.ptr.buffer = (binder_uintptr_t) ((uintptr_t)t->buffer->data + binder_alloc_get_user_buffer_offset(&proc->alloc)); - tr.data.ptr.offsets = tr.data.ptr.buffer + + trd->data.ptr.offsets = trd->data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); + tr.secctx = t->security_ctx; + if (t->security_ctx) { + cmd = BR_TRANSACTION_SEC_CTX; + trsize = sizeof(tr); + } if (put_user(cmd, (uint32_t __user *)ptr)) { if (t_from) binder_thread_dec_tmpref(t_from); @@ -4299,7 +4343,7 @@ retry: return -EFAULT; } ptr += sizeof(uint32_t); - if (copy_to_user(ptr, &tr, sizeof(tr))) { + if (copy_to_user(ptr, &tr, trsize)) { if (t_from) binder_thread_dec_tmpref(t_from); @@ -4308,7 +4352,7 @@ retry: return -EFAULT; } - ptr += sizeof(tr); + ptr += trsize; trace_binder_transaction_received(t); binder_stat_br(proc, thread, cmd); @@ -4316,16 +4360,18 @@ retry: "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n", proc->pid, thread->pid, (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : - "BR_REPLY", + (cmd == BR_TRANSACTION_SEC_CTX) ? + "BR_TRANSACTION_SEC_CTX" : "BR_REPLY", t->debug_id, t_from ? t_from->proc->pid : 0, t_from ? t_from->pid : 0, cmd, t->buffer->data_size, t->buffer->offsets_size, - (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); + (u64)trd->data.ptr.buffer, + (u64)trd->data.ptr.offsets); if (t_from) binder_thread_dec_tmpref(t_from); t->buffer->allow_user_free = 1; - if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { + if (cmd != BR_REPLY && !(t->flags & TF_ONE_WAY)) { binder_inner_proc_lock(thread->proc); t->to_parent = thread->transaction_stack; t->to_thread = thread; @@ -4670,7 +4716,8 @@ out: return ret; } -static int binder_ioctl_set_ctx_mgr(struct file *filp) +static int binder_ioctl_set_ctx_mgr(struct file *filp, + struct flat_binder_object *fbo) { int ret = 0; struct binder_proc *proc = filp->private_data; @@ -4699,7 +4746,7 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp) } else { context->binder_context_mgr_uid = curr_euid; } - new_node = binder_new_node(proc, NULL); + new_node = binder_new_node(proc, fbo); if (!new_node) { ret = -ENOMEM; goto out; @@ -4785,8 +4832,20 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) binder_inner_proc_unlock(proc); break; } + case BINDER_SET_CONTEXT_MGR_EXT: { + struct flat_binder_object fbo; + + if (copy_from_user(&fbo, ubuf, sizeof(fbo))) { + ret = -EINVAL; + goto err; + } + ret = binder_ioctl_set_ctx_mgr(filp, &fbo); + if (ret) + goto err; + break; + } case BINDER_SET_CONTEXT_MGR: - ret = binder_ioctl_set_ctx_mgr(filp); + ret = binder_ioctl_set_ctx_mgr(filp, NULL); if (ret) goto err; break; diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 5539933b3491..993bb463ef96 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -87,6 +87,14 @@ enum flat_binder_object_flags { * scheduling policy from the caller (for synchronous transactions). */ FLAT_BINDER_FLAG_INHERIT_RT = 0x800, + + /** + * @FLAT_BINDER_FLAG_TXN_SECURITY_CTX: request security contexts + * + * Only when set, causes senders to include their security + * context + */ + FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000, }; #ifdef BINDER_IPC_32BIT @@ -254,6 +262,7 @@ struct binder_node_debug_info { #define BINDER_THREAD_EXIT _IOW('b', 8, __s32) #define BINDER_VERSION _IOWR('b', 9, struct binder_version) #define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) +#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object) /* * NOTE: Two special error codes you should check for when calling @@ -312,6 +321,11 @@ struct binder_transaction_data { } data; }; +struct binder_transaction_data_secctx { + struct binder_transaction_data transaction_data; + binder_uintptr_t secctx; +}; + struct binder_transaction_data_sg { struct binder_transaction_data transaction_data; binder_size_t buffers_size; @@ -347,6 +361,11 @@ enum binder_driver_return_protocol { BR_OK = _IO('r', 1), /* No parameters! */ + BR_TRANSACTION_SEC_CTX = _IOR('r', 2, + struct binder_transaction_data_secctx), + /* + * binder_transaction_data_secctx: the received command. + */ BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data), BR_REPLY = _IOR('r', 3, struct binder_transaction_data), /* -- cgit v1.2.3 From 4c3b017c545f7c4d1242e16b48ae4bf84e378e97 Mon Sep 17 00:00:00 2001 From: Tom Gall Date: Tue, 26 Mar 2019 10:13:26 -0500 Subject: Fix merge issue with 4.4.177 Change global_attr to kobj_attribute to keep up with change in symbol name (drivers/cpufreq/cpufreq_governor.h) that came in via LTS. Signed-off-by: Tom Gall Link: https://github.com/tom-gall/hikey-linaro/commit/5ea186d035e346383f18ce189214b315d60f1316 Change-Id: I672f2a8016038790d134b45437571a4d68d73f42 Signed-off-by: Alistair Strachan (cherry picked from commit abe4979abd879af2f4d82e8c0bd46ded3a5ea1dd) --- drivers/cpufreq/cpufreq_interactive.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index e0a586895136..55b3c58931a7 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -1041,7 +1041,7 @@ show_store_gov_pol_sys(boostpulse_duration); show_store_gov_pol_sys(io_is_busy); #define gov_sys_attr_rw(_name) \ -static struct global_attr _name##_gov_sys = \ +static struct kobj_attribute _name##_gov_sys = \ __ATTR(_name, 0644, show_##_name##_gov_sys, store_##_name##_gov_sys) #define gov_pol_attr_rw(_name) \ @@ -1063,7 +1063,7 @@ gov_sys_pol_attr_rw(boost); gov_sys_pol_attr_rw(boostpulse_duration); gov_sys_pol_attr_rw(io_is_busy); -static struct global_attr boostpulse_gov_sys = +static struct kobj_attribute boostpulse_gov_sys = __ATTR(boostpulse, 0200, NULL, store_boostpulse_gov_sys); static struct freq_attr boostpulse_gov_pol = -- cgit v1.2.3 From cdfc6e8fbb4f5b4a24c685d6e2ddbf076709fe54 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Sat, 6 Apr 2019 11:53:39 -0700 Subject: Fix merge issue with 4.4.178 Change-Id: I4bd7f3c192046b4e7fc257f03b9cf1fea18e13f7 Signed-off-by: Alistair Strachan (cherry picked from commit 07797f0ce78953f8527f708fbf79857d3f3ed479) --- drivers/usb/gadget/function/rndis.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c index 35766fedd556..4dba794a6ad5 100644 --- a/drivers/usb/gadget/function/rndis.c +++ b/drivers/usb/gadget/function/rndis.c @@ -693,13 +693,6 @@ static int rndis_reset_response(struct rndis_params *params, u8 *xbuf; u32 length; - /* drain the response queue */ - while ((xbuf = rndis_get_next_response(params, &length))) - rndis_free_response(params, xbuf); - - u32 length; - u8 *xbuf; - /* drain the response queue */ while ((xbuf = rndis_get_next_response(params, &length))) rndis_free_response(params, xbuf); -- cgit v1.2.3 From c68e0b5a2cf4b7fa8c0b4be460f5844fbafa2478 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Fri, 5 Apr 2019 16:25:04 +0100 Subject: ANDROID: Communicates LMK events to userland where they can be logged Makes a file /proc/lowmemorykiller available for polling by user space. Immediately as a process is killed by lowmemorykiller information about that process is pushed to the file. It contains information about the process at the time it was killed, to be gathered as metrics. The file is expected to be continuously read from. To prevent failure to do so from causing memory to be continuously consumed, after eight processes have been killed, no more events will be logged until the file is read from again. The format is integers separated by spaces: Field 0 pid The identifier of the process. Field 1 uid The UNIX ID of the user the process was running under. Field 2 group_leader_pid The group leader of the process. Field 3 min_flt The number of minor page faults. Field 4 maj_flt The number of minor page faults. Field 5 rss_in_pages The Resident Set Size in pages. Field 6 oom_score_adj The adjusted Out Of Memory score. Field 7 start_time The number of nanoseconds that the process ran for. --New line-- Field 8 taskname The cmd line used to launch the process, truncated to 127 characters, and terminated by a new line. Bug: 130017100 Test: Tested manually Change-Id: I461b191eda9e578b9d2c2d1843b1b81948353a95 Signed-off-by: Jim Blackler --- drivers/staging/android/lowmemorykiller.c | 157 ++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 2f4ef2120d31..8b19b5e4bd69 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -42,6 +42,9 @@ #include #include #include +#include +#include +#include #define CREATE_TRACE_POINTS #include "trace/lowmemorykiller.h" @@ -70,6 +73,157 @@ static unsigned long lowmem_deathpending_timeout; pr_info(x); \ } while (0) + +static DECLARE_WAIT_QUEUE_HEAD(event_wait); +static DEFINE_SPINLOCK(lmk_event_lock); +static struct circ_buf event_buffer; +#define MAX_BUFFERED_EVENTS 8 +#define MAX_TASKNAME 128 + +struct lmk_event { + char taskname[MAX_TASKNAME]; + pid_t pid; + uid_t uid; + pid_t group_leader_pid; + unsigned long min_flt; + unsigned long maj_flt; + unsigned long rss_in_pages; + short oom_score_adj; + short min_score_adj; + unsigned long long start_time; + struct list_head list; +}; + +void handle_lmk_event(struct task_struct *selected, short min_score_adj) +{ + int head; + int tail; + struct lmk_event *events; + struct lmk_event *event; + int res; + long rss_in_pages = -1; + struct mm_struct *mm = get_task_mm(selected); + + if (mm) { + rss_in_pages = get_mm_rss(mm); + mmput(mm); + } + + spin_lock(&lmk_event_lock); + + head = event_buffer.head; + tail = READ_ONCE(event_buffer.tail); + + /* Do not continue to log if no space remains in the buffer. */ + if (CIRC_SPACE(head, tail, MAX_BUFFERED_EVENTS) < 1) { + spin_unlock(&lmk_event_lock); + return; + } + + events = (struct lmk_event *) event_buffer.buf; + event = &events[head]; + + res = get_cmdline(selected, event->taskname, MAX_TASKNAME - 1); + + /* No valid process name means this is definitely not associated with a + * userspace activity. + */ + + if (res <= 0 || res >= MAX_TASKNAME) { + spin_unlock(&lmk_event_lock); + return; + } + + event->taskname[res] = '\0'; + event->pid = selected->pid; + event->uid = from_kuid_munged(current_user_ns(), task_uid(selected)); + if (selected->group_leader) + event->group_leader_pid = selected->group_leader->pid; + else + event->group_leader_pid = -1; + event->min_flt = selected->min_flt; + event->maj_flt = selected->maj_flt; + event->oom_score_adj = selected->signal->oom_score_adj; + event->start_time = nsec_to_clock_t(selected->real_start_time); + event->rss_in_pages = rss_in_pages; + event->min_score_adj = min_score_adj; + + event_buffer.head = (head + 1) & (MAX_BUFFERED_EVENTS - 1); + + spin_unlock(&lmk_event_lock); + + wake_up_interruptible(&event_wait); +} + +static int lmk_event_show(struct seq_file *s, void *unused) +{ + struct lmk_event *events = (struct lmk_event *) event_buffer.buf; + int head; + int tail; + struct lmk_event *event; + + spin_lock(&lmk_event_lock); + + head = event_buffer.head; + tail = event_buffer.tail; + + if (head == tail) { + spin_unlock(&lmk_event_lock); + return -EAGAIN; + } + + event = &events[tail]; + + seq_printf(s, "%lu %lu %lu %lu %lu %lu %hd %hd %llu\n%s\n", + (unsigned long) event->pid, (unsigned long) event->uid, + (unsigned long) event->group_leader_pid, event->min_flt, + event->maj_flt, event->rss_in_pages, event->oom_score_adj, + event->min_score_adj, event->start_time, event->taskname); + + event_buffer.tail = (tail + 1) & (MAX_BUFFERED_EVENTS - 1); + + spin_unlock(&lmk_event_lock); + return 0; +} + +static unsigned int lmk_event_poll(struct file *file, poll_table *wait) +{ + int ret = 0; + + poll_wait(file, &event_wait, wait); + spin_lock(&lmk_event_lock); + if (event_buffer.head != event_buffer.tail) + ret = POLLIN; + spin_unlock(&lmk_event_lock); + return ret; +} + +static int lmk_event_open(struct inode *inode, struct file *file) +{ + return single_open(file, lmk_event_show, inode->i_private); +} + +static const struct file_operations event_file_ops = { + .open = lmk_event_open, + .poll = lmk_event_poll, + .read = seq_read +}; + +static void lmk_event_init(void) +{ + struct proc_dir_entry *entry; + + event_buffer.head = 0; + event_buffer.tail = 0; + event_buffer.buf = kmalloc( + sizeof(struct lmk_event) * MAX_BUFFERED_EVENTS, GFP_KERNEL); + if (!event_buffer.buf) + return; + entry = proc_create("lowmemorykiller", 0, NULL, &event_file_ops); + if (!entry) + pr_err("error creating kernel lmk event file\n"); +} + static unsigned long lowmem_count(struct shrinker *s, struct shrink_control *sc) { @@ -190,6 +344,8 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) free); lowmem_deathpending_timeout = jiffies + HZ; rem += selected_tasksize; + + handle_lmk_event(selected, min_score_adj); } lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n", @@ -207,6 +363,7 @@ static struct shrinker lowmem_shrinker = { static int __init lowmem_init(void) { register_shrinker(&lowmem_shrinker); + lmk_event_init(); return 0; } device_initcall(lowmem_init); -- cgit v1.2.3 From 298690f64bf926d919993ac8cd5d3d73834fa714 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Wed, 24 Oct 2018 17:24:14 -0700 Subject: ANDROID: arm64 defconfig / build config for cuttlefish Add an arm64 defconfig with the Android and cuttlefish feature sets merged in. This has been boot tested only on the QEMU virt model for AArch64. $ qemu-system-aarch64 -M virt -cpu cortex-a57 \ -kernel arch/arm64/boot/Image.gz -serial stdio Bug: 118442619 Change-Id: I99f3b78af85de8d051226f202351bd852a032248 Signed-off-by: Alistair Strachan --- arch/arm64/configs/cuttlefish_defconfig | 410 ++++++++++++++++++++++++++++++++ build.config.cuttlefish.aarch64 | 16 ++ 2 files changed, 426 insertions(+) create mode 100644 arch/arm64/configs/cuttlefish_defconfig create mode 100644 build.config.cuttlefish.aarch64 diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig new file mode 100644 index 000000000000..d77d20e5a728 --- /dev/null +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -0,0 +1,410 @@ +# CONFIG_USELIB is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_SGETMASK_SYSCALL=y +# CONFIG_SYSFS_SYSCALL is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +CONFIG_EMBEDDED=y +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_JUMP_LABEL=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_HOST_GENERIC=y +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +# CONFIG_SPARSEMEM_VMEMMAP is not set +CONFIG_KSM=y +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_ZSMALLOC=y +CONFIG_SECCOMP=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y +CONFIG_RANDOMIZE_BASE=y +CONFIG_CMDLINE="console=ttyAMA0" +CONFIG_CMDLINE_EXTEND=y +# CONFIG_EFI is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPUFREQ_DT=y +CONFIG_ARM_BIG_LITTLE_CPUFREQ=y +CONFIG_ARM_DT_BL_CPUFREQ=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_NET_IPGRE_DEMUX=y +CONFIG_NET_IPVTI=y +CONFIG_INET_ESP=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_UDP_DIAG=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_HTCP is not set +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_L2TP=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_CFG80211=y +# CONFIG_CFG80211_DEFAULT_PS is not set +CONFIG_MAC80211=y +# CONFIG_MAC80211_RC_MINSTREL is not set +CONFIG_RFKILL=y +# CONFIG_UEVENT_HELPER is not set +CONFIG_DEVTMPFS=y +# CONFIG_ALLOW_DEV_COREDUMP is not set +CONFIG_DEBUG_DEVRES=y +CONFIG_OF_UNITTEST=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_VIRTIO_BLK=y +CONFIG_UID_SYS_STATS=y +CONFIG_SCSI=y +# CONFIG_SCSI_PROC_FS is not set +CONFIG_BLK_DEV_SD=y +CONFIG_SCSI_VIRTIO=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_DM_VERITY_AVB=y +CONFIG_NETDEVICES=y +CONFIG_NETCONSOLE=y +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_TUN=y +CONFIG_VIRTIO_NET=y +# CONFIG_ETHERNET is not set +CONFIG_PHYLIB=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPTP=y +CONFIG_PPPOL2TP=y +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_AX8817X is not set +# CONFIG_USB_NET_AX88179_178A is not set +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_VIRTIO=y +# CONFIG_DEVPORT is not set +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_GPIOLIB=y +# CONFIG_HWMON is not set +CONFIG_CPU_THERMAL=y +CONFIG_MEDIA_SUPPORT=y +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set +# CONFIG_VGA_ARB is not set +CONFIG_DRM=y +# CONFIG_DRM_FBDEV_EMULATION is not set +CONFIG_DRM_VIRTIO_GPU=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_GADGET=y +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_MMC=y +# CONFIG_MMC_BLOCK is not set +CONFIG_RTC_CLASS=y +# CONFIG_RTC_HCTOSYS is not set +# CONFIG_RTC_SYSTOHC is not set +CONFIG_RTC_DRV_PL031=y +CONFIG_VIRTIO_PCI=y +# CONFIG_VIRTIO_PCI_LEGACY is not set +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_SYNC=y +CONFIG_ANDROID_VSOC=y +CONFIG_ION=y +# CONFIG_COMMON_CLK_XGENE is not set +CONFIG_MAILBOX=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_SECURITY=y +CONFIG_F2FS_FS_ENCRYPTION=y +# CONFIG_DNOTIFY is not set +CONFIG_QUOTA=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_SDCARD_FS=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_ENABLE_DEFAULT_TRACERS=y +CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_LSM_MMAP_MIN_ADDR=65536 +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_LZ4=y +CONFIG_CRYPTO_ZSTD=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_XZ_DEC=y diff --git a/build.config.cuttlefish.aarch64 b/build.config.cuttlefish.aarch64 new file mode 100644 index 000000000000..40e9a3bd8d0d --- /dev/null +++ b/build.config.cuttlefish.aarch64 @@ -0,0 +1,16 @@ +ARCH=arm64 +BRANCH=android-4.4 +CLANG_TRIPLE=aarch64-linux-gnu- +CROSS_COMPILE=aarch64-linux-androidkernel- +DEFCONFIG=cuttlefish_defconfig +EXTRA_CMDS='' +KERNEL_DIR=common +POST_DEFCONFIG_CMDS="check_defconfig" +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r328903/bin +LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin +FILES=" +arch/arm64/boot/Image.gz +vmlinux +System.map +" +STOP_SHIP_TRACEPRINTK=1 -- cgit v1.2.3 From 78ffa7d598f025ca0c2cb3420c60c6594a0a1c2d Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Fri, 7 Dec 2018 11:34:16 -0800 Subject: ANDROID: Move from clang r328903 to r346389b. Bug: 120439617 Bug: 120503084 Change-Id: I21bb183cac03753d1ba719a69305e2199c3f3227 Signed-off-by: Alistair Strachan --- build.config.cuttlefish.aarch64 | 2 +- build.config.cuttlefish.x86_64 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.config.cuttlefish.aarch64 b/build.config.cuttlefish.aarch64 index 40e9a3bd8d0d..e36bae42443e 100644 --- a/build.config.cuttlefish.aarch64 +++ b/build.config.cuttlefish.aarch64 @@ -6,7 +6,7 @@ DEFCONFIG=cuttlefish_defconfig EXTRA_CMDS='' KERNEL_DIR=common POST_DEFCONFIG_CMDS="check_defconfig" -CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r328903/bin +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r346389b/bin LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin FILES=" arch/arm64/boot/Image.gz diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64 index ce8c226a1db4..0a77fa871e83 100644 --- a/build.config.cuttlefish.x86_64 +++ b/build.config.cuttlefish.x86_64 @@ -6,7 +6,7 @@ DEFCONFIG=x86_64_cuttlefish_defconfig EXTRA_CMDS='' KERNEL_DIR=common POST_DEFCONFIG_CMDS="check_defconfig" -CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r328903/bin +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r346389b/bin LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin FILES=" arch/x86/boot/bzImage -- cgit v1.2.3 From 388617946ad771f0a4dfe5e56e6be281ddcc28b2 Mon Sep 17 00:00:00 2001 From: Cody Schuffelen Date: Tue, 20 Nov 2018 19:14:49 -0800 Subject: FROMGIT, BACKPORT: mac80211-next: rtnetlink wifi simulation device This device takes over an existing network device and produces a new one that appears like a wireless connection, returning enough canned responses to nl80211 to satisfy a standard connection manager. If necessary, it can also be set up one step removed from an existing network device, such as through a vlan/80211Q or macvlan connection to not disrupt the existing network interface. To use it to wrap a bare ethernet connection: ip link add link eth0 name wlan0 type virt_wifi You may have to rename or otherwise hide the eth0 from your connection manager, as the original network link will become unusuable and only the wireless wrapper will be functional. This can also be combined with vlan or macvlan links on top of eth0 to share the network between distinct links, but that requires support outside the machine for accepting vlan-tagged packets or packets from multiple MAC addresses. This is being used for Google's Remote Android Virtual Device project, which runs Android devices in virtual machines. The standard network interfaces provided inside the virtual machines are all ethernet. However, Android is not interested in ethernet devices and would rather connect to a wireless interface. This patch allows the virtual machine guest to treat one of its network connections as wireless rather than ethernet, satisfying Android's network connection requirements. We believe this is a generally useful driver for simulating wireless network connections in other environments where a wireless connection is desired by some userspace process but is not available. This is distinct from other testing efforts such as mac80211_hwsim by being a cfg80211 device instead of mac80211 device, allowing straight pass-through on the data plane instead of forcing packaging of ethernet data into mac80211 frames. Signed-off-by: A. Cody Schuffelen Acked-by: Alistair Strachan Acked-by: Greg Hartman Acked-by: Tristan Muntsinger [make it a tristate] Signed-off-by: Johannes Berg (cherry picked from commit c7cdba31ed8b87526db978976392802d3f93110c) [astrachan: taken from mac80211-next/master] [astrachan: removed 'extack' from call to netdev_upper_dev_link()] [astrachan: removed 'extack' from virt_wifi_newlink() and initialized 'destructor' instead of 'priv_destructor'] [astrachan: renamed NL80211_BAND_xxGHZ -> IEEE80211_BAND_xxGHZ] Bug: 120682817 Test: boot tested cuttlefish and enabled wifi, saw AndroidWifi Change-Id: I726ec28617574c0217d937da049089f0ab8e0da8 Signed-off-by: Alistair Strachan --- drivers/net/wireless/Kconfig | 7 + drivers/net/wireless/Makefile | 2 + drivers/net/wireless/virt_wifi.c | 629 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 638 insertions(+) create mode 100644 drivers/net/wireless/virt_wifi.c diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index f9f94229bf1b..0ab1a0f04075 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -256,6 +256,13 @@ config MAC80211_HWSIM To compile this driver as a module, choose M here: the module will be called mac80211_hwsim. If unsure, say N. +config VIRT_WIFI + tristate "Wifi wrapper for ethernet drivers" + depends on CFG80211 + ---help--- + This option adds support for ethernet connections to appear as if they + are wifi connections through a special rtnetlink device. + config MWL8K tristate "Marvell 88W8xxx PCI/PCIe Wireless support" depends on MAC80211 && PCI diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 740fdd353c5d..76b7b9198657 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -51,6 +51,8 @@ obj-$(CONFIG_ATH_CARDS) += ath/ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o +obj-$(CONFIG_VIRT_WIFI) += virt_wifi.o + obj-$(CONFIG_WL_TI) += ti/ obj-$(CONFIG_MWIFIEX) += mwifiex/ diff --git a/drivers/net/wireless/virt_wifi.c b/drivers/net/wireless/virt_wifi.c new file mode 100644 index 000000000000..90ecb7e8834f --- /dev/null +++ b/drivers/net/wireless/virt_wifi.c @@ -0,0 +1,629 @@ +// SPDX-License-Identifier: GPL-2.0 +/* drivers/net/wireless/virt_wifi.c + * + * A fake implementation of cfg80211_ops that can be tacked on to an ethernet + * net_device to make it appear as a wireless connection. + * + * Copyright (C) 2018 Google, Inc. + * + * Author: schuffelen@google.com + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +static struct wiphy *common_wiphy; + +struct virt_wifi_wiphy_priv { + struct delayed_work scan_result; + struct cfg80211_scan_request *scan_request; + bool being_deleted; +}; + +static struct ieee80211_channel channel_2ghz = { + .band = IEEE80211_BAND_2GHZ, + .center_freq = 2432, + .hw_value = 2432, + .max_power = 20, +}; + +static struct ieee80211_rate bitrates_2ghz[] = { + { .bitrate = 10 }, + { .bitrate = 20 }, + { .bitrate = 55 }, + { .bitrate = 110 }, + { .bitrate = 60 }, + { .bitrate = 120 }, + { .bitrate = 240 }, +}; + +static struct ieee80211_supported_band band_2ghz = { + .channels = &channel_2ghz, + .bitrates = bitrates_2ghz, + .band = IEEE80211_BAND_2GHZ, + .n_channels = 1, + .n_bitrates = ARRAY_SIZE(bitrates_2ghz), + .ht_cap = { + .ht_supported = true, + .cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40, + .ampdu_factor = 0x3, + .ampdu_density = 0x6, + .mcs = { + .rx_mask = {0xff, 0xff}, + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, + }, + }, +}; + +static struct ieee80211_channel channel_5ghz = { + .band = IEEE80211_BAND_5GHZ, + .center_freq = 5240, + .hw_value = 5240, + .max_power = 20, +}; + +static struct ieee80211_rate bitrates_5ghz[] = { + { .bitrate = 60 }, + { .bitrate = 120 }, + { .bitrate = 240 }, +}; + +#define RX_MCS_MAP (IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 14) + +#define TX_MCS_MAP (IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 2 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 6 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 8 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 | \ + IEEE80211_VHT_MCS_SUPPORT_0_9 << 14) + +static struct ieee80211_supported_band band_5ghz = { + .channels = &channel_5ghz, + .bitrates = bitrates_5ghz, + .band = IEEE80211_BAND_5GHZ, + .n_channels = 1, + .n_bitrates = ARRAY_SIZE(bitrates_5ghz), + .ht_cap = { + .ht_supported = true, + .cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40, + .ampdu_factor = 0x3, + .ampdu_density = 0x6, + .mcs = { + .rx_mask = {0xff, 0xff}, + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, + }, + }, + .vht_cap = { + .vht_supported = true, + .cap = IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ | + IEEE80211_VHT_CAP_RXLDPC | + IEEE80211_VHT_CAP_SHORT_GI_80 | + IEEE80211_VHT_CAP_SHORT_GI_160 | + IEEE80211_VHT_CAP_TXSTBC | + IEEE80211_VHT_CAP_RXSTBC_1 | + IEEE80211_VHT_CAP_RXSTBC_2 | + IEEE80211_VHT_CAP_RXSTBC_3 | + IEEE80211_VHT_CAP_RXSTBC_4 | + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK, + .vht_mcs = { + .rx_mcs_map = cpu_to_le16(RX_MCS_MAP), + .tx_mcs_map = cpu_to_le16(TX_MCS_MAP), + } + }, +}; + +/* Assigned at module init. Guaranteed locally-administered and unicast. */ +static u8 fake_router_bssid[ETH_ALEN] __ro_after_init = {}; + +/* Called with the rtnl lock held. */ +static int virt_wifi_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request) +{ + struct virt_wifi_wiphy_priv *priv = wiphy_priv(wiphy); + + wiphy_debug(wiphy, "scan\n"); + + if (priv->scan_request || priv->being_deleted) + return -EBUSY; + + priv->scan_request = request; + schedule_delayed_work(&priv->scan_result, HZ * 2); + + return 0; +} + +/* Acquires and releases the rdev BSS lock. */ +static void virt_wifi_scan_result(struct work_struct *work) +{ + struct { + u8 tag; + u8 len; + u8 ssid[8]; + } __packed ssid = { + .tag = WLAN_EID_SSID, .len = 8, .ssid = "VirtWifi", + }; + struct cfg80211_bss *informed_bss; + struct virt_wifi_wiphy_priv *priv = + container_of(work, struct virt_wifi_wiphy_priv, + scan_result.work); + struct wiphy *wiphy = priv_to_wiphy(priv); + + informed_bss = cfg80211_inform_bss(wiphy, &channel_5ghz, + CFG80211_BSS_FTYPE_PRESP, + fake_router_bssid, + ktime_get_boot_ns(), + WLAN_CAPABILITY_ESS, 0, + (void *)&ssid, sizeof(ssid), + DBM_TO_MBM(-50), GFP_KERNEL); + cfg80211_put_bss(wiphy, informed_bss); + + /* Schedules work which acquires and releases the rtnl lock. */ + cfg80211_scan_done(priv->scan_request, false); + priv->scan_request = NULL; +} + +/* May acquire and release the rdev BSS lock. */ +static void virt_wifi_cancel_scan(struct wiphy *wiphy) +{ + struct virt_wifi_wiphy_priv *priv = wiphy_priv(wiphy); + + cancel_delayed_work_sync(&priv->scan_result); + /* Clean up dangling callbacks if necessary. */ + if (priv->scan_request) { + /* Schedules work which acquires and releases the rtnl lock. */ + cfg80211_scan_done(priv->scan_request, true); + priv->scan_request = NULL; + } +} + +struct virt_wifi_netdev_priv { + struct delayed_work connect; + struct net_device *lowerdev; + struct net_device *upperdev; + u32 tx_packets; + u32 tx_failed; + u8 connect_requested_bss[ETH_ALEN]; + bool is_up; + bool is_connected; + bool being_deleted; +}; + +/* Called with the rtnl lock held. */ +static int virt_wifi_connect(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_connect_params *sme) +{ + struct virt_wifi_netdev_priv *priv = netdev_priv(netdev); + bool could_schedule; + + if (priv->being_deleted || !priv->is_up) + return -EBUSY; + + could_schedule = schedule_delayed_work(&priv->connect, HZ * 2); + if (!could_schedule) + return -EBUSY; + + if (sme->bssid) + ether_addr_copy(priv->connect_requested_bss, sme->bssid); + else + eth_zero_addr(priv->connect_requested_bss); + + wiphy_debug(wiphy, "connect\n"); + + return 0; +} + +/* Acquires and releases the rdev event lock. */ +static void virt_wifi_connect_complete(struct work_struct *work) +{ + struct virt_wifi_netdev_priv *priv = + container_of(work, struct virt_wifi_netdev_priv, connect.work); + u8 *requested_bss = priv->connect_requested_bss; + bool has_addr = !is_zero_ether_addr(requested_bss); + bool right_addr = ether_addr_equal(requested_bss, fake_router_bssid); + u16 status = WLAN_STATUS_SUCCESS; + + if (!priv->is_up || (has_addr && !right_addr)) + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + else + priv->is_connected = true; + + /* Schedules an event that acquires the rtnl lock. */ + cfg80211_connect_result(priv->upperdev, requested_bss, NULL, 0, NULL, 0, + status, GFP_KERNEL); + netif_carrier_on(priv->upperdev); +} + +/* May acquire and release the rdev event lock. */ +static void virt_wifi_cancel_connect(struct net_device *netdev) +{ + struct virt_wifi_netdev_priv *priv = netdev_priv(netdev); + + /* If there is work pending, clean up dangling callbacks. */ + if (cancel_delayed_work_sync(&priv->connect)) { + /* Schedules an event that acquires the rtnl lock. */ + cfg80211_connect_result(priv->upperdev, + priv->connect_requested_bss, NULL, 0, + NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + } +} + +/* Called with the rtnl lock held. Acquires the rdev event lock. */ +static int virt_wifi_disconnect(struct wiphy *wiphy, struct net_device *netdev, + u16 reason_code) +{ + struct virt_wifi_netdev_priv *priv = netdev_priv(netdev); + + if (priv->being_deleted) + return -EBUSY; + + wiphy_debug(wiphy, "disconnect\n"); + virt_wifi_cancel_connect(netdev); + + cfg80211_disconnected(netdev, reason_code, NULL, 0, true, GFP_KERNEL); + priv->is_connected = false; + netif_carrier_off(netdev); + + return 0; +} + +/* Called with the rtnl lock held. */ +static int virt_wifi_get_station(struct wiphy *wiphy, struct net_device *dev, + const u8 *mac, struct station_info *sinfo) +{ + struct virt_wifi_netdev_priv *priv = netdev_priv(dev); + + wiphy_debug(wiphy, "get_station\n"); + + if (!priv->is_connected || !ether_addr_equal(mac, fake_router_bssid)) + return -ENOENT; + + sinfo->filled = BIT_ULL(NL80211_STA_INFO_TX_PACKETS) | + BIT_ULL(NL80211_STA_INFO_TX_FAILED) | + BIT_ULL(NL80211_STA_INFO_SIGNAL) | + BIT_ULL(NL80211_STA_INFO_TX_BITRATE); + sinfo->tx_packets = priv->tx_packets; + sinfo->tx_failed = priv->tx_failed; + /* For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_ */ + sinfo->signal = -50; + sinfo->txrate = (struct rate_info) { + .legacy = 10, /* units are 100kbit/s */ + }; + return 0; +} + +/* Called with the rtnl lock held. */ +static int virt_wifi_dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo) +{ + struct virt_wifi_netdev_priv *priv = netdev_priv(dev); + + wiphy_debug(wiphy, "dump_station\n"); + + if (idx != 0 || !priv->is_connected) + return -ENOENT; + + ether_addr_copy(mac, fake_router_bssid); + return virt_wifi_get_station(wiphy, dev, fake_router_bssid, sinfo); +} + +static const struct cfg80211_ops virt_wifi_cfg80211_ops = { + .scan = virt_wifi_scan, + + .connect = virt_wifi_connect, + .disconnect = virt_wifi_disconnect, + + .get_station = virt_wifi_get_station, + .dump_station = virt_wifi_dump_station, +}; + +/* Acquires and releases the rtnl lock. */ +static struct wiphy *virt_wifi_make_wiphy(void) +{ + struct wiphy *wiphy; + struct virt_wifi_wiphy_priv *priv; + int err; + + wiphy = wiphy_new(&virt_wifi_cfg80211_ops, sizeof(*priv)); + + if (!wiphy) + return NULL; + + wiphy->max_scan_ssids = 4; + wiphy->max_scan_ie_len = 1000; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2ghz; + wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5ghz; + wiphy->bands[IEEE80211_BAND_60GHZ] = NULL; + + wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + + priv = wiphy_priv(wiphy); + priv->being_deleted = false; + priv->scan_request = NULL; + INIT_DELAYED_WORK(&priv->scan_result, virt_wifi_scan_result); + + err = wiphy_register(wiphy); + if (err < 0) { + wiphy_free(wiphy); + return NULL; + } + + return wiphy; +} + +/* Acquires and releases the rtnl lock. */ +static void virt_wifi_destroy_wiphy(struct wiphy *wiphy) +{ + struct virt_wifi_wiphy_priv *priv; + + WARN(!wiphy, "%s called with null wiphy", __func__); + if (!wiphy) + return; + + priv = wiphy_priv(wiphy); + priv->being_deleted = true; + virt_wifi_cancel_scan(wiphy); + + if (wiphy->registered) + wiphy_unregister(wiphy); + wiphy_free(wiphy); +} + +/* Enters and exits a RCU-bh critical section. */ +static netdev_tx_t virt_wifi_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct virt_wifi_netdev_priv *priv = netdev_priv(dev); + + priv->tx_packets++; + if (!priv->is_connected) { + priv->tx_failed++; + return NET_XMIT_DROP; + } + + skb->dev = priv->lowerdev; + return dev_queue_xmit(skb); +} + +/* Called with rtnl lock held. */ +static int virt_wifi_net_device_open(struct net_device *dev) +{ + struct virt_wifi_netdev_priv *priv = netdev_priv(dev); + + priv->is_up = true; + return 0; +} + +/* Called with rtnl lock held. */ +static int virt_wifi_net_device_stop(struct net_device *dev) +{ + struct virt_wifi_netdev_priv *n_priv = netdev_priv(dev); + struct virt_wifi_wiphy_priv *w_priv; + + n_priv->is_up = false; + + if (!dev->ieee80211_ptr) + return 0; + w_priv = wiphy_priv(dev->ieee80211_ptr->wiphy); + + virt_wifi_cancel_scan(dev->ieee80211_ptr->wiphy); + virt_wifi_cancel_connect(dev); + netif_carrier_off(dev); + + return 0; +} + +static const struct net_device_ops virt_wifi_ops = { + .ndo_start_xmit = virt_wifi_start_xmit, + .ndo_open = virt_wifi_net_device_open, + .ndo_stop = virt_wifi_net_device_stop, +}; + +/* Invoked as part of rtnl lock release. */ +static void virt_wifi_net_device_destructor(struct net_device *dev) +{ + /* Delayed past dellink to allow nl80211 to react to the device being + * deleted. + */ + kfree(dev->ieee80211_ptr); + dev->ieee80211_ptr = NULL; + free_netdev(dev); +} + +/* No lock interaction. */ +static void virt_wifi_setup(struct net_device *dev) +{ + ether_setup(dev); + dev->netdev_ops = &virt_wifi_ops; + dev->destructor = virt_wifi_net_device_destructor; +} + +/* Called in a RCU read critical section from netif_receive_skb */ +static rx_handler_result_t virt_wifi_rx_handler(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + struct virt_wifi_netdev_priv *priv = + rcu_dereference(skb->dev->rx_handler_data); + + if (!priv->is_connected) + return RX_HANDLER_PASS; + + /* GFP_ATOMIC because this is a packet interrupt handler. */ + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) { + dev_err(&priv->upperdev->dev, "can't skb_share_check\n"); + return RX_HANDLER_CONSUMED; + } + + *pskb = skb; + skb->dev = priv->upperdev; + skb->pkt_type = PACKET_HOST; + return RX_HANDLER_ANOTHER; +} + +/* Called with rtnl lock held. */ +static int virt_wifi_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + struct virt_wifi_netdev_priv *priv = netdev_priv(dev); + int err; + + if (!tb[IFLA_LINK]) + return -EINVAL; + + netif_carrier_off(dev); + + priv->upperdev = dev; + priv->lowerdev = __dev_get_by_index(src_net, + nla_get_u32(tb[IFLA_LINK])); + + if (!priv->lowerdev) + return -ENODEV; + if (!tb[IFLA_MTU]) + dev->mtu = priv->lowerdev->mtu; + else if (dev->mtu > priv->lowerdev->mtu) + return -EINVAL; + + err = netdev_rx_handler_register(priv->lowerdev, virt_wifi_rx_handler, + priv); + if (err) { + dev_err(&priv->lowerdev->dev, + "can't netdev_rx_handler_register: %d\n", err); + return err; + } + + eth_hw_addr_inherit(dev, priv->lowerdev); + netif_stacked_transfer_operstate(priv->lowerdev, dev); + + SET_NETDEV_DEV(dev, &priv->lowerdev->dev); + dev->ieee80211_ptr = kzalloc(sizeof(*dev->ieee80211_ptr), GFP_KERNEL); + + if (!dev->ieee80211_ptr) + goto remove_handler; + + dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; + dev->ieee80211_ptr->wiphy = common_wiphy; + + err = register_netdevice(dev); + if (err) { + dev_err(&priv->lowerdev->dev, "can't register_netdevice: %d\n", + err); + goto free_wireless_dev; + } + + err = netdev_upper_dev_link(priv->lowerdev, dev); + if (err) { + dev_err(&priv->lowerdev->dev, "can't netdev_upper_dev_link: %d\n", + err); + goto unregister_netdev; + } + + priv->being_deleted = false; + priv->is_connected = false; + priv->is_up = false; + INIT_DELAYED_WORK(&priv->connect, virt_wifi_connect_complete); + + return 0; +unregister_netdev: + unregister_netdevice(dev); +free_wireless_dev: + kfree(dev->ieee80211_ptr); + dev->ieee80211_ptr = NULL; +remove_handler: + netdev_rx_handler_unregister(priv->lowerdev); + + return err; +} + +/* Called with rtnl lock held. */ +static void virt_wifi_dellink(struct net_device *dev, + struct list_head *head) +{ + struct virt_wifi_netdev_priv *priv = netdev_priv(dev); + + if (dev->ieee80211_ptr) + virt_wifi_cancel_scan(dev->ieee80211_ptr->wiphy); + + priv->being_deleted = true; + virt_wifi_cancel_connect(dev); + netif_carrier_off(dev); + + netdev_rx_handler_unregister(priv->lowerdev); + netdev_upper_dev_unlink(priv->lowerdev, dev); + + unregister_netdevice_queue(dev, head); + + /* Deleting the wiphy is handled in the module destructor. */ +} + +static struct rtnl_link_ops virt_wifi_link_ops = { + .kind = "virt_wifi", + .setup = virt_wifi_setup, + .newlink = virt_wifi_newlink, + .dellink = virt_wifi_dellink, + .priv_size = sizeof(struct virt_wifi_netdev_priv), +}; + +/* Acquires and releases the rtnl lock. */ +static int __init virt_wifi_init_module(void) +{ + int err; + + /* Guaranteed to be locallly-administered and not multicast. */ + eth_random_addr(fake_router_bssid); + + common_wiphy = virt_wifi_make_wiphy(); + if (!common_wiphy) + return -ENOMEM; + + err = rtnl_link_register(&virt_wifi_link_ops); + if (err) + virt_wifi_destroy_wiphy(common_wiphy); + + return err; +} + +/* Acquires and releases the rtnl lock. */ +static void __exit virt_wifi_cleanup_module(void) +{ + /* Will delete any devices that depend on the wiphy. */ + rtnl_link_unregister(&virt_wifi_link_ops); + virt_wifi_destroy_wiphy(common_wiphy); +} + +module_init(virt_wifi_init_module); +module_exit(virt_wifi_cleanup_module); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Cody Schuffelen "); +MODULE_DESCRIPTION("Driver for a wireless wrapper of ethernet devices"); +MODULE_ALIAS_RTNL_LINK("virt_wifi"); -- cgit v1.2.3 From 291ade53b68efc4b0925410be492f0edd887b8aa Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Fri, 7 Dec 2018 16:40:23 -0800 Subject: ANDROID: cuttlefish_defconfig: Enable VIRT_WIFI Bug: 120439617 Bug: 120682817 Change-Id: Ia1b66528bd9cb1e6e95bd75ac60f393978caa582 Signed-off-by: Alistair Strachan --- arch/arm64/configs/cuttlefish_defconfig | 1 + arch/x86/configs/x86_64_cuttlefish_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index d77d20e5a728..c620078b587c 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -227,6 +227,7 @@ CONFIG_USB_USBNET=y # CONFIG_USB_NET_NET1080 is not set # CONFIG_USB_NET_CDC_SUBSET is not set # CONFIG_USB_NET_ZAURUS is not set +CONFIG_VIRT_WIFI=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_KEYRESET=y # CONFIG_INPUT_KEYBOARD is not set diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index df9b6bd228f7..2bb9b7f6642c 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -246,6 +246,7 @@ CONFIG_USB_USBNET=y # CONFIG_USB_NET_CDC_SUBSET is not set # CONFIG_USB_NET_ZAURUS is not set CONFIG_MAC80211_HWSIM=y +CONFIG_VIRT_WIFI=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_KEYRESET=y # CONFIG_INPUT_KEYBOARD is not set -- cgit v1.2.3 From 2c332d29d2f335db8100bd03bb039b062d57eb7d Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Wed, 2 Jan 2019 15:24:37 -0800 Subject: ANDROID: cuttlefish_defconfig: Enable VIRTIO_INPUT Bug: 120439617 Change-Id: I83fdb2088f17e71f377e5864d217655b47839267 Signed-off-by: Alistair Strachan --- arch/arm64/configs/cuttlefish_defconfig | 1 + arch/x86/configs/x86_64_cuttlefish_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index c620078b587c..2dacb5ca76df 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -353,6 +353,7 @@ CONFIG_RTC_DRV_PL031=y CONFIG_VIRTIO_PCI=y # CONFIG_VIRTIO_PCI_LEGACY is not set CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_INPUT=y CONFIG_VIRTIO_MMIO=y CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y CONFIG_STAGING=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 2bb9b7f6642c..9efb463d0d52 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -379,6 +379,7 @@ CONFIG_RTC_CLASS=y # CONFIG_RTC_HCTOSYS is not set CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_INPUT=y CONFIG_VIRTIO_MMIO=y CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y CONFIG_STAGING=y -- cgit v1.2.3 From 0c64823b69525f7e2dcecc4352598e0a1a61992d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Nov 2015 06:31:01 -0800 Subject: UPSTREAM: net: move napi_hash[] into read mostly section We do not often add/delete a napi context. Moving napi_hash[] into read mostly section avoids potential false sharing. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller (cherry picked from commit 6180d9de61a5c461f9e3efef5417a844701dbbb2) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I891b9dfef88c44f6480842754cd7d81e7a250792 --- include/linux/hashtable.h | 4 ++++ net/core/dev.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/linux/hashtable.h b/include/linux/hashtable.h index 519b6e2d769e..661e5c2a8e2a 100644 --- a/include/linux/hashtable.h +++ b/include/linux/hashtable.h @@ -16,6 +16,10 @@ struct hlist_head name[1 << (bits)] = \ { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } +#define DEFINE_READ_MOSTLY_HASHTABLE(name, bits) \ + struct hlist_head name[1 << (bits)] __read_mostly = \ + { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } + #define DECLARE_HASHTABLE(name, bits) \ struct hlist_head name[1 << (bits)] diff --git a/net/core/dev.c b/net/core/dev.c index 49f78bce5795..5e78923dfd63 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -183,7 +183,7 @@ EXPORT_SYMBOL(dev_base_lock); static DEFINE_SPINLOCK(napi_hash_lock); static unsigned int napi_gen_id = NR_CPUS; -static DEFINE_HASHTABLE(napi_hash, 8); +static DEFINE_READ_MOSTLY_HASHTABLE(napi_hash, 8); static seqcount_t devnet_rename_seq; -- cgit v1.2.3 From 9952f731f9849d64535a4d6b8306cf683990f77e Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 17 Dec 2015 16:53:43 +0800 Subject: UPSTREAM: virtio: make find_vqs() checkpatch.pl-friendly checkpatch.pl wants arrays of strings declared as follows: static const char * const names[] = { "vq-1", "vq-2", "vq-3" }; Currently the find_vqs() function takes a const char *names[] argument so passing checkpatch.pl's const char * const names[] results in a compiler error due to losing the second const. This patch adjusts the find_vqs() prototype and updates all virtio transports. This makes it possible for virtio_balloon.c, virtio_input.c, virtgpu_kms.c, and virtio_rpmsg_bus.c to use the checkpatch.pl-friendly type. Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin Acked-by: Bjorn Andersson (cherry picked from commit f7ad26ff952b3ca2702d7da03aad0ab1f6c01d7c) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Cody Schuffelen Change-Id: I23513ea85e7a43efd0c604fc4445b301b4f610ba --- drivers/gpu/drm/virtio/virtgpu_kms.c | 2 +- drivers/misc/mic/card/mic_virtio.c | 2 +- drivers/remoteproc/remoteproc_virtio.c | 2 +- drivers/rpmsg/virtio_rpmsg_bus.c | 2 +- drivers/s390/virtio/kvm_virtio.c | 2 +- drivers/s390/virtio/virtio_ccw.c | 2 +- drivers/virtio/virtio_balloon.c | 2 +- drivers/virtio/virtio_input.c | 2 +- drivers/virtio/virtio_mmio.c | 2 +- drivers/virtio/virtio_pci_common.c | 4 ++-- drivers/virtio/virtio_pci_common.h | 2 +- drivers/virtio/virtio_pci_modern.c | 2 +- include/linux/virtio_config.h | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c index 06496a128162..4150873d432e 100644 --- a/drivers/gpu/drm/virtio/virtgpu_kms.c +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c @@ -130,7 +130,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) static vq_callback_t *callbacks[] = { virtio_gpu_ctrl_ack, virtio_gpu_cursor_ack }; - static const char *names[] = { "control", "cursor" }; + static const char * const names[] = { "control", "cursor" }; struct virtio_gpu_device *vgdev; /* this will expand later */ diff --git a/drivers/misc/mic/card/mic_virtio.c b/drivers/misc/mic/card/mic_virtio.c index e486a0c26267..f6ed57d3125c 100644 --- a/drivers/misc/mic/card/mic_virtio.c +++ b/drivers/misc/mic/card/mic_virtio.c @@ -311,7 +311,7 @@ unmap: static int mic_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char *names[]) + const char * const names[]) { struct mic_vdev *mvdev = to_micvdev(vdev); struct mic_device_ctrl __iomem *dc = mvdev->dc; diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index e1a10232a943..e44872fb9e5e 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -147,7 +147,7 @@ static void rproc_virtio_del_vqs(struct virtio_device *vdev) static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char *names[]) + const char * const names[]) { struct rproc *rproc = vdev_to_rproc(vdev); int i, ret; diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 73354ee27877..1fcd27c1f183 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -945,7 +945,7 @@ static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len, static int rpmsg_probe(struct virtio_device *vdev) { vq_callback_t *vq_cbs[] = { rpmsg_recv_done, rpmsg_xmit_done }; - const char *names[] = { "input", "output" }; + static const char * const names[] = { "input", "output" }; struct virtqueue *vqs[2]; struct virtproc_info *vrp; void *bufs_va; diff --git a/drivers/s390/virtio/kvm_virtio.c b/drivers/s390/virtio/kvm_virtio.c index 53fb975c404b..1d060fd293a3 100644 --- a/drivers/s390/virtio/kvm_virtio.c +++ b/drivers/s390/virtio/kvm_virtio.c @@ -255,7 +255,7 @@ static void kvm_del_vqs(struct virtio_device *vdev) static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char *names[]) + const char * const names[]) { struct kvm_device *kdev = to_kvmdev(vdev); int i; diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index 2bb275fb39d1..5abd37ce4f6f 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -641,7 +641,7 @@ out: static int virtio_ccw_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char *names[]) + const char * const names[]) { struct virtio_ccw_device *vcdev = to_vc_device(vdev); unsigned long *indicatorp = NULL; diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index cbe9e2295752..e3ac3e157485 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -396,7 +396,7 @@ static int init_vqs(struct virtio_balloon *vb) { struct virtqueue *vqs[3]; vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request }; - const char *names[] = { "inflate", "deflate", "stats" }; + static const char * const names[] = { "inflate", "deflate", "stats" }; int err, nvqs; /* diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c index c96944b59856..350a2a5a49db 100644 --- a/drivers/virtio/virtio_input.c +++ b/drivers/virtio/virtio_input.c @@ -170,7 +170,7 @@ static int virtinput_init_vqs(struct virtio_input *vi) struct virtqueue *vqs[2]; vq_callback_t *cbs[] = { virtinput_recv_events, virtinput_recv_status }; - static const char *names[] = { "events", "status" }; + static const char * const names[] = { "events", "status" }; int err; err = vi->vdev->config->find_vqs(vi->vdev, 2, vqs, cbs, names); diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index f499d9da7237..745c6ee1bb3e 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -482,7 +482,7 @@ error_available: static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char *names[]) + const char * const names[]) { struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); unsigned int irq = platform_get_irq(vm_dev->pdev, 0); diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index 2046a68ad0ba..f6bed86c17f9 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -296,7 +296,7 @@ void vp_del_vqs(struct virtio_device *vdev) static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char *names[], + const char * const names[], bool use_msix, bool per_vq_vectors) { @@ -376,7 +376,7 @@ error_find: int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char *names[]) + const char * const names[]) { int err; diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci_common.h index b976d968e793..2cc252270b2d 100644 --- a/drivers/virtio/virtio_pci_common.h +++ b/drivers/virtio/virtio_pci_common.h @@ -139,7 +139,7 @@ void vp_del_vqs(struct virtio_device *vdev); int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char *names[]); + const char * const names[]); const char *vp_bus_name(struct virtio_device *vdev); /* Setup the affinity for a virtqueue: diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c index 4469202eaa8e..631021cfc740 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -423,7 +423,7 @@ err_new_queue: static int vp_modern_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char *names[]) + const char * const names[]) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtqueue *vq; diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index e5ce8ab0b8b0..6e6cb0c9d7cb 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -70,7 +70,7 @@ struct virtio_config_ops { int (*find_vqs)(struct virtio_device *, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], - const char *names[]); + const char * const names[]); void (*del_vqs)(struct virtio_device *); u64 (*get_features)(struct virtio_device *vdev); int (*finalize_features)(struct virtio_device *vdev); -- cgit v1.2.3 From b8e64a0e093f05fd5bb44764ab5adeca2a4f8c3f Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 16 Feb 2016 15:54:28 +0100 Subject: UPSTREAM: vhost: fix error path in vhost_init_used() We don't want side effects. If something fails, we rollback vq->is_le to its previous value. Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin (cherry picked from commit e1f33be9186363da7955bcb5f0b03e6685544c50) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I18c57e5c78aa3e89d267213770f915a5a5c76100 --- drivers/vhost/vhost.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 2ed0a356d1d3..e00271076996 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1157,6 +1157,8 @@ int vhost_init_used(struct vhost_virtqueue *vq) { __virtio16 last_used_idx; int r; + bool is_le = vq->is_le; + if (!vq->private_data) { vq->is_le = virtio_legacy_is_little_endian(); return 0; @@ -1166,15 +1168,20 @@ int vhost_init_used(struct vhost_virtqueue *vq) r = vhost_update_used_flags(vq); if (r) - return r; + goto err; vq->signalled_used_valid = false; - if (!access_ok(VERIFY_READ, &vq->used->idx, sizeof vq->used->idx)) - return -EFAULT; + if (!access_ok(VERIFY_READ, &vq->used->idx, sizeof vq->used->idx)) { + r = -EFAULT; + goto err; + } r = __get_user(last_used_idx, &vq->used->idx); if (r) - return r; + goto err; vq->last_used_idx = vhost16_to_cpu(vq, last_used_idx); return 0; +err: + vq->is_le = is_le; + return r; } EXPORT_SYMBOL_GPL(vhost_init_used); -- cgit v1.2.3 From 7adf5c331347eab03a0ee78b408165a907c11e30 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 16 Feb 2016 15:59:34 +0100 Subject: UPSTREAM: vhost: rename cross-endian helpers The default use case for vhost is when the host and the vring have the same endianness (default native endianness). But there are cases where they differ and vhost should byteswap when accessing the vring. The first case is when the host is big endian and the vring belongs to a virtio 1.0 device, which is always little endian. This is covered by the vq->is_le field. This field is initialized when userspace calls the VHOST_SET_FEATURES ioctl. It is reset when the device stops. We already have a vhost_init_is_le() helper, but the reset operation is opencoded as follows: vq->is_le = virtio_legacy_is_little_endian(); It isn't clear that we are resetting vq->is_le here. This patch moves the code to a helper with a more explicit name. The other case where we may have to byteswap is when the architecture can switch endianness at runtime (bi-endian). If endianness differs in the host and in the guest, then legacy devices need to be used in cross-endian mode. This mode is available with CONFIG_VHOST_CROSS_ENDIAN_LEGACY=y, which introduces a vq->user_be field. Userspace may enable cross-endian mode by calling the SET_VRING_ENDIAN ioctl before the device is started. The cross-endian mode is disabled when the device is stopped. The current names of the helpers that manipulate vq->user_be are unclear. This patch renames those helpers to clearly show that this is cross-endian stuff and with explicit enable/disable semantics. No behaviour change. Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin (cherry picked from commit c507203756ca6303df2191c96c1385e965e2f0b7) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I42271a7cbc4ecc3826116943805bc59d4f8bd192 --- drivers/vhost/vhost.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index e00271076996..135946a21658 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -44,11 +44,21 @@ enum { #define vhost_avail_event(vq) ((__virtio16 __user *)&vq->used->ring[vq->num]) #ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY -static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) +static void vhost_disable_cross_endian(struct vhost_virtqueue *vq) { vq->user_be = !virtio_legacy_is_little_endian(); } +static void vhost_enable_cross_endian_big(struct vhost_virtqueue *vq) +{ + vq->user_be = true; +} + +static void vhost_enable_cross_endian_little(struct vhost_virtqueue *vq) +{ + vq->user_be = false; +} + static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user *argp) { struct vhost_vring_state s; @@ -63,7 +73,10 @@ static long vhost_set_vring_endian(struct vhost_virtqueue *vq, int __user *argp) s.num != VHOST_VRING_BIG_ENDIAN) return -EINVAL; - vq->user_be = s.num; + if (s.num == VHOST_VRING_BIG_ENDIAN) + vhost_enable_cross_endian_big(vq); + else + vhost_enable_cross_endian_little(vq); return 0; } @@ -92,7 +105,7 @@ static void vhost_init_is_le(struct vhost_virtqueue *vq) vq->is_le = vhost_has_feature(vq, VIRTIO_F_VERSION_1) || !vq->user_be; } #else -static void vhost_vq_reset_user_be(struct vhost_virtqueue *vq) +static void vhost_disable_cross_endian(struct vhost_virtqueue *vq) { } @@ -114,6 +127,11 @@ static void vhost_init_is_le(struct vhost_virtqueue *vq) } #endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ +static void vhost_reset_is_le(struct vhost_virtqueue *vq) +{ + vq->is_le = virtio_legacy_is_little_endian(); +} + static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt) { @@ -276,8 +294,8 @@ static void vhost_vq_reset(struct vhost_dev *dev, vq->call = NULL; vq->log_ctx = NULL; vq->memory = NULL; - vq->is_le = virtio_legacy_is_little_endian(); - vhost_vq_reset_user_be(vq); + vhost_reset_is_le(vq); + vhost_disable_cross_endian(vq); } static int vhost_worker(void *data) @@ -1160,7 +1178,7 @@ int vhost_init_used(struct vhost_virtqueue *vq) bool is_le = vq->is_le; if (!vq->private_data) { - vq->is_le = virtio_legacy_is_little_endian(); + vhost_reset_is_le(vq); return 0; } -- cgit v1.2.3 From ea4e49b0dff9cacd52db01dbef9dd7e1ae4bb858 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Tue, 16 Feb 2016 15:59:44 +0100 Subject: UPSTREAM: vhost: rename vhost_init_used() Looking at how callers use this, maybe we should just rename init_used to vhost_vq_init_access. The _used suffix was a hint that we access the vq used ring. But maybe what callers care about is that it must be called after access_ok. Also, this function manipulates the vq->is_le field which isn't related to the vq used ring. This patch simply renames vhost_init_used() to vhost_vq_init_access() as suggested by Michael. No behaviour change. Signed-off-by: Greg Kurz Signed-off-by: Michael S. Tsirkin (cherry picked from commit 80f7d0301e7913f704d3505722f806717c61dff5) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: If8ef33d7f00e515afbff3adc7b00607c4a58fdf6 --- drivers/vhost/net.c | 2 +- drivers/vhost/scsi.c | 2 +- drivers/vhost/test.c | 2 +- drivers/vhost/vhost.c | 4 ++-- drivers/vhost/vhost.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 645b2197930e..211b5538258e 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -917,7 +917,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) vhost_net_disable_vq(n, vq); vq->private_data = sock; - r = vhost_init_used(vq); + r = vhost_vq_init_access(vq); if (r) goto err_used; r = vhost_net_enable_vq(n, vq); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 8fc62a03637a..009315f006bf 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1277,7 +1277,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, vq = &vs->vqs[i].vq; mutex_lock(&vq->mutex); vq->private_data = vs_tpg; - vhost_init_used(vq); + vhost_vq_init_access(vq); mutex_unlock(&vq->mutex); } ret = 0; diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c index f2882ac98726..388eec4e1a90 100644 --- a/drivers/vhost/test.c +++ b/drivers/vhost/test.c @@ -196,7 +196,7 @@ static long vhost_test_run(struct vhost_test *n, int test) oldpriv = vq->private_data; vq->private_data = priv; - r = vhost_init_used(&n->vqs[index]); + r = vhost_vq_init_access(&n->vqs[index]); mutex_unlock(&vq->mutex); diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 135946a21658..167a263dfb86 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1171,7 +1171,7 @@ static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event) return 0; } -int vhost_init_used(struct vhost_virtqueue *vq) +int vhost_vq_init_access(struct vhost_virtqueue *vq) { __virtio16 last_used_idx; int r; @@ -1201,7 +1201,7 @@ err: vq->is_le = is_le; return r; } -EXPORT_SYMBOL_GPL(vhost_init_used); +EXPORT_SYMBOL_GPL(vhost_vq_init_access); static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len, struct iovec iov[], int iov_size) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index d3f767448a72..8f0dd0d915d4 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -148,7 +148,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *, struct vhost_log *log, unsigned int *log_num); void vhost_discard_vq_desc(struct vhost_virtqueue *, int n); -int vhost_init_used(struct vhost_virtqueue *); +int vhost_vq_init_access(struct vhost_virtqueue *); int vhost_add_used(struct vhost_virtqueue *, unsigned int head, int len); int vhost_add_used_n(struct vhost_virtqueue *, struct vring_used_elem *heads, unsigned count); -- cgit v1.2.3 From eb7e61ae8c0aa8b1e9d3e36a055785da096d0f0e Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 4 Mar 2016 06:24:51 -0500 Subject: UPSTREAM: vhost: introduce vhost_has_work() This path introduces a helper which can give a hint for whether or not there's a work queued in the work list. This could be used for busy polling code to exit the busy loop. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin (cherry picked from commit 526d3e7ff515582eaf7cf5d9da2a11bf681204e6) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I2717a212f888b0d3ea78f1ce0bcc21ec9dee5050 --- drivers/vhost/vhost.c | 7 +++++++ drivers/vhost/vhost.h | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 167a263dfb86..65a1d2da114a 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -263,6 +263,13 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work) } EXPORT_SYMBOL_GPL(vhost_work_queue); +/* A lockless hint for busy polling code to exit the loop */ +bool vhost_has_work(struct vhost_dev *dev) +{ + return !list_empty(&dev->work_list); +} +EXPORT_SYMBOL_GPL(vhost_has_work); + void vhost_poll_queue(struct vhost_poll *poll) { vhost_work_queue(poll->dev, &poll->work); diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 8f0dd0d915d4..eef33b11a7ed 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -37,6 +37,7 @@ struct vhost_poll { void vhost_work_init(struct vhost_work *work, vhost_work_fn_t fn); void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work); +bool vhost_has_work(struct vhost_dev *dev); void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn, unsigned long mask, struct vhost_dev *dev); -- cgit v1.2.3 From 179cda3b96b1edc266daa8773938f64c6a0639e1 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 4 Mar 2016 06:24:52 -0500 Subject: UPSTREAM: vhost: introduce vhost_vq_avail_empty() This patch introduces a helper which will return true if we're sure that the available ring is empty for a specific vq. When we're not sure, e.g vq access failure, return false instead. This could be used for busy polling code to exit the busy loop. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin (cherry picked from commit d4a60603fa0b42012decfa058dfa44cffde7a10c) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I1d4e972543470530a5bc37e19f4199b1f345e042 --- drivers/vhost/vhost.c | 14 ++++++++++++++ drivers/vhost/vhost.h | 1 + 2 files changed, 15 insertions(+) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 65a1d2da114a..73d4545ee0d3 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1661,6 +1661,20 @@ void vhost_add_used_and_signal_n(struct vhost_dev *dev, } EXPORT_SYMBOL_GPL(vhost_add_used_and_signal_n); +/* return true if we're sure that avaiable ring is empty */ +bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq) +{ + __virtio16 avail_idx; + int r; + + r = __get_user(avail_idx, &vq->avail->idx); + if (r) + return false; + + return vhost16_to_cpu(vq, avail_idx) == vq->avail_idx; +} +EXPORT_SYMBOL_GPL(vhost_vq_avail_empty); + /* OK, now we need to know about added descriptors. */ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq) { diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index eef33b11a7ed..af5af773bf7a 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -159,6 +159,7 @@ void vhost_add_used_and_signal_n(struct vhost_dev *, struct vhost_virtqueue *, struct vring_used_elem *heads, unsigned count); void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *); void vhost_disable_notify(struct vhost_dev *, struct vhost_virtqueue *); +bool vhost_vq_avail_empty(struct vhost_dev *, struct vhost_virtqueue *); bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *); int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, -- cgit v1.2.3 From a1fc433fea713a935ae82d8ae741bd8787af86de Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 4 Mar 2016 06:24:53 -0500 Subject: UPSTREAM: vhost_net: basic polling support This patch tries to poll for new added tx buffer or socket receive queue for a while at the end of tx/rx processing. The maximum time spent on polling were specified through a new kind of vring ioctl. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin (cherry picked from commit 0308813724606549436d30efd877a80c8e00790e) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I93db6c14e39b2db04e047ee2e0dce3af5436d95e --- drivers/vhost/net.c | 78 +++++++++++++++++++++++++++++++++++++++++++--- drivers/vhost/vhost.c | 14 +++++++++ drivers/vhost/vhost.h | 1 + include/uapi/linux/vhost.h | 6 ++++ 4 files changed, 94 insertions(+), 5 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 211b5538258e..7d411d85de52 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -287,6 +287,43 @@ static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success) rcu_read_unlock_bh(); } +static inline unsigned long busy_clock(void) +{ + return local_clock() >> 10; +} + +static bool vhost_can_busy_poll(struct vhost_dev *dev, + unsigned long endtime) +{ + return likely(!need_resched()) && + likely(!time_after(busy_clock(), endtime)) && + likely(!signal_pending(current)) && + !vhost_has_work(dev); +} + +static int vhost_net_tx_get_vq_desc(struct vhost_net *net, + struct vhost_virtqueue *vq, + struct iovec iov[], unsigned int iov_size, + unsigned int *out_num, unsigned int *in_num) +{ + unsigned long uninitialized_var(endtime); + int r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov), + out_num, in_num, NULL, NULL); + + if (r == vq->num && vq->busyloop_timeout) { + preempt_disable(); + endtime = busy_clock() + vq->busyloop_timeout; + while (vhost_can_busy_poll(vq->dev, endtime) && + vhost_vq_avail_empty(vq->dev, vq)) + cpu_relax_lowlatency(); + preempt_enable(); + r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov), + out_num, in_num, NULL, NULL); + } + + return r; +} + /* Expects to be always run from workqueue - which acts as * read-size critical section for our kind of RCU. */ static void handle_tx(struct vhost_net *net) @@ -331,10 +368,9 @@ static void handle_tx(struct vhost_net *net) % UIO_MAXIOV == nvq->done_idx)) break; - head = vhost_get_vq_desc(vq, vq->iov, - ARRAY_SIZE(vq->iov), - &out, &in, - NULL, NULL); + head = vhost_net_tx_get_vq_desc(net, vq, vq->iov, + ARRAY_SIZE(vq->iov), + &out, &in); /* On error, stop handling until the next kick. */ if (unlikely(head < 0)) break; @@ -435,6 +471,38 @@ static int peek_head_len(struct sock *sk) return len; } +static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) +{ + struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX]; + struct vhost_virtqueue *vq = &nvq->vq; + unsigned long uninitialized_var(endtime); + int len = peek_head_len(sk); + + if (!len && vq->busyloop_timeout) { + /* Both tx vq and rx socket were polled here */ + mutex_lock(&vq->mutex); + vhost_disable_notify(&net->dev, vq); + + preempt_disable(); + endtime = busy_clock() + vq->busyloop_timeout; + + while (vhost_can_busy_poll(&net->dev, endtime) && + skb_queue_empty(&sk->sk_receive_queue) && + vhost_vq_avail_empty(&net->dev, vq)) + cpu_relax_lowlatency(); + + preempt_enable(); + + if (vhost_enable_notify(&net->dev, vq)) + vhost_poll_queue(&vq->poll); + mutex_unlock(&vq->mutex); + + len = peek_head_len(sk); + } + + return len; +} + /* This is a multi-buffer version of vhost_get_desc, that works if * vq has read descriptors only. * @vq - the relevant virtqueue @@ -553,7 +621,7 @@ static void handle_rx(struct vhost_net *net) vq->log : NULL; mergeable = vhost_has_feature(vq, VIRTIO_NET_F_MRG_RXBUF); - while ((sock_len = peek_head_len(sock->sk))) { + while ((sock_len = vhost_net_rx_peek_head_len(net, sock->sk))) { sock_len += sock_hlen; vhost_len = sock_len + vhost_hlen; headcount = get_rx_bufs(vq, vq->heads, vhost_len, diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 73d4545ee0d3..a10459c5ca37 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -303,6 +303,7 @@ static void vhost_vq_reset(struct vhost_dev *dev, vq->memory = NULL; vhost_reset_is_le(vq); vhost_disable_cross_endian(vq); + vq->busyloop_timeout = 0; } static int vhost_worker(void *data) @@ -938,6 +939,19 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) case VHOST_GET_VRING_ENDIAN: r = vhost_get_vring_endian(vq, idx, argp); break; + case VHOST_SET_VRING_BUSYLOOP_TIMEOUT: + if (copy_from_user(&s, argp, sizeof(s))) { + r = -EFAULT; + break; + } + vq->busyloop_timeout = s.num; + break; + case VHOST_GET_VRING_BUSYLOOP_TIMEOUT: + s.index = idx; + s.num = vq->busyloop_timeout; + if (copy_to_user(argp, &s, sizeof(s))) + r = -EFAULT; + break; default: r = -ENOIOCTLCMD; } diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index af5af773bf7a..d36d8beb3351 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -115,6 +115,7 @@ struct vhost_virtqueue { /* Ring endianness requested by userspace for cross-endian support. */ bool user_be; #endif + u32 busyloop_timeout; }; struct vhost_dev { diff --git a/include/uapi/linux/vhost.h b/include/uapi/linux/vhost.h index ab3731917bac..61a8777178c6 100644 --- a/include/uapi/linux/vhost.h +++ b/include/uapi/linux/vhost.h @@ -126,6 +126,12 @@ struct vhost_memory { #define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file) /* Set eventfd to signal an error */ #define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file) +/* Set busy loop timeout (in us) */ +#define VHOST_SET_VRING_BUSYLOOP_TIMEOUT _IOW(VHOST_VIRTIO, 0x23, \ + struct vhost_vring_state) +/* Get busy loop timeout (in us) */ +#define VHOST_GET_VRING_BUSYLOOP_TIMEOUT _IOW(VHOST_VIRTIO, 0x24, \ + struct vhost_vring_state) /* VHOST_NET specific defines */ -- cgit v1.2.3 From 4c64016c654438267e4c4773d946d2a537ecc244 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 22 Mar 2016 17:05:52 +0100 Subject: BACKPORT: AF_VSOCK: Shrink the area influenced by prepare_to_wait When a thread is prepared for waiting by calling prepare_to_wait, sleeping is not allowed until either the wait has taken place or finish_wait has been called. The existing code in af_vsock imposed unnecessary no-sleep assumptions to a broad list of backend functions. This patch shrinks the influence of prepare_to_wait to the area where it is strictly needed, therefore relaxing the no-sleep restriction there. Signed-off-by: Claudio Imbrenda Signed-off-by: David S. Miller (cherry picked from commit f7f9b5e7f8eccfd68ffa7b8d74b07c478bb9e7f0) [astrachan: Backported around stable backport 3223ea1 ("vsock: use new wait API for vsock_stream_sendmsg()")] Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Cody Schuffelen Change-Id: Ic1d7bae4b1187ad48194bf4d0b1dd09ab0275734 --- net/vmw_vsock/af_vsock.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 7f1d166ce612..2cb12fe3b60d 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1559,7 +1559,7 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg, while (total_written < len) { ssize_t written; - add_wait_queue(sk_sleep(sk), &wait); + prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); while (vsock_stream_has_space(vsk) == 0 && sk->sk_err == 0 && !(sk->sk_shutdown & SEND_SHUTDOWN) && @@ -1568,13 +1568,13 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg, /* Don't wait for non-blocking sockets. */ if (timeout == 0) { err = -EAGAIN; - remove_wait_queue(sk_sleep(sk), &wait); + finish_wait(sk_sleep(sk), &wait); goto out_err; } err = transport->notify_send_pre_block(vsk, &send_data); if (err < 0) { - remove_wait_queue(sk_sleep(sk), &wait); + finish_wait(sk_sleep(sk), &wait); goto out_err; } @@ -1583,15 +1583,15 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg, lock_sock(sk); if (signal_pending(current)) { err = sock_intr_errno(timeout); - remove_wait_queue(sk_sleep(sk), &wait); + finish_wait(sk_sleep(sk), &wait); goto out_err; } else if (timeout == 0) { err = -EAGAIN; - remove_wait_queue(sk_sleep(sk), &wait); + finish_wait(sk_sleep(sk), &wait); goto out_err; } } - remove_wait_queue(sk_sleep(sk), &wait); + finish_wait(sk_sleep(sk), &wait); /* These checks occur both as part of and after the loop * conditional since we need to check before and after -- cgit v1.2.3 From ec0b5a2904a24503db0b515ab284b228d22200df Mon Sep 17 00:00:00 2001 From: Jorgen Hansen Date: Mon, 18 Apr 2016 23:58:52 -0700 Subject: UPSTREAM: VSOCK: Only check error on skb_recv_datagram when skb is NULL If skb_recv_datagram returns an skb, we should ignore the err value returned. Otherwise, datagram receives will return EAGAIN when they have to wait for a datagram. Acked-by: Adit Ranadive Signed-off-by: Jorgen Hansen Signed-off-by: David S. Miller (cherry picked from commit 9c995cc9a206a008699da82f6cd01e9b2615649a) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Cody Schuffelen Change-Id: I69d487529656cb2fe8be9c2cef0db440d4db5cac --- net/vmw_vsock/vmci_transport.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index 217810674c35..4597d6a5da5c 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c @@ -1771,11 +1771,8 @@ static int vmci_transport_dgram_dequeue(struct vsock_sock *vsk, /* Retrieve the head sk_buff from the socket's receive queue. */ err = 0; skb = skb_recv_datagram(&vsk->sk, flags, noblock, &err); - if (err) - return err; - if (!skb) - return -EAGAIN; + return err; dg = (struct vmci_datagram *)skb->data; if (!dg) @@ -2190,7 +2187,7 @@ module_exit(vmci_transport_exit); MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMCI transport for Virtual Sockets"); -MODULE_VERSION("1.0.3.0-k"); +MODULE_VERSION("1.0.4.0-k"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("vmware_vsock"); MODULE_ALIAS_NETPROTO(PF_VSOCK); -- cgit v1.2.3 From 2f1f7c837a53f60b5103cc34f8de9c71fd014614 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 25 Apr 2016 22:14:32 -0400 Subject: UPSTREAM: vhost: simplify work flushing We used to implement the work flushing through tracking queued seq, done seq, and the number of flushing. This patch simplify this by just implement work flushing through another kind of vhost work with completion. This will be used by lockless enqueuing patch. Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 7235acdb1144460d9f520f0d931f3cbb79eb244c) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: Id3903050706dd734a0217c56ad8ca99b2b22471e --- drivers/vhost/vhost.c | 53 ++++++++++++++++++++------------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index a10459c5ca37..f942082b984c 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -132,6 +132,19 @@ static void vhost_reset_is_le(struct vhost_virtqueue *vq) vq->is_le = virtio_legacy_is_little_endian(); } +struct vhost_flush_struct { + struct vhost_work work; + struct completion wait_event; +}; + +static void vhost_flush_work(struct vhost_work *work) +{ + struct vhost_flush_struct *s; + + s = container_of(work, struct vhost_flush_struct, work); + complete(&s->wait_event); +} + static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt) { @@ -159,8 +172,6 @@ void vhost_work_init(struct vhost_work *work, vhost_work_fn_t fn) INIT_LIST_HEAD(&work->node); work->fn = fn; init_waitqueue_head(&work->done); - work->flushing = 0; - work->queue_seq = work->done_seq = 0; } EXPORT_SYMBOL_GPL(vhost_work_init); @@ -211,31 +222,17 @@ void vhost_poll_stop(struct vhost_poll *poll) } EXPORT_SYMBOL_GPL(vhost_poll_stop); -static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work, - unsigned seq) -{ - int left; - - spin_lock_irq(&dev->work_lock); - left = seq - work->done_seq; - spin_unlock_irq(&dev->work_lock); - return left <= 0; -} - void vhost_work_flush(struct vhost_dev *dev, struct vhost_work *work) { - unsigned seq; - int flushing; + struct vhost_flush_struct flush; + + if (dev->worker) { + init_completion(&flush.wait_event); + vhost_work_init(&flush.work, vhost_flush_work); - spin_lock_irq(&dev->work_lock); - seq = work->queue_seq; - work->flushing++; - spin_unlock_irq(&dev->work_lock); - wait_event(work->done, vhost_work_seq_done(dev, work, seq)); - spin_lock_irq(&dev->work_lock); - flushing = --work->flushing; - spin_unlock_irq(&dev->work_lock); - BUG_ON(flushing < 0); + vhost_work_queue(dev, &flush.work); + wait_for_completion(&flush.wait_event); + } } EXPORT_SYMBOL_GPL(vhost_work_flush); @@ -254,7 +251,6 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work) spin_lock_irqsave(&dev->work_lock, flags); if (list_empty(&work->node)) { list_add_tail(&work->node, &dev->work_list); - work->queue_seq++; spin_unlock_irqrestore(&dev->work_lock, flags); wake_up_process(dev->worker); } else { @@ -310,7 +306,6 @@ static int vhost_worker(void *data) { struct vhost_dev *dev = data; struct vhost_work *work = NULL; - unsigned uninitialized_var(seq); mm_segment_t oldfs = get_fs(); set_fs(USER_DS); @@ -321,11 +316,6 @@ static int vhost_worker(void *data) set_current_state(TASK_INTERRUPTIBLE); spin_lock_irq(&dev->work_lock); - if (work) { - work->done_seq = seq; - if (work->flushing) - wake_up_all(&work->done); - } if (kthread_should_stop()) { spin_unlock_irq(&dev->work_lock); @@ -336,7 +326,6 @@ static int vhost_worker(void *data) work = list_first_entry(&dev->work_list, struct vhost_work, node); list_del_init(&work->node); - seq = work->queue_seq; } else work = NULL; spin_unlock_irq(&dev->work_lock); -- cgit v1.2.3 From 74df5bd4266a1206e3f156a9f1a29e2de4d915ec Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 25 Apr 2016 22:14:33 -0400 Subject: UPSTREAM: vhost: lockless enqueuing We use spinlock to synchronize the work list now which may cause unnecessary contentions. So this patch switch to use llist to remove this contention. Pktgen tests shows about 5% improvement: Before: ~1300000 pps After: ~1370000 pps Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin (cherry picked from commit 04b96e5528ca97199b429810fe963185a67dd40e) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: Icf032cf2010eaedd92dc5906d454274709b4a9b4 --- drivers/vhost/vhost.c | 52 +++++++++++++++++++++++++-------------------------- drivers/vhost/vhost.h | 7 ++++--- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index f942082b984c..a508c40c9e25 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -169,7 +169,7 @@ static int vhost_poll_wakeup(wait_queue_t *wait, unsigned mode, int sync, void vhost_work_init(struct vhost_work *work, vhost_work_fn_t fn) { - INIT_LIST_HEAD(&work->node); + clear_bit(VHOST_WORK_QUEUED, &work->flags); work->fn = fn; init_waitqueue_head(&work->done); } @@ -246,15 +246,16 @@ EXPORT_SYMBOL_GPL(vhost_poll_flush); void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work) { - unsigned long flags; + if (!dev->worker) + return; - spin_lock_irqsave(&dev->work_lock, flags); - if (list_empty(&work->node)) { - list_add_tail(&work->node, &dev->work_list); - spin_unlock_irqrestore(&dev->work_lock, flags); + if (!test_and_set_bit(VHOST_WORK_QUEUED, &work->flags)) { + /* We can only add the work to the list after we're + * sure it was not in the list. + */ + smp_mb(); + llist_add(&work->node, &dev->work_list); wake_up_process(dev->worker); - } else { - spin_unlock_irqrestore(&dev->work_lock, flags); } } EXPORT_SYMBOL_GPL(vhost_work_queue); @@ -262,7 +263,7 @@ EXPORT_SYMBOL_GPL(vhost_work_queue); /* A lockless hint for busy polling code to exit the loop */ bool vhost_has_work(struct vhost_dev *dev) { - return !list_empty(&dev->work_list); + return !llist_empty(&dev->work_list); } EXPORT_SYMBOL_GPL(vhost_has_work); @@ -305,7 +306,8 @@ static void vhost_vq_reset(struct vhost_dev *dev, static int vhost_worker(void *data) { struct vhost_dev *dev = data; - struct vhost_work *work = NULL; + struct vhost_work *work, *work_next; + struct llist_node *node; mm_segment_t oldfs = get_fs(); set_fs(USER_DS); @@ -315,29 +317,25 @@ static int vhost_worker(void *data) /* mb paired w/ kthread_stop */ set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irq(&dev->work_lock); - if (kthread_should_stop()) { - spin_unlock_irq(&dev->work_lock); __set_current_state(TASK_RUNNING); break; } - if (!list_empty(&dev->work_list)) { - work = list_first_entry(&dev->work_list, - struct vhost_work, node); - list_del_init(&work->node); - } else - work = NULL; - spin_unlock_irq(&dev->work_lock); - if (work) { + node = llist_del_all(&dev->work_list); + if (!node) + schedule(); + + node = llist_reverse_order(node); + /* make sure flag is seen after deletion */ + smp_wmb(); + llist_for_each_entry_safe(work, work_next, node, node) { + clear_bit(VHOST_WORK_QUEUED, &work->flags); __set_current_state(TASK_RUNNING); work->fn(work); if (need_resched()) schedule(); - } else - schedule(); - + } } unuse_mm(dev->mm); set_fs(oldfs); @@ -398,9 +396,9 @@ void vhost_dev_init(struct vhost_dev *dev, dev->log_file = NULL; dev->memory = NULL; dev->mm = NULL; - spin_lock_init(&dev->work_lock); - INIT_LIST_HEAD(&dev->work_list); dev->worker = NULL; + init_llist_head(&dev->work_list); + for (i = 0; i < dev->nvqs; ++i) { vq = dev->vqs[i]; @@ -566,7 +564,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked) /* No one will access memory at this point */ kvfree(dev->memory); dev->memory = NULL; - WARN_ON(!list_empty(&dev->work_list)); + WARN_ON(!llist_empty(&dev->work_list)); if (dev->worker) { kthread_stop(dev->worker); dev->worker = NULL; diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index d36d8beb3351..6690e645d2f8 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -15,13 +15,15 @@ struct vhost_work; typedef void (*vhost_work_fn_t)(struct vhost_work *work); +#define VHOST_WORK_QUEUED 1 struct vhost_work { - struct list_head node; + struct llist_node node; vhost_work_fn_t fn; wait_queue_head_t done; int flushing; unsigned queue_seq; unsigned done_seq; + unsigned long flags; }; /* Poll a file (eventfd or socket) */ @@ -126,8 +128,7 @@ struct vhost_dev { int nvqs; struct file *log_file; struct eventfd_ctx *log_ctx; - spinlock_t work_lock; - struct list_head work_list; + struct llist_head work_list; struct task_struct *worker; }; -- cgit v1.2.3 From f8b9e1a37bcc1f80f05e3442b832579416ca32f7 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 1 May 2016 14:49:15 +0200 Subject: UPSTREAM: VSOCK: constify vsock_transport structure The vsock_transport structure is never modified, so declare it as const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: David S. Miller (cherry picked from commit 56130915bbe31656c80f7493d28536693f8de0e2) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Cody Schuffelen Change-Id: I59ffded185fbf22aaeb39753870ef9c866ab1a2a --- net/vmw_vsock/vmci_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index 4597d6a5da5c..f3fc34f7a77e 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c @@ -2087,7 +2087,7 @@ static u32 vmci_transport_get_local_cid(void) return vmci_get_context_id(); } -static struct vsock_transport vmci_transport = { +static const struct vsock_transport vmci_transport = { .init = vmci_transport_socket_init, .destruct = vmci_transport_destruct, .release = vmci_transport_release, -- cgit v1.2.3 From 1f1f6576f3b58668e9f55bc309c58beee97bfb42 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 1 Jun 2016 01:56:33 -0400 Subject: UPSTREAM: vhost_net: stop polling socket during rx processing We don't stop rx polling socket during rx processing, this will lead unnecessary wakeups from under layer net devices (E.g sock_def_readable() form tun). Rx will be slowed down in this way. This patch avoids this by stop polling socket during rx processing. A small drawback is that this introduces some overheads in light load case because of the extra start/stop polling, but single netperf TCP_RR does not notice any change. In a super heavy load case, e.g using pktgen to inject packet to guest, we get about ~8.8% improvement on pps: before: ~1240000 pkt/s after: ~1350000 pkt/s Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller (cherry picked from commit 8241a1e466cd56e6c10472cac9c1ad4e54bc65db) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: Ia51c61a6c1976b6f6406342f369ffc365d964078 --- drivers/vhost/net.c | 64 +++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 7d411d85de52..9bf9af7667f4 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -301,6 +301,32 @@ static bool vhost_can_busy_poll(struct vhost_dev *dev, !vhost_has_work(dev); } +static void vhost_net_disable_vq(struct vhost_net *n, + struct vhost_virtqueue *vq) +{ + struct vhost_net_virtqueue *nvq = + container_of(vq, struct vhost_net_virtqueue, vq); + struct vhost_poll *poll = n->poll + (nvq - n->vqs); + if (!vq->private_data) + return; + vhost_poll_stop(poll); +} + +static int vhost_net_enable_vq(struct vhost_net *n, + struct vhost_virtqueue *vq) +{ + struct vhost_net_virtqueue *nvq = + container_of(vq, struct vhost_net_virtqueue, vq); + struct vhost_poll *poll = n->poll + (nvq - n->vqs); + struct socket *sock; + + sock = vq->private_data; + if (!sock) + return 0; + + return vhost_poll_start(poll, sock->file); +} + static int vhost_net_tx_get_vq_desc(struct vhost_net *net, struct vhost_virtqueue *vq, struct iovec iov[], unsigned int iov_size, @@ -613,6 +639,7 @@ static void handle_rx(struct vhost_net *net) if (!sock) goto out; vhost_disable_notify(&net->dev, vq); + vhost_net_disable_vq(net, vq); vhost_hlen = nvq->vhost_hlen; sock_hlen = nvq->sock_hlen; @@ -629,7 +656,7 @@ static void handle_rx(struct vhost_net *net) likely(mergeable) ? UIO_MAXIOV : 1); /* On error, stop handling until the next kick. */ if (unlikely(headcount < 0)) - break; + goto out; /* On overrun, truncate and discard */ if (unlikely(headcount > UIO_MAXIOV)) { iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1); @@ -648,7 +675,7 @@ static void handle_rx(struct vhost_net *net) } /* Nothing new? Wait for eventfd to tell us * they refilled. */ - break; + goto out; } /* We don't need to be notified again. */ iov_iter_init(&msg.msg_iter, READ, vq->iov, in, vhost_len); @@ -676,7 +703,7 @@ static void handle_rx(struct vhost_net *net) &fixup) != sizeof(hdr)) { vq_err(vq, "Unable to write vnet_hdr " "at addr %p\n", vq->iov->iov_base); - break; + goto out; } } else { /* Header came from socket; we'll need to patch @@ -692,7 +719,7 @@ static void handle_rx(struct vhost_net *net) &fixup) != sizeof num_buffers) { vq_err(vq, "Failed num_buffers write"); vhost_discard_vq_desc(vq, headcount); - break; + goto out; } vhost_add_used_and_signal_n(&net->dev, vq, vq->heads, headcount); @@ -701,9 +728,10 @@ static void handle_rx(struct vhost_net *net) total_len += vhost_len; if (unlikely(total_len >= VHOST_NET_WEIGHT)) { vhost_poll_queue(&vq->poll); - break; + goto out; } } + vhost_net_enable_vq(net, vq); out: mutex_unlock(&vq->mutex); } @@ -782,32 +810,6 @@ static int vhost_net_open(struct inode *inode, struct file *f) return 0; } -static void vhost_net_disable_vq(struct vhost_net *n, - struct vhost_virtqueue *vq) -{ - struct vhost_net_virtqueue *nvq = - container_of(vq, struct vhost_net_virtqueue, vq); - struct vhost_poll *poll = n->poll + (nvq - n->vqs); - if (!vq->private_data) - return; - vhost_poll_stop(poll); -} - -static int vhost_net_enable_vq(struct vhost_net *n, - struct vhost_virtqueue *vq) -{ - struct vhost_net_virtqueue *nvq = - container_of(vq, struct vhost_net_virtqueue, vq); - struct vhost_poll *poll = n->poll + (nvq - n->vqs); - struct socket *sock; - - sock = vq->private_data; - if (!sock) - return 0; - - return vhost_poll_start(poll, sock->file); -} - static struct socket *vhost_net_stop_vq(struct vhost_net *n, struct vhost_virtqueue *vq) { -- cgit v1.2.3 From 606946ea25fb23109af1326414a5c73647595d6a Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 23 Jun 2016 02:04:30 -0400 Subject: UPSTREAM: vhost: introduce vhost memory accessors This patch introduces vhost memory accessors which were just wrappers for userspace address access helpers. This is a requirement for vhost device iotlb implementation which will add iotlb translations in those accessors. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin (cherry picked from commit bfe2bc512884d0b1c5297a15350f940ca80e439b) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: Ia67c171384109e646f55027a71dd8df9c6b9c61a --- drivers/vhost/vhost.c | 50 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index a508c40c9e25..5725063e320b 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -638,6 +638,22 @@ static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem, return 1; } +#define vhost_put_user(vq, x, ptr) __put_user(x, ptr) + +static int vhost_copy_to_user(struct vhost_virtqueue *vq, void *to, + const void *from, unsigned size) +{ + return __copy_to_user(to, from, size); +} + +#define vhost_get_user(vq, x, ptr) __get_user(x, ptr) + +static int vhost_copy_from_user(struct vhost_virtqueue *vq, void *to, + void *from, unsigned size) +{ + return __copy_from_user(to, from, size); +} + static int vq_access_ok(struct vhost_virtqueue *vq, unsigned int num, struct vring_desc __user *desc, struct vring_avail __user *avail, @@ -1144,7 +1160,8 @@ EXPORT_SYMBOL_GPL(vhost_log_write); static int vhost_update_used_flags(struct vhost_virtqueue *vq) { void __user *used; - if (__put_user(cpu_to_vhost16(vq, vq->used_flags), &vq->used->flags) < 0) + if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->used_flags), + &vq->used->flags) < 0) return -EFAULT; if (unlikely(vq->log_used)) { /* Make sure the flag is seen before log. */ @@ -1162,7 +1179,8 @@ static int vhost_update_used_flags(struct vhost_virtqueue *vq) static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event) { - if (__put_user(cpu_to_vhost16(vq, vq->avail_idx), vhost_avail_event(vq))) + if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->avail_idx), + vhost_avail_event(vq))) return -EFAULT; if (unlikely(vq->log_used)) { void __user *used; @@ -1200,7 +1218,7 @@ int vhost_vq_init_access(struct vhost_virtqueue *vq) r = -EFAULT; goto err; } - r = __get_user(last_used_idx, &vq->used->idx); + r = vhost_get_user(vq, last_used_idx, &vq->used->idx); if (r) goto err; vq->last_used_idx = vhost16_to_cpu(vq, last_used_idx); @@ -1380,7 +1398,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq, /* Check it isn't doing very strange things with descriptor numbers. */ last_avail_idx = vq->last_avail_idx; - if (unlikely(__get_user(avail_idx, &vq->avail->idx))) { + if (unlikely(vhost_get_user(vq, avail_idx, &vq->avail->idx))) { vq_err(vq, "Failed to access avail idx at %p\n", &vq->avail->idx); return -EFAULT; @@ -1402,8 +1420,8 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq, /* Grab the next descriptor number they're advertising, and increment * the index we've seen. */ - if (unlikely(__get_user(ring_head, - &vq->avail->ring[last_avail_idx & (vq->num - 1)]))) { + if (unlikely(vhost_get_user(vq, ring_head, + &vq->avail->ring[last_avail_idx & (vq->num - 1)]))) { vq_err(vq, "Failed to read head: idx %d address %p\n", last_avail_idx, &vq->avail->ring[last_avail_idx % vq->num]); @@ -1438,7 +1456,8 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq, i, vq->num, head); return -EINVAL; } - ret = __copy_from_user(&desc, vq->desc + i, sizeof desc); + ret = vhost_copy_from_user(vq, &desc, vq->desc + i, + sizeof desc); if (unlikely(ret)) { vq_err(vq, "Failed to get descriptor: idx %d addr %p\n", i, vq->desc + i); @@ -1526,15 +1545,15 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq, start = vq->last_used_idx & (vq->num - 1); used = vq->used->ring + start; if (count == 1) { - if (__put_user(heads[0].id, &used->id)) { + if (vhost_put_user(vq, heads[0].id, &used->id)) { vq_err(vq, "Failed to write used id"); return -EFAULT; } - if (__put_user(heads[0].len, &used->len)) { + if (vhost_put_user(vq, heads[0].len, &used->len)) { vq_err(vq, "Failed to write used len"); return -EFAULT; } - } else if (__copy_to_user(used, heads, count * sizeof *used)) { + } else if (vhost_copy_to_user(vq, used, heads, count * sizeof *used)) { vq_err(vq, "Failed to write used"); return -EFAULT; } @@ -1578,7 +1597,8 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads, /* Make sure buffer is written before we update index. */ smp_wmb(); - if (__put_user(cpu_to_vhost16(vq, vq->last_used_idx), &vq->used->idx)) { + if (vhost_put_user(vq, cpu_to_vhost16(vq, vq->last_used_idx), + &vq->used->idx)) { vq_err(vq, "Failed to increment used idx"); return -EFAULT; } @@ -1612,7 +1632,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq) if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) { __virtio16 flags; - if (__get_user(flags, &vq->avail->flags)) { + if (vhost_get_user(vq, flags, &vq->avail->flags)) { vq_err(vq, "Failed to get flags"); return true; } @@ -1626,7 +1646,7 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq) if (unlikely(!v)) return true; - if (__get_user(event, vhost_used_event(vq))) { + if (vhost_get_user(vq, event, vhost_used_event(vq))) { vq_err(vq, "Failed to get used event idx"); return true; } @@ -1668,7 +1688,7 @@ bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq) __virtio16 avail_idx; int r; - r = __get_user(avail_idx, &vq->avail->idx); + r = vhost_get_user(vq, avail_idx, &vq->avail->idx); if (r) return false; @@ -1703,7 +1723,7 @@ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq) /* They could have slipped one in as we were doing that: make * sure it's written, then check again. */ smp_mb(); - r = __get_user(avail_idx, &vq->avail->idx); + r = vhost_get_user(vq, avail_idx, &vq->avail->idx); if (r) { vq_err(vq, "Failed to check avail idx at %p: %d\n", &vq->avail->idx, r); -- cgit v1.2.3 From ca9385aac9f2a9bce49b299ccf377ee03e64f360 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Tue, 15 Jan 2019 15:45:17 -0800 Subject: BACKPORT: vhost: convert pre sorted vhost memory array to interval tree Current pre-sorted memory region array has some limitations for future device IOTLB conversion: 1) need extra work for adding and removing a single region, and it's expected to be slow because of sorting or memory re-allocation. 2) need extra work of removing a large range which may intersect several regions with different size. 3) need trick for a replacement policy like LRU To overcome the above shortcomings, this patch convert it to interval tree which can easily address the above issue with almost no extra work. The patch could be used for: - Extend the current API and only let the userspace to send diffs of memory table. - Simplify Device IOTLB implementation. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin (cherry picked from commit a9709d6874d55130663567577a9b05c35138cc6b) [astrachan: Backported around stable backport 711df71 ("vhost_net: stop device during reset owner")] Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I51c7c7229908a5ce1f082a80eeda5a01e85c2234 --- drivers/vhost/net.c | 8 +-- drivers/vhost/vhost.c | 182 ++++++++++++++++++++++++++++---------------------- drivers/vhost/vhost.h | 27 ++++++-- 3 files changed, 128 insertions(+), 89 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 9bf9af7667f4..9b5e6788f9bf 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -1039,21 +1039,21 @@ static long vhost_net_reset_owner(struct vhost_net *n) struct socket *tx_sock = NULL; struct socket *rx_sock = NULL; long err; - struct vhost_memory *memory; + struct vhost_umem *umem; mutex_lock(&n->dev.mutex); err = vhost_dev_check_owner(&n->dev); if (err) goto done; - memory = vhost_dev_reset_owner_prepare(); - if (!memory) { + umem = vhost_dev_reset_owner_prepare(); + if (!umem) { err = -ENOMEM; goto done; } vhost_net_stop(n, &tx_sock, &rx_sock); vhost_net_flush(n); vhost_dev_stop(&n->dev); - vhost_dev_reset_owner(&n->dev, memory); + vhost_dev_reset_owner(&n->dev, umem); vhost_net_vq_reset(n); done: mutex_unlock(&n->dev.mutex); diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 5725063e320b..bb06d3b3392a 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "vhost.h" @@ -43,6 +44,10 @@ enum { #define vhost_used_event(vq) ((__virtio16 __user *)&vq->avail->ring[vq->num]) #define vhost_avail_event(vq) ((__virtio16 __user *)&vq->used->ring[vq->num]) +INTERVAL_TREE_DEFINE(struct vhost_umem_node, + rb, __u64, __subtree_last, + START, LAST, , vhost_umem_interval_tree); + #ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY static void vhost_disable_cross_endian(struct vhost_virtqueue *vq) { @@ -297,10 +302,10 @@ static void vhost_vq_reset(struct vhost_dev *dev, vq->call_ctx = NULL; vq->call = NULL; vq->log_ctx = NULL; - vq->memory = NULL; vhost_reset_is_le(vq); vhost_disable_cross_endian(vq); vq->busyloop_timeout = 0; + vq->umem = NULL; } static int vhost_worker(void *data) @@ -394,7 +399,7 @@ void vhost_dev_init(struct vhost_dev *dev, mutex_init(&dev->mutex); dev->log_ctx = NULL; dev->log_file = NULL; - dev->memory = NULL; + dev->umem = NULL; dev->mm = NULL; dev->worker = NULL; init_llist_head(&dev->work_list); @@ -499,27 +504,36 @@ err_mm: } EXPORT_SYMBOL_GPL(vhost_dev_set_owner); -struct vhost_memory *vhost_dev_reset_owner_prepare(void) +static void *vhost_kvzalloc(unsigned long size) { - return kmalloc(offsetof(struct vhost_memory, regions), GFP_KERNEL); + void *n = kzalloc(size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); + + if (!n) + n = vzalloc(size); + return n; +} + +struct vhost_umem *vhost_dev_reset_owner_prepare(void) +{ + return vhost_kvzalloc(sizeof(struct vhost_umem)); } EXPORT_SYMBOL_GPL(vhost_dev_reset_owner_prepare); /* Caller should have device mutex */ -void vhost_dev_reset_owner(struct vhost_dev *dev, struct vhost_memory *memory) +void vhost_dev_reset_owner(struct vhost_dev *dev, struct vhost_umem *umem) { int i; vhost_dev_cleanup(dev, true); /* Restore memory to default empty mapping. */ - memory->nregions = 0; - dev->memory = memory; + INIT_LIST_HEAD(&umem->umem_list); + dev->umem = umem; /* We don't need VQ locks below since vhost_dev_cleanup makes sure * VQs aren't running. */ for (i = 0; i < dev->nvqs; ++i) - dev->vqs[i]->memory = memory; + dev->vqs[i]->umem = umem; } EXPORT_SYMBOL_GPL(vhost_dev_reset_owner); @@ -536,6 +550,21 @@ void vhost_dev_stop(struct vhost_dev *dev) } EXPORT_SYMBOL_GPL(vhost_dev_stop); +static void vhost_umem_clean(struct vhost_umem *umem) +{ + struct vhost_umem_node *node, *tmp; + + if (!umem) + return; + + list_for_each_entry_safe(node, tmp, &umem->umem_list, link) { + vhost_umem_interval_tree_remove(node, &umem->umem_tree); + list_del(&node->link); + kvfree(node); + } + kvfree(umem); +} + /* Caller should have device mutex if and only if locked is set */ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked) { @@ -562,8 +591,8 @@ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked) fput(dev->log_file); dev->log_file = NULL; /* No one will access memory at this point */ - kvfree(dev->memory); - dev->memory = NULL; + vhost_umem_clean(dev->umem); + dev->umem = NULL; WARN_ON(!llist_empty(&dev->work_list)); if (dev->worker) { kthread_stop(dev->worker); @@ -589,25 +618,25 @@ static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz) } /* Caller should have vq mutex and device mutex. */ -static int vq_memory_access_ok(void __user *log_base, struct vhost_memory *mem, +static int vq_memory_access_ok(void __user *log_base, struct vhost_umem *umem, int log_all) { - int i; + struct vhost_umem_node *node; - if (!mem) + if (!umem) return 0; - for (i = 0; i < mem->nregions; ++i) { - struct vhost_memory_region *m = mem->regions + i; - unsigned long a = m->userspace_addr; - if (m->memory_size > ULONG_MAX) + list_for_each_entry(node, &umem->umem_list, link) { + unsigned long a = node->userspace_addr; + + if (node->size > ULONG_MAX) return 0; else if (!access_ok(VERIFY_WRITE, (void __user *)a, - m->memory_size)) + node->size)) return 0; else if (log_all && !log_access_ok(log_base, - m->guest_phys_addr, - m->memory_size)) + node->start, + node->size)) return 0; } return 1; @@ -615,7 +644,7 @@ static int vq_memory_access_ok(void __user *log_base, struct vhost_memory *mem, /* Can we switch to this memory table? */ /* Caller should have device mutex but not vq mutex */ -static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem, +static int memory_access_ok(struct vhost_dev *d, struct vhost_umem *umem, int log_all) { int i; @@ -628,7 +657,8 @@ static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem, log = log_all || vhost_has_feature(d->vqs[i], VHOST_F_LOG_ALL); /* If ring is inactive, will check when it's enabled. */ if (d->vqs[i]->private_data) - ok = vq_memory_access_ok(d->vqs[i]->log_base, mem, log); + ok = vq_memory_access_ok(d->vqs[i]->log_base, + umem, log); else ok = 1; mutex_unlock(&d->vqs[i]->mutex); @@ -671,7 +701,7 @@ static int vq_access_ok(struct vhost_virtqueue *vq, unsigned int num, /* Caller should have device mutex but not vq mutex */ int vhost_log_access_ok(struct vhost_dev *dev) { - return memory_access_ok(dev, dev->memory, 1); + return memory_access_ok(dev, dev->umem, 1); } EXPORT_SYMBOL_GPL(vhost_log_access_ok); @@ -682,7 +712,7 @@ static int vq_log_access_ok(struct vhost_virtqueue *vq, { size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0; - return vq_memory_access_ok(log_base, vq->memory, + return vq_memory_access_ok(log_base, vq->umem, vhost_has_feature(vq, VHOST_F_LOG_ALL)) && (!vq->log_used || log_access_ok(log_base, vq->log_addr, sizeof *vq->used + @@ -698,28 +728,12 @@ int vhost_vq_access_ok(struct vhost_virtqueue *vq) } EXPORT_SYMBOL_GPL(vhost_vq_access_ok); -static int vhost_memory_reg_sort_cmp(const void *p1, const void *p2) -{ - const struct vhost_memory_region *r1 = p1, *r2 = p2; - if (r1->guest_phys_addr < r2->guest_phys_addr) - return 1; - if (r1->guest_phys_addr > r2->guest_phys_addr) - return -1; - return 0; -} - -static void *vhost_kvzalloc(unsigned long size) -{ - void *n = kzalloc(size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); - - if (!n) - n = vzalloc(size); - return n; -} - static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) { - struct vhost_memory mem, *newmem, *oldmem; + struct vhost_memory mem, *newmem; + struct vhost_memory_region *region; + struct vhost_umem_node *node; + struct vhost_umem *newumem, *oldumem; unsigned long size = offsetof(struct vhost_memory, regions); int i; @@ -739,24 +753,52 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) kvfree(newmem); return -EFAULT; } - sort(newmem->regions, newmem->nregions, sizeof(*newmem->regions), - vhost_memory_reg_sort_cmp, NULL); - if (!memory_access_ok(d, newmem, 0)) { + newumem = vhost_kvzalloc(sizeof(*newumem)); + if (!newumem) { kvfree(newmem); - return -EFAULT; + return -ENOMEM; + } + + newumem->umem_tree = RB_ROOT; + INIT_LIST_HEAD(&newumem->umem_list); + + for (region = newmem->regions; + region < newmem->regions + mem.nregions; + region++) { + node = vhost_kvzalloc(sizeof(*node)); + if (!node) + goto err; + node->start = region->guest_phys_addr; + node->size = region->memory_size; + node->last = node->start + node->size - 1; + node->userspace_addr = region->userspace_addr; + INIT_LIST_HEAD(&node->link); + list_add_tail(&node->link, &newumem->umem_list); + vhost_umem_interval_tree_insert(node, &newumem->umem_tree); } - oldmem = d->memory; - d->memory = newmem; + + if (!memory_access_ok(d, newumem, 0)) + goto err; + + oldumem = d->umem; + d->umem = newumem; /* All memory accesses are done under some VQ mutex. */ for (i = 0; i < d->nvqs; ++i) { mutex_lock(&d->vqs[i]->mutex); - d->vqs[i]->memory = newmem; + d->vqs[i]->umem = newumem; mutex_unlock(&d->vqs[i]->mutex); } - kvfree(oldmem); + + kvfree(newmem); + vhost_umem_clean(oldumem); return 0; + +err: + vhost_umem_clean(newumem); + kvfree(newmem); + return -EFAULT; } long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) @@ -1060,28 +1102,6 @@ done: } EXPORT_SYMBOL_GPL(vhost_dev_ioctl); -static const struct vhost_memory_region *find_region(struct vhost_memory *mem, - __u64 addr, __u32 len) -{ - const struct vhost_memory_region *reg; - int start = 0, end = mem->nregions; - - while (start < end) { - int slot = start + (end - start) / 2; - reg = mem->regions + slot; - if (addr >= reg->guest_phys_addr) - end = slot; - else - start = slot + 1; - } - - reg = mem->regions + start; - if (addr >= reg->guest_phys_addr && - reg->guest_phys_addr + reg->memory_size > addr) - return reg; - return NULL; -} - /* TODO: This is really inefficient. We need something like get_user() * (instruction directly accesses the data, with an exception table entry * returning -EFAULT). See Documentation/x86/exception-tables.txt. @@ -1232,29 +1252,29 @@ EXPORT_SYMBOL_GPL(vhost_vq_init_access); static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len, struct iovec iov[], int iov_size) { - const struct vhost_memory_region *reg; - struct vhost_memory *mem; + const struct vhost_umem_node *node; + struct vhost_umem *umem = vq->umem; struct iovec *_iov; u64 s = 0; int ret = 0; - mem = vq->memory; while ((u64)len > s) { u64 size; if (unlikely(ret >= iov_size)) { ret = -ENOBUFS; break; } - reg = find_region(mem, addr, len); - if (unlikely(!reg)) { + node = vhost_umem_interval_tree_iter_first(&umem->umem_tree, + addr, addr + len - 1); + if (node == NULL || node->start > addr) { ret = -EFAULT; break; } _iov = iov + ret; - size = reg->memory_size - addr + reg->guest_phys_addr; + size = node->size - addr + node->start; _iov->iov_len = min((u64)len - s, size); _iov->iov_base = (void __user *)(unsigned long) - (reg->userspace_addr + addr - reg->guest_phys_addr); + (node->userspace_addr + addr - node->start); s += size; addr += size; ++ret; diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 6690e645d2f8..eaaf6df72218 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -55,6 +55,25 @@ struct vhost_log { u64 len; }; +#define START(node) ((node)->start) +#define LAST(node) ((node)->last) + +struct vhost_umem_node { + struct rb_node rb; + struct list_head link; + __u64 start; + __u64 last; + __u64 size; + __u64 userspace_addr; + __u64 flags_padding; + __u64 __subtree_last; +}; + +struct vhost_umem { + struct rb_root umem_tree; + struct list_head umem_list; +}; + /* The virtqueue structure describes a queue attached to a device. */ struct vhost_virtqueue { struct vhost_dev *dev; @@ -103,7 +122,7 @@ struct vhost_virtqueue { struct iovec *indirect; struct vring_used_elem *heads; /* Protected by virtqueue mutex. */ - struct vhost_memory *memory; + struct vhost_umem *umem; void *private_data; u64 acked_features; /* Log write descriptors */ @@ -121,7 +140,6 @@ struct vhost_virtqueue { }; struct vhost_dev { - struct vhost_memory *memory; struct mm_struct *mm; struct mutex mutex; struct vhost_virtqueue **vqs; @@ -130,14 +148,15 @@ struct vhost_dev { struct eventfd_ctx *log_ctx; struct llist_head work_list; struct task_struct *worker; + struct vhost_umem *umem; }; void vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs, int nvqs); long vhost_dev_set_owner(struct vhost_dev *dev); bool vhost_dev_has_owner(struct vhost_dev *dev); long vhost_dev_check_owner(struct vhost_dev *); -struct vhost_memory *vhost_dev_reset_owner_prepare(void); -void vhost_dev_reset_owner(struct vhost_dev *, struct vhost_memory *); +struct vhost_umem *vhost_dev_reset_owner_prepare(void); +void vhost_dev_reset_owner(struct vhost_dev *, struct vhost_umem *); void vhost_dev_cleanup(struct vhost_dev *, bool locked); void vhost_dev_stop(struct vhost_dev *); long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, void __user *argp); -- cgit v1.2.3 From ef6c5bb7eb80e44863fd54f97a77ed7e21b57dc8 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 23 Jun 2016 02:04:32 -0400 Subject: UPSTREAM: vhost: new device IOTLB API This patch tries to implement an device IOTLB for vhost. This could be used with userspace(qemu) implementation of DMA remapping to emulate an IOMMU for the guest. The idea is simple, cache the translation in a software device IOTLB (which is implemented as an interval tree) in vhost and use vhost_net file descriptor for reporting IOTLB miss and IOTLB update/invalidation. When vhost meets an IOTLB miss, the fault address, size and access can be read from the file. After userspace finishes the translation, it writes the translated address to the vhost_net file to update the device IOTLB. When device IOTLB is enabled by setting VIRTIO_F_IOMMU_PLATFORM all vq addresses set by ioctl are treated as iova instead of virtual address and the accessing can only be done through IOTLB instead of direct userspace memory access. Before each round or vq processing, all vq metadata is prefetched in device IOTLB to make sure no translation fault happens during vq processing. In most cases, virtqueues are contiguous even in virtual address space. The IOTLB translation for virtqueue itself may make it a little slower. We might add fast path cache on top of this patch. Signed-off-by: Jason Wang [mst: use virtio feature bit: VHOST_F_DEVICE_IOTLB -> VIRTIO_F_IOMMU_PLATFORM ] [mst: fix build warnings ] Signed-off-by: Michael S. Tsirkin [ weiyj.lk: missing unlock on error ] Signed-off-by: Wei Yongjun (cherry picked from commit 6b1e6cc7855b09a0a9bfa1d9f30172ba366f161c) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: I10e4e64d6bc9b36a0d9b444c2319e290921c63c6 --- drivers/vhost/net.c | 59 ++++- drivers/vhost/vhost.c | 636 ++++++++++++++++++++++++++++++++++++++++++--- drivers/vhost/vhost.h | 32 ++- include/uapi/linux/vhost.h | 28 ++ 4 files changed, 705 insertions(+), 50 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 9b5e6788f9bf..77e94ecfd608 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -61,7 +61,8 @@ MODULE_PARM_DESC(experimental_zcopytx, "Enable Zero Copy TX;" enum { VHOST_NET_FEATURES = VHOST_FEATURES | (1ULL << VHOST_NET_F_VIRTIO_NET_HDR) | - (1ULL << VIRTIO_NET_F_MRG_RXBUF) + (1ULL << VIRTIO_NET_F_MRG_RXBUF) | + (1ULL << VIRTIO_F_IOMMU_PLATFORM) }; enum { @@ -334,7 +335,7 @@ static int vhost_net_tx_get_vq_desc(struct vhost_net *net, { unsigned long uninitialized_var(endtime); int r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov), - out_num, in_num, NULL, NULL); + out_num, in_num, NULL, NULL); if (r == vq->num && vq->busyloop_timeout) { preempt_disable(); @@ -344,7 +345,7 @@ static int vhost_net_tx_get_vq_desc(struct vhost_net *net, cpu_relax_lowlatency(); preempt_enable(); r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov), - out_num, in_num, NULL, NULL); + out_num, in_num, NULL, NULL); } return r; @@ -377,6 +378,9 @@ static void handle_tx(struct vhost_net *net) if (!sock) goto out; + if (!vq_iotlb_prefetch(vq)) + goto out; + vhost_disable_notify(&net->dev, vq); hdr_size = nvq->vhost_hlen; @@ -638,6 +642,10 @@ static void handle_rx(struct vhost_net *net) sock = vq->private_data; if (!sock) goto out; + + if (!vq_iotlb_prefetch(vq)) + goto out; + vhost_disable_notify(&net->dev, vq); vhost_net_disable_vq(net, vq); @@ -1084,10 +1092,14 @@ static int vhost_net_set_features(struct vhost_net *n, u64 features) } mutex_lock(&n->dev.mutex); if ((features & (1 << VHOST_F_LOG_ALL)) && - !vhost_log_access_ok(&n->dev)) { - mutex_unlock(&n->dev.mutex); - return -EFAULT; + !vhost_log_access_ok(&n->dev)) + goto out_unlock; + + if ((features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))) { + if (vhost_init_device_iotlb(&n->dev, true)) + goto out_unlock; } + for (i = 0; i < VHOST_NET_VQ_MAX; ++i) { mutex_lock(&n->vqs[i].vq.mutex); n->vqs[i].vq.acked_features = features; @@ -1097,6 +1109,10 @@ static int vhost_net_set_features(struct vhost_net *n, u64 features) } mutex_unlock(&n->dev.mutex); return 0; + +out_unlock: + mutex_unlock(&n->dev.mutex); + return -EFAULT; } static long vhost_net_set_owner(struct vhost_net *n) @@ -1170,9 +1186,40 @@ static long vhost_net_compat_ioctl(struct file *f, unsigned int ioctl, } #endif +static ssize_t vhost_net_chr_read_iter(struct kiocb *iocb, struct iov_iter *to) +{ + struct file *file = iocb->ki_filp; + struct vhost_net *n = file->private_data; + struct vhost_dev *dev = &n->dev; + int noblock = file->f_flags & O_NONBLOCK; + + return vhost_chr_read_iter(dev, to, noblock); +} + +static ssize_t vhost_net_chr_write_iter(struct kiocb *iocb, + struct iov_iter *from) +{ + struct file *file = iocb->ki_filp; + struct vhost_net *n = file->private_data; + struct vhost_dev *dev = &n->dev; + + return vhost_chr_write_iter(dev, from); +} + +static unsigned int vhost_net_chr_poll(struct file *file, poll_table *wait) +{ + struct vhost_net *n = file->private_data; + struct vhost_dev *dev = &n->dev; + + return vhost_chr_poll(file, dev, wait); +} + static const struct file_operations vhost_net_fops = { .owner = THIS_MODULE, .release = vhost_net_release, + .read_iter = vhost_net_chr_read_iter, + .write_iter = vhost_net_chr_write_iter, + .poll = vhost_net_chr_poll, .unlocked_ioctl = vhost_net_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = vhost_net_compat_ioctl, diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index bb06d3b3392a..bd3428ce6b9b 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -36,6 +36,10 @@ static ushort max_mem_regions = 64; module_param(max_mem_regions, ushort, 0444); MODULE_PARM_DESC(max_mem_regions, "Maximum number of memory regions in memory map. (default: 64)"); +static int max_iotlb_entries = 2048; +module_param(max_iotlb_entries, int, 0444); +MODULE_PARM_DESC(max_iotlb_entries, + "Maximum number of iotlb entries. (default: 2048)"); enum { VHOST_MEMORY_F_LOG = 0x1, @@ -306,6 +310,7 @@ static void vhost_vq_reset(struct vhost_dev *dev, vhost_disable_cross_endian(vq); vq->busyloop_timeout = 0; vq->umem = NULL; + vq->iotlb = NULL; } static int vhost_worker(void *data) @@ -400,9 +405,14 @@ void vhost_dev_init(struct vhost_dev *dev, dev->log_ctx = NULL; dev->log_file = NULL; dev->umem = NULL; + dev->iotlb = NULL; dev->mm = NULL; dev->worker = NULL; init_llist_head(&dev->work_list); + init_waitqueue_head(&dev->wait); + INIT_LIST_HEAD(&dev->read_list); + INIT_LIST_HEAD(&dev->pending_list); + spin_lock_init(&dev->iotlb_lock); for (i = 0; i < dev->nvqs; ++i) { @@ -550,6 +560,15 @@ void vhost_dev_stop(struct vhost_dev *dev) } EXPORT_SYMBOL_GPL(vhost_dev_stop); +static void vhost_umem_free(struct vhost_umem *umem, + struct vhost_umem_node *node) +{ + vhost_umem_interval_tree_remove(node, &umem->umem_tree); + list_del(&node->link); + kfree(node); + umem->numem--; +} + static void vhost_umem_clean(struct vhost_umem *umem) { struct vhost_umem_node *node, *tmp; @@ -557,14 +576,31 @@ static void vhost_umem_clean(struct vhost_umem *umem) if (!umem) return; - list_for_each_entry_safe(node, tmp, &umem->umem_list, link) { - vhost_umem_interval_tree_remove(node, &umem->umem_tree); - list_del(&node->link); - kvfree(node); - } + list_for_each_entry_safe(node, tmp, &umem->umem_list, link) + vhost_umem_free(umem, node); + kvfree(umem); } +static void vhost_clear_msg(struct vhost_dev *dev) +{ + struct vhost_msg_node *node, *n; + + spin_lock(&dev->iotlb_lock); + + list_for_each_entry_safe(node, n, &dev->read_list, node) { + list_del(&node->node); + kfree(node); + } + + list_for_each_entry_safe(node, n, &dev->pending_list, node) { + list_del(&node->node); + kfree(node); + } + + spin_unlock(&dev->iotlb_lock); +} + /* Caller should have device mutex if and only if locked is set */ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked) { @@ -593,6 +629,10 @@ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked) /* No one will access memory at this point */ vhost_umem_clean(dev->umem); dev->umem = NULL; + vhost_umem_clean(dev->iotlb); + dev->iotlb = NULL; + vhost_clear_msg(dev); + wake_up_interruptible_poll(&dev->wait, POLLIN | POLLRDNORM); WARN_ON(!llist_empty(&dev->work_list)); if (dev->worker) { kthread_stop(dev->worker); @@ -668,28 +708,381 @@ static int memory_access_ok(struct vhost_dev *d, struct vhost_umem *umem, return 1; } -#define vhost_put_user(vq, x, ptr) __put_user(x, ptr) +static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len, + struct iovec iov[], int iov_size, int access); static int vhost_copy_to_user(struct vhost_virtqueue *vq, void *to, const void *from, unsigned size) { - return __copy_to_user(to, from, size); -} + int ret; -#define vhost_get_user(vq, x, ptr) __get_user(x, ptr) + if (!vq->iotlb) + return __copy_to_user(to, from, size); + else { + /* This function should be called after iotlb + * prefetch, which means we're sure that all vq + * could be access through iotlb. So -EAGAIN should + * not happen in this case. + */ + /* TODO: more fast path */ + struct iov_iter t; + ret = translate_desc(vq, (u64)(uintptr_t)to, size, vq->iotlb_iov, + ARRAY_SIZE(vq->iotlb_iov), + VHOST_ACCESS_WO); + if (ret < 0) + goto out; + iov_iter_init(&t, WRITE, vq->iotlb_iov, ret, size); + ret = copy_to_iter(from, size, &t); + if (ret == size) + ret = 0; + } +out: + return ret; +} static int vhost_copy_from_user(struct vhost_virtqueue *vq, void *to, void *from, unsigned size) { - return __copy_from_user(to, from, size); + int ret; + + if (!vq->iotlb) + return __copy_from_user(to, from, size); + else { + /* This function should be called after iotlb + * prefetch, which means we're sure that vq + * could be access through iotlb. So -EAGAIN should + * not happen in this case. + */ + /* TODO: more fast path */ + struct iov_iter f; + ret = translate_desc(vq, (u64)(uintptr_t)from, size, vq->iotlb_iov, + ARRAY_SIZE(vq->iotlb_iov), + VHOST_ACCESS_RO); + if (ret < 0) { + vq_err(vq, "IOTLB translation failure: uaddr " + "%p size 0x%llx\n", from, + (unsigned long long) size); + goto out; + } + iov_iter_init(&f, READ, vq->iotlb_iov, ret, size); + ret = copy_from_iter(to, size, &f); + if (ret == size) + ret = 0; + } + +out: + return ret; +} + +static void __user *__vhost_get_user(struct vhost_virtqueue *vq, + void *addr, unsigned size) +{ + int ret; + + /* This function should be called after iotlb + * prefetch, which means we're sure that vq + * could be access through iotlb. So -EAGAIN should + * not happen in this case. + */ + /* TODO: more fast path */ + ret = translate_desc(vq, (u64)(uintptr_t)addr, size, vq->iotlb_iov, + ARRAY_SIZE(vq->iotlb_iov), + VHOST_ACCESS_RO); + if (ret < 0) { + vq_err(vq, "IOTLB translation failure: uaddr " + "%p size 0x%llx\n", addr, + (unsigned long long) size); + return NULL; + } + + if (ret != 1 || vq->iotlb_iov[0].iov_len != size) { + vq_err(vq, "Non atomic userspace memory access: uaddr " + "%p size 0x%llx\n", addr, + (unsigned long long) size); + return NULL; + } + + return vq->iotlb_iov[0].iov_base; +} + +#define vhost_put_user(vq, x, ptr) \ +({ \ + int ret = -EFAULT; \ + if (!vq->iotlb) { \ + ret = __put_user(x, ptr); \ + } else { \ + __typeof__(ptr) to = \ + (__typeof__(ptr)) __vhost_get_user(vq, ptr, sizeof(*ptr)); \ + if (to != NULL) \ + ret = __put_user(x, to); \ + else \ + ret = -EFAULT; \ + } \ + ret; \ +}) + +#define vhost_get_user(vq, x, ptr) \ +({ \ + int ret; \ + if (!vq->iotlb) { \ + ret = __get_user(x, ptr); \ + } else { \ + __typeof__(ptr) from = \ + (__typeof__(ptr)) __vhost_get_user(vq, ptr, sizeof(*ptr)); \ + if (from != NULL) \ + ret = __get_user(x, from); \ + else \ + ret = -EFAULT; \ + } \ + ret; \ +}) + +static void vhost_dev_lock_vqs(struct vhost_dev *d) +{ + int i = 0; + for (i = 0; i < d->nvqs; ++i) + mutex_lock(&d->vqs[i]->mutex); +} + +static void vhost_dev_unlock_vqs(struct vhost_dev *d) +{ + int i = 0; + for (i = 0; i < d->nvqs; ++i) + mutex_unlock(&d->vqs[i]->mutex); +} + +static int vhost_new_umem_range(struct vhost_umem *umem, + u64 start, u64 size, u64 end, + u64 userspace_addr, int perm) +{ + struct vhost_umem_node *tmp, *node = kmalloc(sizeof(*node), GFP_ATOMIC); + + if (!node) + return -ENOMEM; + + if (umem->numem == max_iotlb_entries) { + tmp = list_first_entry(&umem->umem_list, typeof(*tmp), link); + vhost_umem_free(umem, tmp); + } + + node->start = start; + node->size = size; + node->last = end; + node->userspace_addr = userspace_addr; + node->perm = perm; + INIT_LIST_HEAD(&node->link); + list_add_tail(&node->link, &umem->umem_list); + vhost_umem_interval_tree_insert(node, &umem->umem_tree); + umem->numem++; + + return 0; +} + +static void vhost_del_umem_range(struct vhost_umem *umem, + u64 start, u64 end) +{ + struct vhost_umem_node *node; + + while ((node = vhost_umem_interval_tree_iter_first(&umem->umem_tree, + start, end))) + vhost_umem_free(umem, node); +} + +static void vhost_iotlb_notify_vq(struct vhost_dev *d, + struct vhost_iotlb_msg *msg) +{ + struct vhost_msg_node *node, *n; + + spin_lock(&d->iotlb_lock); + + list_for_each_entry_safe(node, n, &d->pending_list, node) { + struct vhost_iotlb_msg *vq_msg = &node->msg.iotlb; + if (msg->iova <= vq_msg->iova && + msg->iova + msg->size - 1 > vq_msg->iova && + vq_msg->type == VHOST_IOTLB_MISS) { + vhost_poll_queue(&node->vq->poll); + list_del(&node->node); + kfree(node); + } + } + + spin_unlock(&d->iotlb_lock); +} + +static int umem_access_ok(u64 uaddr, u64 size, int access) +{ + unsigned long a = uaddr; + + if ((access & VHOST_ACCESS_RO) && + !access_ok(VERIFY_READ, (void __user *)a, size)) + return -EFAULT; + if ((access & VHOST_ACCESS_WO) && + !access_ok(VERIFY_WRITE, (void __user *)a, size)) + return -EFAULT; + return 0; +} + +int vhost_process_iotlb_msg(struct vhost_dev *dev, + struct vhost_iotlb_msg *msg) +{ + int ret = 0; + + vhost_dev_lock_vqs(dev); + switch (msg->type) { + case VHOST_IOTLB_UPDATE: + if (!dev->iotlb) { + ret = -EFAULT; + break; + } + if (umem_access_ok(msg->uaddr, msg->size, msg->perm)) { + ret = -EFAULT; + break; + } + if (vhost_new_umem_range(dev->iotlb, msg->iova, msg->size, + msg->iova + msg->size - 1, + msg->uaddr, msg->perm)) { + ret = -ENOMEM; + break; + } + vhost_iotlb_notify_vq(dev, msg); + break; + case VHOST_IOTLB_INVALIDATE: + vhost_del_umem_range(dev->iotlb, msg->iova, + msg->iova + msg->size - 1); + break; + default: + ret = -EINVAL; + break; + } + + vhost_dev_unlock_vqs(dev); + return ret; +} +ssize_t vhost_chr_write_iter(struct vhost_dev *dev, + struct iov_iter *from) +{ + struct vhost_msg_node node; + unsigned size = sizeof(struct vhost_msg); + size_t ret; + int err; + + if (iov_iter_count(from) < size) + return 0; + ret = copy_from_iter(&node.msg, size, from); + if (ret != size) + goto done; + + switch (node.msg.type) { + case VHOST_IOTLB_MSG: + err = vhost_process_iotlb_msg(dev, &node.msg.iotlb); + if (err) + ret = err; + break; + default: + ret = -EINVAL; + break; + } + +done: + return ret; +} +EXPORT_SYMBOL(vhost_chr_write_iter); + +unsigned int vhost_chr_poll(struct file *file, struct vhost_dev *dev, + poll_table *wait) +{ + unsigned int mask = 0; + + poll_wait(file, &dev->wait, wait); + + if (!list_empty(&dev->read_list)) + mask |= POLLIN | POLLRDNORM; + + return mask; +} +EXPORT_SYMBOL(vhost_chr_poll); + +ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to, + int noblock) +{ + DEFINE_WAIT(wait); + struct vhost_msg_node *node; + ssize_t ret = 0; + unsigned size = sizeof(struct vhost_msg); + + if (iov_iter_count(to) < size) + return 0; + + while (1) { + if (!noblock) + prepare_to_wait(&dev->wait, &wait, + TASK_INTERRUPTIBLE); + + node = vhost_dequeue_msg(dev, &dev->read_list); + if (node) + break; + if (noblock) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + if (!dev->iotlb) { + ret = -EBADFD; + break; + } + + schedule(); + } + + if (!noblock) + finish_wait(&dev->wait, &wait); + + if (node) { + ret = copy_to_iter(&node->msg, size, to); + + if (ret != size || node->msg.type != VHOST_IOTLB_MISS) { + kfree(node); + return ret; + } + + vhost_enqueue_msg(dev, &dev->pending_list, node); + } + + return ret; +} +EXPORT_SYMBOL_GPL(vhost_chr_read_iter); + +static int vhost_iotlb_miss(struct vhost_virtqueue *vq, u64 iova, int access) +{ + struct vhost_dev *dev = vq->dev; + struct vhost_msg_node *node; + struct vhost_iotlb_msg *msg; + + node = vhost_new_msg(vq, VHOST_IOTLB_MISS); + if (!node) + return -ENOMEM; + + msg = &node->msg.iotlb; + msg->type = VHOST_IOTLB_MISS; + msg->iova = iova; + msg->perm = access; + + vhost_enqueue_msg(dev, &dev->read_list, node); + + return 0; } static int vq_access_ok(struct vhost_virtqueue *vq, unsigned int num, struct vring_desc __user *desc, struct vring_avail __user *avail, struct vring_used __user *used) + { size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0; + return access_ok(VERIFY_READ, desc, num * sizeof *desc) && access_ok(VERIFY_READ, avail, sizeof *avail + num * sizeof *avail->ring + s) && @@ -697,6 +1090,54 @@ static int vq_access_ok(struct vhost_virtqueue *vq, unsigned int num, sizeof *used + num * sizeof *used->ring + s); } +static int iotlb_access_ok(struct vhost_virtqueue *vq, + int access, u64 addr, u64 len) +{ + const struct vhost_umem_node *node; + struct vhost_umem *umem = vq->iotlb; + u64 s = 0, size; + + while (len > s) { + node = vhost_umem_interval_tree_iter_first(&umem->umem_tree, + addr, + addr + len - 1); + if (node == NULL || node->start > addr) { + vhost_iotlb_miss(vq, addr, access); + return false; + } else if (!(node->perm & access)) { + /* Report the possible access violation by + * request another translation from userspace. + */ + return false; + } + + size = node->size - addr + node->start; + s += size; + addr += size; + } + + return true; +} + +int vq_iotlb_prefetch(struct vhost_virtqueue *vq) +{ + size_t s = vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0; + unsigned int num = vq->num; + + if (!vq->iotlb) + return 1; + + return iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->desc, + num * sizeof *vq->desc) && + iotlb_access_ok(vq, VHOST_ACCESS_RO, (u64)(uintptr_t)vq->avail, + sizeof *vq->avail + + num * sizeof *vq->avail->ring + s) && + iotlb_access_ok(vq, VHOST_ACCESS_WO, (u64)(uintptr_t)vq->used, + sizeof *vq->used + + num * sizeof *vq->used->ring + s); +} +EXPORT_SYMBOL_GPL(vq_iotlb_prefetch); + /* Can we log writes? */ /* Caller should have device mutex but not vq mutex */ int vhost_log_access_ok(struct vhost_dev *dev) @@ -723,16 +1164,35 @@ static int vq_log_access_ok(struct vhost_virtqueue *vq, /* Caller should have vq mutex and device mutex */ int vhost_vq_access_ok(struct vhost_virtqueue *vq) { + if (vq->iotlb) { + /* When device IOTLB was used, the access validation + * will be validated during prefetching. + */ + return 1; + } return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used) && vq_log_access_ok(vq, vq->log_base); } EXPORT_SYMBOL_GPL(vhost_vq_access_ok); +static struct vhost_umem *vhost_umem_alloc(void) +{ + struct vhost_umem *umem = vhost_kvzalloc(sizeof(*umem)); + + if (!umem) + return NULL; + + umem->umem_tree = RB_ROOT; + umem->numem = 0; + INIT_LIST_HEAD(&umem->umem_list); + + return umem; +} + static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) { struct vhost_memory mem, *newmem; struct vhost_memory_region *region; - struct vhost_umem_node *node; struct vhost_umem *newumem, *oldumem; unsigned long size = offsetof(struct vhost_memory, regions); int i; @@ -754,28 +1214,23 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) return -EFAULT; } - newumem = vhost_kvzalloc(sizeof(*newumem)); + newumem = vhost_umem_alloc(); if (!newumem) { kvfree(newmem); return -ENOMEM; } - newumem->umem_tree = RB_ROOT; - INIT_LIST_HEAD(&newumem->umem_list); - for (region = newmem->regions; region < newmem->regions + mem.nregions; region++) { - node = vhost_kvzalloc(sizeof(*node)); - if (!node) + if (vhost_new_umem_range(newumem, + region->guest_phys_addr, + region->memory_size, + region->guest_phys_addr + + region->memory_size - 1, + region->userspace_addr, + VHOST_ACCESS_RW)) goto err; - node->start = region->guest_phys_addr; - node->size = region->memory_size; - node->last = node->start + node->size - 1; - node->userspace_addr = region->userspace_addr; - INIT_LIST_HEAD(&node->link); - list_add_tail(&node->link, &newumem->umem_list); - vhost_umem_interval_tree_insert(node, &newumem->umem_tree); } if (!memory_access_ok(d, newumem, 0)) @@ -1020,6 +1475,30 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) } EXPORT_SYMBOL_GPL(vhost_vring_ioctl); +int vhost_init_device_iotlb(struct vhost_dev *d, bool enabled) +{ + struct vhost_umem *niotlb, *oiotlb; + int i; + + niotlb = vhost_umem_alloc(); + if (!niotlb) + return -ENOMEM; + + oiotlb = d->iotlb; + d->iotlb = niotlb; + + for (i = 0; i < d->nvqs; ++i) { + mutex_lock(&d->vqs[i]->mutex); + d->vqs[i]->iotlb = niotlb; + mutex_unlock(&d->vqs[i]->mutex); + } + + vhost_umem_clean(oiotlb); + + return 0; +} +EXPORT_SYMBOL_GPL(vhost_init_device_iotlb); + /* Caller must have device mutex */ long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp) { @@ -1234,15 +1713,20 @@ int vhost_vq_init_access(struct vhost_virtqueue *vq) if (r) goto err; vq->signalled_used_valid = false; - if (!access_ok(VERIFY_READ, &vq->used->idx, sizeof vq->used->idx)) { + if (!vq->iotlb && + !access_ok(VERIFY_READ, &vq->used->idx, sizeof vq->used->idx)) { r = -EFAULT; goto err; } r = vhost_get_user(vq, last_used_idx, &vq->used->idx); - if (r) + if (r) { + vq_err(vq, "Can't access used idx at %p\n", + &vq->used->idx); goto err; + } vq->last_used_idx = vhost16_to_cpu(vq, last_used_idx); return 0; + err: vq->is_le = is_le; return r; @@ -1250,10 +1734,11 @@ err: EXPORT_SYMBOL_GPL(vhost_vq_init_access); static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len, - struct iovec iov[], int iov_size) + struct iovec iov[], int iov_size, int access) { const struct vhost_umem_node *node; - struct vhost_umem *umem = vq->umem; + struct vhost_dev *dev = vq->dev; + struct vhost_umem *umem = dev->iotlb ? dev->iotlb : dev->umem; struct iovec *_iov; u64 s = 0; int ret = 0; @@ -1264,12 +1749,21 @@ static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len, ret = -ENOBUFS; break; } + node = vhost_umem_interval_tree_iter_first(&umem->umem_tree, addr, addr + len - 1); if (node == NULL || node->start > addr) { - ret = -EFAULT; + if (umem != dev->iotlb) { + ret = -EFAULT; + break; + } + ret = -EAGAIN; + break; + } else if (!(node->perm & access)) { + ret = -EPERM; break; } + _iov = iov + ret; size = node->size - addr + node->start; _iov->iov_len = min((u64)len - s, size); @@ -1280,6 +1774,8 @@ static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len, ++ret; } + if (ret == -EAGAIN) + vhost_iotlb_miss(vq, addr, access); return ret; } @@ -1314,7 +1810,7 @@ static int get_indirect(struct vhost_virtqueue *vq, unsigned int i = 0, count, found = 0; u32 len = vhost32_to_cpu(vq, indirect->len); struct iov_iter from; - int ret; + int ret, access; /* Sanity check */ if (unlikely(len % sizeof desc)) { @@ -1326,9 +1822,10 @@ static int get_indirect(struct vhost_virtqueue *vq, } ret = translate_desc(vq, vhost64_to_cpu(vq, indirect->addr), len, vq->indirect, - UIO_MAXIOV); + UIO_MAXIOV, VHOST_ACCESS_RO); if (unlikely(ret < 0)) { - vq_err(vq, "Translation failure %d in indirect.\n", ret); + if (ret != -EAGAIN) + vq_err(vq, "Translation failure %d in indirect.\n", ret); return ret; } iov_iter_init(&from, READ, vq->indirect, ret, len); @@ -1366,16 +1863,22 @@ static int get_indirect(struct vhost_virtqueue *vq, return -EINVAL; } + if (desc.flags & cpu_to_vhost16(vq, VRING_DESC_F_WRITE)) + access = VHOST_ACCESS_WO; + else + access = VHOST_ACCESS_RO; + ret = translate_desc(vq, vhost64_to_cpu(vq, desc.addr), vhost32_to_cpu(vq, desc.len), iov + iov_count, - iov_size - iov_count); + iov_size - iov_count, access); if (unlikely(ret < 0)) { - vq_err(vq, "Translation failure %d indirect idx %d\n", - ret, i); + if (ret != -EAGAIN) + vq_err(vq, "Translation failure %d indirect idx %d\n", + ret, i); return ret; } /* If this is an input descriptor, increment that count. */ - if (desc.flags & cpu_to_vhost16(vq, VRING_DESC_F_WRITE)) { + if (access == VHOST_ACCESS_WO) { *in_num += ret; if (unlikely(log)) { log[*log_num].addr = vhost64_to_cpu(vq, desc.addr); @@ -1414,7 +1917,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq, u16 last_avail_idx; __virtio16 avail_idx; __virtio16 ring_head; - int ret; + int ret, access; /* Check it isn't doing very strange things with descriptor numbers. */ last_avail_idx = vq->last_avail_idx; @@ -1488,22 +1991,28 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq, out_num, in_num, log, log_num, &desc); if (unlikely(ret < 0)) { - vq_err(vq, "Failure detected " - "in indirect descriptor at idx %d\n", i); + if (ret != -EAGAIN) + vq_err(vq, "Failure detected " + "in indirect descriptor at idx %d\n", i); return ret; } continue; } + if (desc.flags & cpu_to_vhost16(vq, VRING_DESC_F_WRITE)) + access = VHOST_ACCESS_WO; + else + access = VHOST_ACCESS_RO; ret = translate_desc(vq, vhost64_to_cpu(vq, desc.addr), vhost32_to_cpu(vq, desc.len), iov + iov_count, - iov_size - iov_count); + iov_size - iov_count, access); if (unlikely(ret < 0)) { - vq_err(vq, "Translation failure %d descriptor idx %d\n", - ret, i); + if (ret != -EAGAIN) + vq_err(vq, "Translation failure %d descriptor idx %d\n", + ret, i); return ret; } - if (desc.flags & cpu_to_vhost16(vq, VRING_DESC_F_WRITE)) { + if (access == VHOST_ACCESS_WO) { /* If this is an input descriptor, * increment that count. */ *in_num += ret; @@ -1771,6 +2280,47 @@ void vhost_disable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq) } EXPORT_SYMBOL_GPL(vhost_disable_notify); +/* Create a new message. */ +struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type) +{ + struct vhost_msg_node *node = kmalloc(sizeof *node, GFP_KERNEL); + if (!node) + return NULL; + node->vq = vq; + node->msg.type = type; + return node; +} +EXPORT_SYMBOL_GPL(vhost_new_msg); + +void vhost_enqueue_msg(struct vhost_dev *dev, struct list_head *head, + struct vhost_msg_node *node) +{ + spin_lock(&dev->iotlb_lock); + list_add_tail(&node->node, head); + spin_unlock(&dev->iotlb_lock); + + wake_up_interruptible_poll(&dev->wait, POLLIN | POLLRDNORM); +} +EXPORT_SYMBOL_GPL(vhost_enqueue_msg); + +struct vhost_msg_node *vhost_dequeue_msg(struct vhost_dev *dev, + struct list_head *head) +{ + struct vhost_msg_node *node = NULL; + + spin_lock(&dev->iotlb_lock); + if (!list_empty(head)) { + node = list_first_entry(head, struct vhost_msg_node, + node); + list_del(&node->node); + } + spin_unlock(&dev->iotlb_lock); + + return node; +} +EXPORT_SYMBOL_GPL(vhost_dequeue_msg); + + static int __init vhost_init(void) { return 0; diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index eaaf6df72218..78f3c5fc02e4 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -65,13 +65,15 @@ struct vhost_umem_node { __u64 last; __u64 size; __u64 userspace_addr; - __u64 flags_padding; + __u32 perm; + __u32 flags_padding; __u64 __subtree_last; }; struct vhost_umem { struct rb_root umem_tree; struct list_head umem_list; + int numem; }; /* The virtqueue structure describes a queue attached to a device. */ @@ -119,10 +121,12 @@ struct vhost_virtqueue { u64 log_addr; struct iovec iov[UIO_MAXIOV]; + struct iovec iotlb_iov[64]; struct iovec *indirect; struct vring_used_elem *heads; /* Protected by virtqueue mutex. */ struct vhost_umem *umem; + struct vhost_umem *iotlb; void *private_data; u64 acked_features; /* Log write descriptors */ @@ -139,6 +143,12 @@ struct vhost_virtqueue { u32 busyloop_timeout; }; +struct vhost_msg_node { + struct vhost_msg msg; + struct vhost_virtqueue *vq; + struct list_head node; +}; + struct vhost_dev { struct mm_struct *mm; struct mutex mutex; @@ -149,6 +159,11 @@ struct vhost_dev { struct llist_head work_list; struct task_struct *worker; struct vhost_umem *umem; + struct vhost_umem *iotlb; + spinlock_t iotlb_lock; + struct list_head read_list; + struct list_head pending_list; + wait_queue_head_t wait; }; void vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs, int nvqs); @@ -185,6 +200,21 @@ bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *); int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log, unsigned int log_num, u64 len); +int vq_iotlb_prefetch(struct vhost_virtqueue *vq); + +struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type); +void vhost_enqueue_msg(struct vhost_dev *dev, + struct list_head *head, + struct vhost_msg_node *node); +struct vhost_msg_node *vhost_dequeue_msg(struct vhost_dev *dev, + struct list_head *head); +unsigned int vhost_chr_poll(struct file *file, struct vhost_dev *dev, + poll_table *wait); +ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to, + int noblock); +ssize_t vhost_chr_write_iter(struct vhost_dev *dev, + struct iov_iter *from); +int vhost_init_device_iotlb(struct vhost_dev *d, bool enabled); #define vq_err(vq, fmt, ...) do { \ pr_debug(pr_fmt(fmt), ##__VA_ARGS__); \ diff --git a/include/uapi/linux/vhost.h b/include/uapi/linux/vhost.h index 61a8777178c6..8cb0a65afd64 100644 --- a/include/uapi/linux/vhost.h +++ b/include/uapi/linux/vhost.h @@ -47,6 +47,32 @@ struct vhost_vring_addr { __u64 log_guest_addr; }; +/* no alignment requirement */ +struct vhost_iotlb_msg { + __u64 iova; + __u64 size; + __u64 uaddr; +#define VHOST_ACCESS_RO 0x1 +#define VHOST_ACCESS_WO 0x2 +#define VHOST_ACCESS_RW 0x3 + __u8 perm; +#define VHOST_IOTLB_MISS 1 +#define VHOST_IOTLB_UPDATE 2 +#define VHOST_IOTLB_INVALIDATE 3 +#define VHOST_IOTLB_ACCESS_FAIL 4 + __u8 type; +}; + +#define VHOST_IOTLB_MSG 0x1 + +struct vhost_msg { + int type; + union { + struct vhost_iotlb_msg iotlb; + __u8 padding[64]; + }; +}; + struct vhost_memory_region { __u64 guest_phys_addr; __u64 memory_size; /* bytes */ @@ -146,6 +172,8 @@ struct vhost_memory { #define VHOST_F_LOG_ALL 26 /* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */ #define VHOST_NET_F_VIRTIO_NET_HDR 27 +/* Vhost have device IOTLB */ +#define VHOST_F_DEVICE_IOTLB 63 /* VHOST_SCSI specific definitions */ -- cgit v1.2.3 From d279af442001d03b41af233e97549f4b23d403a0 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 23 Jun 2016 16:28:58 +0100 Subject: UPSTREAM: vsock: make listener child lock ordering explicit There are several places where the listener and pending or accept queue child sockets are accessed at the same time. Lockdep is unhappy that two locks from the same class are held. Tell lockdep that it is safe and document the lock ordering. Originally Claudio Imbrenda sent a similar patch asking whether this is safe. I have audited the code and also covered the vsock_pending_work() function. Suggested-by: Claudio Imbrenda Signed-off-by: Stefan Hajnoczi Signed-off-by: David S. Miller (cherry picked from commit 4192f672fae559f32d82de72a677701853cc98a7) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Cody Schuffelen Change-Id: I0cb7ee964057e9338971e1a2043ae17557feaec7 --- net/vmw_vsock/af_vsock.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 2cb12fe3b60d..611e3b13675e 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -61,6 +61,14 @@ * function will also cleanup rejected sockets, those that reach the connected * state but leave it before they have been accepted. * + * - Lock ordering for pending or accept queue sockets is: + * + * lock_sock(listener); + * lock_sock_nested(pending, SINGLE_DEPTH_NESTING); + * + * Using explicit nested locking keeps lockdep happy since normally only one + * lock of a given class may be taken at a time. + * * - Sockets created by user action will be cleaned up when the user process * calls close(2), causing our release implementation to be called. Our release * implementation will perform some cleanup then drop the last reference so our @@ -443,7 +451,7 @@ static void vsock_pending_work(struct work_struct *work) cleanup = true; lock_sock(listener); - lock_sock(sk); + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); if (vsock_is_pending(sk)) { vsock_remove_pending(listener, sk); @@ -1293,7 +1301,7 @@ static int vsock_accept(struct socket *sock, struct socket *newsock, int flags) if (connected) { listener->sk_ack_backlog--; - lock_sock(connected); + lock_sock_nested(connected, SINGLE_DEPTH_NESTING); vconnected = vsock_sk(connected); /* If the listener socket has received an error, then we should -- cgit v1.2.3 From bcb6d9e1950c8e2d301e0713bf25e29bcc70bf69 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 28 Jul 2016 15:36:30 +0100 Subject: UPSTREAM: VSOCK: transport-specific vsock_transport functions struct vsock_transport contains function pointers called by AF_VSOCK core code. The transport may want its own transport-specific function pointers and they can be added after struct vsock_transport. Allow the transport to fetch vsock_transport. It can downcast it to access transport-specific function pointers. The virtio transport will use this. Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin (cherry picked from commit 0b01aeb3d2fbf16787f0c9629f4ca52ae792f732) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Cody Schuffelen Change-Id: I442706ae71dc14c70fc4033d9719134c2d034509 --- include/net/af_vsock.h | 3 +++ net/vmw_vsock/af_vsock.c | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index f7a35fcaaaf6..2f987679239b 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -165,6 +165,9 @@ static inline int vsock_core_init(const struct vsock_transport *t) } void vsock_core_exit(void); +/* The transport may downcast this to access transport-specific functions */ +const struct vsock_transport *vsock_core_get_transport(void); + /**** UTILS ****/ void vsock_release_pending(struct sock *pending); diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 611e3b13675e..fa5bed6dcd30 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1991,6 +1991,15 @@ void vsock_core_exit(void) } EXPORT_SYMBOL_GPL(vsock_core_exit); +const struct vsock_transport *vsock_core_get_transport(void) +{ + /* vsock_register_mutex not taken since only the transport uses this + * function and only while registered. + */ + return transport; +} +EXPORT_SYMBOL_GPL(vsock_core_get_transport); + MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMware Virtual Socket Family"); MODULE_VERSION("1.0.1.0-k"); -- cgit v1.2.3 From f477c730c32ccb3fd1c8e29bb1520edfbb5f1bfb Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 28 Jul 2016 15:36:31 +0100 Subject: UPSTREAM: VSOCK: defer sock removal to transports The virtio transport will implement graceful shutdown and the related SO_LINGER socket option. This requires orphaning the sock but keeping it in the table of connections after .release(). This patch adds the vsock_remove_sock() function and leaves it up to the transport when to remove the sock. Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin (cherry picked from commit 6773b7dc39f165bd9d824b50ac52cbb3f87d53c8) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Cody Schuffelen Change-Id: I889cdbc0b1de8d2ff54a70ab7a6b4623edb3de06 --- include/net/af_vsock.h | 1 + net/vmw_vsock/af_vsock.c | 16 ++++++++++------ net/vmw_vsock/vmci_transport.c | 2 ++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index 2f987679239b..d8a1a41d5f8f 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -180,6 +180,7 @@ void vsock_remove_connected(struct vsock_sock *vsk); struct sock *vsock_find_bound_socket(struct sockaddr_vm *addr); struct sock *vsock_find_connected_socket(struct sockaddr_vm *src, struct sockaddr_vm *dst); +void vsock_remove_sock(struct vsock_sock *vsk); void vsock_for_each_connected_socket(void (*fn)(struct sock *sk)); #endif /* __AF_VSOCK_H__ */ diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index fa5bed6dcd30..db7c6615371b 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -344,6 +344,16 @@ static bool vsock_in_connected_table(struct vsock_sock *vsk) return ret; } +void vsock_remove_sock(struct vsock_sock *vsk) +{ + if (vsock_in_bound_table(vsk)) + vsock_remove_bound(vsk); + + if (vsock_in_connected_table(vsk)) + vsock_remove_connected(vsk); +} +EXPORT_SYMBOL_GPL(vsock_remove_sock); + void vsock_for_each_connected_socket(void (*fn)(struct sock *sk)) { int i; @@ -663,12 +673,6 @@ static void __vsock_release(struct sock *sk) vsk = vsock_sk(sk); pending = NULL; /* Compiler warning. */ - if (vsock_in_bound_table(vsk)) - vsock_remove_bound(vsk); - - if (vsock_in_connected_table(vsk)) - vsock_remove_connected(vsk); - transport->release(vsk); lock_sock(sk); diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c index f3fc34f7a77e..102bf9194662 100644 --- a/net/vmw_vsock/vmci_transport.c +++ b/net/vmw_vsock/vmci_transport.c @@ -1680,6 +1680,8 @@ static void vmci_transport_destruct(struct vsock_sock *vsk) static void vmci_transport_release(struct vsock_sock *vsk) { + vsock_remove_sock(vsk); + if (!vmci_handle_is_invalid(vmci_trans(vsk)->dg_handle)) { vmci_datagram_destroy_handle(vmci_trans(vsk)->dg_handle); vmci_trans(vsk)->dg_handle = VMCI_INVALID_HANDLE; -- cgit v1.2.3 From 801941dfcc5138548defb3dd82c1747bd0ad14f3 Mon Sep 17 00:00:00 2001 From: Asias He Date: Thu, 28 Jul 2016 15:36:32 +0100 Subject: BACKPORT: VSOCK: Introduce virtio_vsock_common.ko This module contains the common code and header files for the following virtio_transporto and vhost_vsock kernel modules. Signed-off-by: Asias He Signed-off-by: Claudio Imbrenda Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin (cherry picked from commit 06a8fc78367d070720af960dcecec917d3ae5f3b) [astrachan: Backported around stable backport 62209d1 ("vsock: split dwork to avoid reinitializations")] Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Cody Schuffelen Change-Id: I723c073db804663ad4bf83b657c72b16cbdb220a --- MAINTAINERS | 10 + include/linux/virtio_vsock.h | 154 ++++ include/net/af_vsock.h | 2 + .../trace/events/vsock_virtio_transport_common.h | 144 +++ include/uapi/linux/Kbuild | 1 + include/uapi/linux/virtio_ids.h | 1 + include/uapi/linux/virtio_vsock.h | 94 ++ net/vmw_vsock/virtio_transport_common.c | 992 +++++++++++++++++++++ 8 files changed, 1398 insertions(+) create mode 100644 include/linux/virtio_vsock.h create mode 100644 include/trace/events/vsock_virtio_transport_common.h create mode 100644 include/uapi/linux/virtio_vsock.h create mode 100644 net/vmw_vsock/virtio_transport_common.c diff --git a/MAINTAINERS b/MAINTAINERS index 3d9edebb58a9..6f23bb412b98 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11448,6 +11448,16 @@ S: Maintained F: drivers/media/v4l2-core/videobuf2-* F: include/media/videobuf2-* +VIRTIO AND VHOST VSOCK DRIVER +M: Stefan Hajnoczi +L: kvm@vger.kernel.org +L: virtualization@lists.linux-foundation.org +L: netdev@vger.kernel.org +S: Maintained +F: include/linux/virtio_vsock.h +F: include/uapi/linux/virtio_vsock.h +F: net/vmw_vsock/virtio_transport_common.c + VIRTUAL SERIO DEVICE DRIVER M: Stephen Chandler Paul S: Maintained diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h new file mode 100644 index 000000000000..9638bfeb0d1f --- /dev/null +++ b/include/linux/virtio_vsock.h @@ -0,0 +1,154 @@ +#ifndef _LINUX_VIRTIO_VSOCK_H +#define _LINUX_VIRTIO_VSOCK_H + +#include +#include +#include +#include + +#define VIRTIO_VSOCK_DEFAULT_MIN_BUF_SIZE 128 +#define VIRTIO_VSOCK_DEFAULT_BUF_SIZE (1024 * 256) +#define VIRTIO_VSOCK_DEFAULT_MAX_BUF_SIZE (1024 * 256) +#define VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE (1024 * 4) +#define VIRTIO_VSOCK_MAX_BUF_SIZE 0xFFFFFFFFUL +#define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE (1024 * 64) + +enum { + VSOCK_VQ_RX = 0, /* for host to guest data */ + VSOCK_VQ_TX = 1, /* for guest to host data */ + VSOCK_VQ_EVENT = 2, + VSOCK_VQ_MAX = 3, +}; + +/* Per-socket state (accessed via vsk->trans) */ +struct virtio_vsock_sock { + struct vsock_sock *vsk; + + /* Protected by lock_sock(sk_vsock(trans->vsk)) */ + u32 buf_size; + u32 buf_size_min; + u32 buf_size_max; + + spinlock_t tx_lock; + spinlock_t rx_lock; + + /* Protected by tx_lock */ + u32 tx_cnt; + u32 buf_alloc; + u32 peer_fwd_cnt; + u32 peer_buf_alloc; + + /* Protected by rx_lock */ + u32 fwd_cnt; + u32 rx_bytes; + struct list_head rx_queue; +}; + +struct virtio_vsock_pkt { + struct virtio_vsock_hdr hdr; + struct work_struct work; + struct list_head list; + void *buf; + u32 len; + u32 off; + bool reply; +}; + +struct virtio_vsock_pkt_info { + u32 remote_cid, remote_port; + struct msghdr *msg; + u32 pkt_len; + u16 type; + u16 op; + u32 flags; + bool reply; +}; + +struct virtio_transport { + /* This must be the first field */ + struct vsock_transport transport; + + /* Takes ownership of the packet */ + int (*send_pkt)(struct virtio_vsock_pkt *pkt); +}; + +ssize_t +virtio_transport_stream_dequeue(struct vsock_sock *vsk, + struct msghdr *msg, + size_t len, + int type); +int +virtio_transport_dgram_dequeue(struct vsock_sock *vsk, + struct msghdr *msg, + size_t len, int flags); + +s64 virtio_transport_stream_has_data(struct vsock_sock *vsk); +s64 virtio_transport_stream_has_space(struct vsock_sock *vsk); + +int virtio_transport_do_socket_init(struct vsock_sock *vsk, + struct vsock_sock *psk); +u64 virtio_transport_get_buffer_size(struct vsock_sock *vsk); +u64 virtio_transport_get_min_buffer_size(struct vsock_sock *vsk); +u64 virtio_transport_get_max_buffer_size(struct vsock_sock *vsk); +void virtio_transport_set_buffer_size(struct vsock_sock *vsk, u64 val); +void virtio_transport_set_min_buffer_size(struct vsock_sock *vsk, u64 val); +void virtio_transport_set_max_buffer_size(struct vsock_sock *vs, u64 val); +int +virtio_transport_notify_poll_in(struct vsock_sock *vsk, + size_t target, + bool *data_ready_now); +int +virtio_transport_notify_poll_out(struct vsock_sock *vsk, + size_t target, + bool *space_available_now); + +int virtio_transport_notify_recv_init(struct vsock_sock *vsk, + size_t target, struct vsock_transport_recv_notify_data *data); +int virtio_transport_notify_recv_pre_block(struct vsock_sock *vsk, + size_t target, struct vsock_transport_recv_notify_data *data); +int virtio_transport_notify_recv_pre_dequeue(struct vsock_sock *vsk, + size_t target, struct vsock_transport_recv_notify_data *data); +int virtio_transport_notify_recv_post_dequeue(struct vsock_sock *vsk, + size_t target, ssize_t copied, bool data_read, + struct vsock_transport_recv_notify_data *data); +int virtio_transport_notify_send_init(struct vsock_sock *vsk, + struct vsock_transport_send_notify_data *data); +int virtio_transport_notify_send_pre_block(struct vsock_sock *vsk, + struct vsock_transport_send_notify_data *data); +int virtio_transport_notify_send_pre_enqueue(struct vsock_sock *vsk, + struct vsock_transport_send_notify_data *data); +int virtio_transport_notify_send_post_enqueue(struct vsock_sock *vsk, + ssize_t written, struct vsock_transport_send_notify_data *data); + +u64 virtio_transport_stream_rcvhiwat(struct vsock_sock *vsk); +bool virtio_transport_stream_is_active(struct vsock_sock *vsk); +bool virtio_transport_stream_allow(u32 cid, u32 port); +int virtio_transport_dgram_bind(struct vsock_sock *vsk, + struct sockaddr_vm *addr); +bool virtio_transport_dgram_allow(u32 cid, u32 port); + +int virtio_transport_connect(struct vsock_sock *vsk); + +int virtio_transport_shutdown(struct vsock_sock *vsk, int mode); + +void virtio_transport_release(struct vsock_sock *vsk); + +ssize_t +virtio_transport_stream_enqueue(struct vsock_sock *vsk, + struct msghdr *msg, + size_t len); +int +virtio_transport_dgram_enqueue(struct vsock_sock *vsk, + struct sockaddr_vm *remote_addr, + struct msghdr *msg, + size_t len); + +void virtio_transport_destruct(struct vsock_sock *vsk); + +void virtio_transport_recv_pkt(struct virtio_vsock_pkt *pkt); +void virtio_transport_free_pkt(struct virtio_vsock_pkt *pkt); +void virtio_transport_inc_tx_pkt(struct virtio_vsock_sock *vvs, struct virtio_vsock_pkt *pkt); +u32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 wanted); +void virtio_transport_put_credit(struct virtio_vsock_sock *vvs, u32 credit); + +#endif /* _LINUX_VIRTIO_VSOCK_H */ diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index d8a1a41d5f8f..e6675f79b925 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -64,6 +64,8 @@ struct vsock_sock { bool rejected; struct delayed_work connect_work; struct delayed_work pending_work; + struct delayed_work close_work; + bool close_work_scheduled; u32 peer_shutdown; bool sent_request; bool ignore_connecting_rst; diff --git a/include/trace/events/vsock_virtio_transport_common.h b/include/trace/events/vsock_virtio_transport_common.h new file mode 100644 index 000000000000..b7f1d6278280 --- /dev/null +++ b/include/trace/events/vsock_virtio_transport_common.h @@ -0,0 +1,144 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM vsock + +#if !defined(_TRACE_VSOCK_VIRTIO_TRANSPORT_COMMON_H) || \ + defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_VSOCK_VIRTIO_TRANSPORT_COMMON_H + +#include + +TRACE_DEFINE_ENUM(VIRTIO_VSOCK_TYPE_STREAM); + +#define show_type(val) \ + __print_symbolic(val, { VIRTIO_VSOCK_TYPE_STREAM, "STREAM" }) + +TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_INVALID); +TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_REQUEST); +TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_RESPONSE); +TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_RST); +TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_SHUTDOWN); +TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_RW); +TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_CREDIT_UPDATE); +TRACE_DEFINE_ENUM(VIRTIO_VSOCK_OP_CREDIT_REQUEST); + +#define show_op(val) \ + __print_symbolic(val, \ + { VIRTIO_VSOCK_OP_INVALID, "INVALID" }, \ + { VIRTIO_VSOCK_OP_REQUEST, "REQUEST" }, \ + { VIRTIO_VSOCK_OP_RESPONSE, "RESPONSE" }, \ + { VIRTIO_VSOCK_OP_RST, "RST" }, \ + { VIRTIO_VSOCK_OP_SHUTDOWN, "SHUTDOWN" }, \ + { VIRTIO_VSOCK_OP_RW, "RW" }, \ + { VIRTIO_VSOCK_OP_CREDIT_UPDATE, "CREDIT_UPDATE" }, \ + { VIRTIO_VSOCK_OP_CREDIT_REQUEST, "CREDIT_REQUEST" }) + +TRACE_EVENT(virtio_transport_alloc_pkt, + TP_PROTO( + __u32 src_cid, __u32 src_port, + __u32 dst_cid, __u32 dst_port, + __u32 len, + __u16 type, + __u16 op, + __u32 flags + ), + TP_ARGS( + src_cid, src_port, + dst_cid, dst_port, + len, + type, + op, + flags + ), + TP_STRUCT__entry( + __field(__u32, src_cid) + __field(__u32, src_port) + __field(__u32, dst_cid) + __field(__u32, dst_port) + __field(__u32, len) + __field(__u16, type) + __field(__u16, op) + __field(__u32, flags) + ), + TP_fast_assign( + __entry->src_cid = src_cid; + __entry->src_port = src_port; + __entry->dst_cid = dst_cid; + __entry->dst_port = dst_port; + __entry->len = len; + __entry->type = type; + __entry->op = op; + __entry->flags = flags; + ), + TP_printk("%u:%u -> %u:%u len=%u type=%s op=%s flags=%#x", + __entry->src_cid, __entry->src_port, + __entry->dst_cid, __entry->dst_port, + __entry->len, + show_type(__entry->type), + show_op(__entry->op), + __entry->flags) +); + +TRACE_EVENT(virtio_transport_recv_pkt, + TP_PROTO( + __u32 src_cid, __u32 src_port, + __u32 dst_cid, __u32 dst_port, + __u32 len, + __u16 type, + __u16 op, + __u32 flags, + __u32 buf_alloc, + __u32 fwd_cnt + ), + TP_ARGS( + src_cid, src_port, + dst_cid, dst_port, + len, + type, + op, + flags, + buf_alloc, + fwd_cnt + ), + TP_STRUCT__entry( + __field(__u32, src_cid) + __field(__u32, src_port) + __field(__u32, dst_cid) + __field(__u32, dst_port) + __field(__u32, len) + __field(__u16, type) + __field(__u16, op) + __field(__u32, flags) + __field(__u32, buf_alloc) + __field(__u32, fwd_cnt) + ), + TP_fast_assign( + __entry->src_cid = src_cid; + __entry->src_port = src_port; + __entry->dst_cid = dst_cid; + __entry->dst_port = dst_port; + __entry->len = len; + __entry->type = type; + __entry->op = op; + __entry->flags = flags; + __entry->buf_alloc = buf_alloc; + __entry->fwd_cnt = fwd_cnt; + ), + TP_printk("%u:%u -> %u:%u len=%u type=%s op=%s flags=%#x " + "buf_alloc=%u fwd_cnt=%u", + __entry->src_cid, __entry->src_port, + __entry->dst_cid, __entry->dst_port, + __entry->len, + show_type(__entry->type), + show_op(__entry->op), + __entry->flags, + __entry->buf_alloc, + __entry->fwd_cnt) +); + +#endif /* _TRACE_VSOCK_VIRTIO_TRANSPORT_COMMON_H */ + +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE vsock_virtio_transport_common + +/* This part must be outside protection */ +#include diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index ebd10e624598..6c51a4d8bb62 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -447,6 +447,7 @@ header-y += virtio_ring.h header-y += virtio_rng.h header-y += virtio_scsi.h header-y += virtio_types.h +header-y += virtio_vsock.h header-y += vm_sockets.h header-y += vt.h header-y += wait.h diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h index 77925f587b15..3228d582234a 100644 --- a/include/uapi/linux/virtio_ids.h +++ b/include/uapi/linux/virtio_ids.h @@ -41,5 +41,6 @@ #define VIRTIO_ID_CAIF 12 /* Virtio caif */ #define VIRTIO_ID_GPU 16 /* virtio GPU */ #define VIRTIO_ID_INPUT 18 /* virtio input */ +#define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ #endif /* _LINUX_VIRTIO_IDS_H */ diff --git a/include/uapi/linux/virtio_vsock.h b/include/uapi/linux/virtio_vsock.h new file mode 100644 index 000000000000..6b011c19b50f --- /dev/null +++ b/include/uapi/linux/virtio_vsock.h @@ -0,0 +1,94 @@ +/* + * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so + * anyone can use the definitions to implement compatible drivers/servers: + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of IBM nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (C) Red Hat, Inc., 2013-2015 + * Copyright (C) Asias He , 2013 + * Copyright (C) Stefan Hajnoczi , 2015 + */ + +#ifndef _UAPI_LINUX_VIRTIO_VSOCK_H +#define _UAPI_LINUX_VIRTIO_VOSCK_H + +#include +#include +#include + +struct virtio_vsock_config { + __le64 guest_cid; +} __attribute__((packed)); + +enum virtio_vsock_event_id { + VIRTIO_VSOCK_EVENT_TRANSPORT_RESET = 0, +}; + +struct virtio_vsock_event { + __le32 id; +} __attribute__((packed)); + +struct virtio_vsock_hdr { + __le64 src_cid; + __le64 dst_cid; + __le32 src_port; + __le32 dst_port; + __le32 len; + __le16 type; /* enum virtio_vsock_type */ + __le16 op; /* enum virtio_vsock_op */ + __le32 flags; + __le32 buf_alloc; + __le32 fwd_cnt; +} __attribute__((packed)); + +enum virtio_vsock_type { + VIRTIO_VSOCK_TYPE_STREAM = 1, +}; + +enum virtio_vsock_op { + VIRTIO_VSOCK_OP_INVALID = 0, + + /* Connect operations */ + VIRTIO_VSOCK_OP_REQUEST = 1, + VIRTIO_VSOCK_OP_RESPONSE = 2, + VIRTIO_VSOCK_OP_RST = 3, + VIRTIO_VSOCK_OP_SHUTDOWN = 4, + + /* To send payload */ + VIRTIO_VSOCK_OP_RW = 5, + + /* Tell the peer our credit info */ + VIRTIO_VSOCK_OP_CREDIT_UPDATE = 6, + /* Request the peer to send the credit info to us */ + VIRTIO_VSOCK_OP_CREDIT_REQUEST = 7, +}; + +/* VIRTIO_VSOCK_OP_SHUTDOWN flags values */ +enum virtio_vsock_shutdown { + VIRTIO_VSOCK_SHUTDOWN_RCV = 1, + VIRTIO_VSOCK_SHUTDOWN_SEND = 2, +}; + +#endif /* _UAPI_LINUX_VIRTIO_VSOCK_H */ diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c new file mode 100644 index 000000000000..a53b3a16b4f1 --- /dev/null +++ b/net/vmw_vsock/virtio_transport_common.c @@ -0,0 +1,992 @@ +/* + * common code for virtio vsock + * + * Copyright (C) 2013-2015 Red Hat, Inc. + * Author: Asias He + * Stefan Hajnoczi + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define CREATE_TRACE_POINTS +#include + +/* How long to wait for graceful shutdown of a connection */ +#define VSOCK_CLOSE_TIMEOUT (8 * HZ) + +static const struct virtio_transport *virtio_transport_get_ops(void) +{ + const struct vsock_transport *t = vsock_core_get_transport(); + + return container_of(t, struct virtio_transport, transport); +} + +struct virtio_vsock_pkt * +virtio_transport_alloc_pkt(struct virtio_vsock_pkt_info *info, + size_t len, + u32 src_cid, + u32 src_port, + u32 dst_cid, + u32 dst_port) +{ + struct virtio_vsock_pkt *pkt; + int err; + + pkt = kzalloc(sizeof(*pkt), GFP_KERNEL); + if (!pkt) + return NULL; + + pkt->hdr.type = cpu_to_le16(info->type); + pkt->hdr.op = cpu_to_le16(info->op); + pkt->hdr.src_cid = cpu_to_le64(src_cid); + pkt->hdr.dst_cid = cpu_to_le64(dst_cid); + pkt->hdr.src_port = cpu_to_le32(src_port); + pkt->hdr.dst_port = cpu_to_le32(dst_port); + pkt->hdr.flags = cpu_to_le32(info->flags); + pkt->len = len; + pkt->hdr.len = cpu_to_le32(len); + pkt->reply = info->reply; + + if (info->msg && len > 0) { + pkt->buf = kmalloc(len, GFP_KERNEL); + if (!pkt->buf) + goto out_pkt; + err = memcpy_from_msg(pkt->buf, info->msg, len); + if (err) + goto out; + } + + trace_virtio_transport_alloc_pkt(src_cid, src_port, + dst_cid, dst_port, + len, + info->type, + info->op, + info->flags); + + return pkt; + +out: + kfree(pkt->buf); +out_pkt: + kfree(pkt); + return NULL; +} +EXPORT_SYMBOL_GPL(virtio_transport_alloc_pkt); + +static int virtio_transport_send_pkt_info(struct vsock_sock *vsk, + struct virtio_vsock_pkt_info *info) +{ + u32 src_cid, src_port, dst_cid, dst_port; + struct virtio_vsock_sock *vvs; + struct virtio_vsock_pkt *pkt; + u32 pkt_len = info->pkt_len; + + src_cid = vm_sockets_get_local_cid(); + src_port = vsk->local_addr.svm_port; + if (!info->remote_cid) { + dst_cid = vsk->remote_addr.svm_cid; + dst_port = vsk->remote_addr.svm_port; + } else { + dst_cid = info->remote_cid; + dst_port = info->remote_port; + } + + vvs = vsk->trans; + + /* we can send less than pkt_len bytes */ + if (pkt_len > VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE) + pkt_len = VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE; + + /* virtio_transport_get_credit might return less than pkt_len credit */ + pkt_len = virtio_transport_get_credit(vvs, pkt_len); + + /* Do not send zero length OP_RW pkt */ + if (pkt_len == 0 && info->op == VIRTIO_VSOCK_OP_RW) + return pkt_len; + + pkt = virtio_transport_alloc_pkt(info, pkt_len, + src_cid, src_port, + dst_cid, dst_port); + if (!pkt) { + virtio_transport_put_credit(vvs, pkt_len); + return -ENOMEM; + } + + virtio_transport_inc_tx_pkt(vvs, pkt); + + return virtio_transport_get_ops()->send_pkt(pkt); +} + +static void virtio_transport_inc_rx_pkt(struct virtio_vsock_sock *vvs, + struct virtio_vsock_pkt *pkt) +{ + vvs->rx_bytes += pkt->len; +} + +static void virtio_transport_dec_rx_pkt(struct virtio_vsock_sock *vvs, + struct virtio_vsock_pkt *pkt) +{ + vvs->rx_bytes -= pkt->len; + vvs->fwd_cnt += pkt->len; +} + +void virtio_transport_inc_tx_pkt(struct virtio_vsock_sock *vvs, struct virtio_vsock_pkt *pkt) +{ + spin_lock_bh(&vvs->tx_lock); + pkt->hdr.fwd_cnt = cpu_to_le32(vvs->fwd_cnt); + pkt->hdr.buf_alloc = cpu_to_le32(vvs->buf_alloc); + spin_unlock_bh(&vvs->tx_lock); +} +EXPORT_SYMBOL_GPL(virtio_transport_inc_tx_pkt); + +u32 virtio_transport_get_credit(struct virtio_vsock_sock *vvs, u32 credit) +{ + u32 ret; + + spin_lock_bh(&vvs->tx_lock); + ret = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt); + if (ret > credit) + ret = credit; + vvs->tx_cnt += ret; + spin_unlock_bh(&vvs->tx_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(virtio_transport_get_credit); + +void virtio_transport_put_credit(struct virtio_vsock_sock *vvs, u32 credit) +{ + spin_lock_bh(&vvs->tx_lock); + vvs->tx_cnt -= credit; + spin_unlock_bh(&vvs->tx_lock); +} +EXPORT_SYMBOL_GPL(virtio_transport_put_credit); + +static int virtio_transport_send_credit_update(struct vsock_sock *vsk, + int type, + struct virtio_vsock_hdr *hdr) +{ + struct virtio_vsock_pkt_info info = { + .op = VIRTIO_VSOCK_OP_CREDIT_UPDATE, + .type = type, + }; + + return virtio_transport_send_pkt_info(vsk, &info); +} + +static ssize_t +virtio_transport_stream_do_dequeue(struct vsock_sock *vsk, + struct msghdr *msg, + size_t len) +{ + struct virtio_vsock_sock *vvs = vsk->trans; + struct virtio_vsock_pkt *pkt; + size_t bytes, total = 0; + int err = -EFAULT; + + spin_lock_bh(&vvs->rx_lock); + while (total < len && !list_empty(&vvs->rx_queue)) { + pkt = list_first_entry(&vvs->rx_queue, + struct virtio_vsock_pkt, list); + + bytes = len - total; + if (bytes > pkt->len - pkt->off) + bytes = pkt->len - pkt->off; + + /* sk_lock is held by caller so no one else can dequeue. + * Unlock rx_lock since memcpy_to_msg() may sleep. + */ + spin_unlock_bh(&vvs->rx_lock); + + err = memcpy_to_msg(msg, pkt->buf + pkt->off, bytes); + if (err) + goto out; + + spin_lock_bh(&vvs->rx_lock); + + total += bytes; + pkt->off += bytes; + if (pkt->off == pkt->len) { + virtio_transport_dec_rx_pkt(vvs, pkt); + list_del(&pkt->list); + virtio_transport_free_pkt(pkt); + } + } + spin_unlock_bh(&vvs->rx_lock); + + /* Send a credit pkt to peer */ + virtio_transport_send_credit_update(vsk, VIRTIO_VSOCK_TYPE_STREAM, + NULL); + + return total; + +out: + if (total) + err = total; + return err; +} + +ssize_t +virtio_transport_stream_dequeue(struct vsock_sock *vsk, + struct msghdr *msg, + size_t len, int flags) +{ + if (flags & MSG_PEEK) + return -EOPNOTSUPP; + + return virtio_transport_stream_do_dequeue(vsk, msg, len); +} +EXPORT_SYMBOL_GPL(virtio_transport_stream_dequeue); + +int +virtio_transport_dgram_dequeue(struct vsock_sock *vsk, + struct msghdr *msg, + size_t len, int flags) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL_GPL(virtio_transport_dgram_dequeue); + +s64 virtio_transport_stream_has_data(struct vsock_sock *vsk) +{ + struct virtio_vsock_sock *vvs = vsk->trans; + s64 bytes; + + spin_lock_bh(&vvs->rx_lock); + bytes = vvs->rx_bytes; + spin_unlock_bh(&vvs->rx_lock); + + return bytes; +} +EXPORT_SYMBOL_GPL(virtio_transport_stream_has_data); + +static s64 virtio_transport_has_space(struct vsock_sock *vsk) +{ + struct virtio_vsock_sock *vvs = vsk->trans; + s64 bytes; + + bytes = vvs->peer_buf_alloc - (vvs->tx_cnt - vvs->peer_fwd_cnt); + if (bytes < 0) + bytes = 0; + + return bytes; +} + +s64 virtio_transport_stream_has_space(struct vsock_sock *vsk) +{ + struct virtio_vsock_sock *vvs = vsk->trans; + s64 bytes; + + spin_lock_bh(&vvs->tx_lock); + bytes = virtio_transport_has_space(vsk); + spin_unlock_bh(&vvs->tx_lock); + + return bytes; +} +EXPORT_SYMBOL_GPL(virtio_transport_stream_has_space); + +int virtio_transport_do_socket_init(struct vsock_sock *vsk, + struct vsock_sock *psk) +{ + struct virtio_vsock_sock *vvs; + + vvs = kzalloc(sizeof(*vvs), GFP_KERNEL); + if (!vvs) + return -ENOMEM; + + vsk->trans = vvs; + vvs->vsk = vsk; + if (psk) { + struct virtio_vsock_sock *ptrans = psk->trans; + + vvs->buf_size = ptrans->buf_size; + vvs->buf_size_min = ptrans->buf_size_min; + vvs->buf_size_max = ptrans->buf_size_max; + vvs->peer_buf_alloc = ptrans->peer_buf_alloc; + } else { + vvs->buf_size = VIRTIO_VSOCK_DEFAULT_BUF_SIZE; + vvs->buf_size_min = VIRTIO_VSOCK_DEFAULT_MIN_BUF_SIZE; + vvs->buf_size_max = VIRTIO_VSOCK_DEFAULT_MAX_BUF_SIZE; + } + + vvs->buf_alloc = vvs->buf_size; + + spin_lock_init(&vvs->rx_lock); + spin_lock_init(&vvs->tx_lock); + INIT_LIST_HEAD(&vvs->rx_queue); + + return 0; +} +EXPORT_SYMBOL_GPL(virtio_transport_do_socket_init); + +u64 virtio_transport_get_buffer_size(struct vsock_sock *vsk) +{ + struct virtio_vsock_sock *vvs = vsk->trans; + + return vvs->buf_size; +} +EXPORT_SYMBOL_GPL(virtio_transport_get_buffer_size); + +u64 virtio_transport_get_min_buffer_size(struct vsock_sock *vsk) +{ + struct virtio_vsock_sock *vvs = vsk->trans; + + return vvs->buf_size_min; +} +EXPORT_SYMBOL_GPL(virtio_transport_get_min_buffer_size); + +u64 virtio_transport_get_max_buffer_size(struct vsock_sock *vsk) +{ + struct virtio_vsock_sock *vvs = vsk->trans; + + return vvs->buf_size_max; +} +EXPORT_SYMBOL_GPL(virtio_transport_get_max_buffer_size); + +void virtio_transport_set_buffer_size(struct vsock_sock *vsk, u64 val) +{ + struct virtio_vsock_sock *vvs = vsk->trans; + + if (val > VIRTIO_VSOCK_MAX_BUF_SIZE) + val = VIRTIO_VSOCK_MAX_BUF_SIZE; + if (val < vvs->buf_size_min) + vvs->buf_size_min = val; + if (val > vvs->buf_size_max) + vvs->buf_size_max = val; + vvs->buf_size = val; + vvs->buf_alloc = val; +} +EXPORT_SYMBOL_GPL(virtio_transport_set_buffer_size); + +void virtio_transport_set_min_buffer_size(struct vsock_sock *vsk, u64 val) +{ + struct virtio_vsock_sock *vvs = vsk->trans; + + if (val > VIRTIO_VSOCK_MAX_BUF_SIZE) + val = VIRTIO_VSOCK_MAX_BUF_SIZE; + if (val > vvs->buf_size) + vvs->buf_size = val; + vvs->buf_size_min = val; +} +EXPORT_SYMBOL_GPL(virtio_transport_set_min_buffer_size); + +void virtio_transport_set_max_buffer_size(struct vsock_sock *vsk, u64 val) +{ + struct virtio_vsock_sock *vvs = vsk->trans; + + if (val > VIRTIO_VSOCK_MAX_BUF_SIZE) + val = VIRTIO_VSOCK_MAX_BUF_SIZE; + if (val < vvs->buf_size) + vvs->buf_size = val; + vvs->buf_size_max = val; +} +EXPORT_SYMBOL_GPL(virtio_transport_set_max_buffer_size); + +int +virtio_transport_notify_poll_in(struct vsock_sock *vsk, + size_t target, + bool *data_ready_now) +{ + if (vsock_stream_has_data(vsk)) + *data_ready_now = true; + else + *data_ready_now = false; + + return 0; +} +EXPORT_SYMBOL_GPL(virtio_transport_notify_poll_in); + +int +virtio_transport_notify_poll_out(struct vsock_sock *vsk, + size_t target, + bool *space_avail_now) +{ + s64 free_space; + + free_space = vsock_stream_has_space(vsk); + if (free_space > 0) + *space_avail_now = true; + else if (free_space == 0) + *space_avail_now = false; + + return 0; +} +EXPORT_SYMBOL_GPL(virtio_transport_notify_poll_out); + +int virtio_transport_notify_recv_init(struct vsock_sock *vsk, + size_t target, struct vsock_transport_recv_notify_data *data) +{ + return 0; +} +EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_init); + +int virtio_transport_notify_recv_pre_block(struct vsock_sock *vsk, + size_t target, struct vsock_transport_recv_notify_data *data) +{ + return 0; +} +EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_pre_block); + +int virtio_transport_notify_recv_pre_dequeue(struct vsock_sock *vsk, + size_t target, struct vsock_transport_recv_notify_data *data) +{ + return 0; +} +EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_pre_dequeue); + +int virtio_transport_notify_recv_post_dequeue(struct vsock_sock *vsk, + size_t target, ssize_t copied, bool data_read, + struct vsock_transport_recv_notify_data *data) +{ + return 0; +} +EXPORT_SYMBOL_GPL(virtio_transport_notify_recv_post_dequeue); + +int virtio_transport_notify_send_init(struct vsock_sock *vsk, + struct vsock_transport_send_notify_data *data) +{ + return 0; +} +EXPORT_SYMBOL_GPL(virtio_transport_notify_send_init); + +int virtio_transport_notify_send_pre_block(struct vsock_sock *vsk, + struct vsock_transport_send_notify_data *data) +{ + return 0; +} +EXPORT_SYMBOL_GPL(virtio_transport_notify_send_pre_block); + +int virtio_transport_notify_send_pre_enqueue(struct vsock_sock *vsk, + struct vsock_transport_send_notify_data *data) +{ + return 0; +} +EXPORT_SYMBOL_GPL(virtio_transport_notify_send_pre_enqueue); + +int virtio_transport_notify_send_post_enqueue(struct vsock_sock *vsk, + ssize_t written, struct vsock_transport_send_notify_data *data) +{ + return 0; +} +EXPORT_SYMBOL_GPL(virtio_transport_notify_send_post_enqueue); + +u64 virtio_transport_stream_rcvhiwat(struct vsock_sock *vsk) +{ + struct virtio_vsock_sock *vvs = vsk->trans; + + return vvs->buf_size; +} +EXPORT_SYMBOL_GPL(virtio_transport_stream_rcvhiwat); + +bool virtio_transport_stream_is_active(struct vsock_sock *vsk) +{ + return true; +} +EXPORT_SYMBOL_GPL(virtio_transport_stream_is_active); + +bool virtio_transport_stream_allow(u32 cid, u32 port) +{ + return true; +} +EXPORT_SYMBOL_GPL(virtio_transport_stream_allow); + +int virtio_transport_dgram_bind(struct vsock_sock *vsk, + struct sockaddr_vm *addr) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL_GPL(virtio_transport_dgram_bind); + +bool virtio_transport_dgram_allow(u32 cid, u32 port) +{ + return false; +} +EXPORT_SYMBOL_GPL(virtio_transport_dgram_allow); + +int virtio_transport_connect(struct vsock_sock *vsk) +{ + struct virtio_vsock_pkt_info info = { + .op = VIRTIO_VSOCK_OP_REQUEST, + .type = VIRTIO_VSOCK_TYPE_STREAM, + }; + + return virtio_transport_send_pkt_info(vsk, &info); +} +EXPORT_SYMBOL_GPL(virtio_transport_connect); + +int virtio_transport_shutdown(struct vsock_sock *vsk, int mode) +{ + struct virtio_vsock_pkt_info info = { + .op = VIRTIO_VSOCK_OP_SHUTDOWN, + .type = VIRTIO_VSOCK_TYPE_STREAM, + .flags = (mode & RCV_SHUTDOWN ? + VIRTIO_VSOCK_SHUTDOWN_RCV : 0) | + (mode & SEND_SHUTDOWN ? + VIRTIO_VSOCK_SHUTDOWN_SEND : 0), + }; + + return virtio_transport_send_pkt_info(vsk, &info); +} +EXPORT_SYMBOL_GPL(virtio_transport_shutdown); + +int +virtio_transport_dgram_enqueue(struct vsock_sock *vsk, + struct sockaddr_vm *remote_addr, + struct msghdr *msg, + size_t dgram_len) +{ + return -EOPNOTSUPP; +} +EXPORT_SYMBOL_GPL(virtio_transport_dgram_enqueue); + +ssize_t +virtio_transport_stream_enqueue(struct vsock_sock *vsk, + struct msghdr *msg, + size_t len) +{ + struct virtio_vsock_pkt_info info = { + .op = VIRTIO_VSOCK_OP_RW, + .type = VIRTIO_VSOCK_TYPE_STREAM, + .msg = msg, + .pkt_len = len, + }; + + return virtio_transport_send_pkt_info(vsk, &info); +} +EXPORT_SYMBOL_GPL(virtio_transport_stream_enqueue); + +void virtio_transport_destruct(struct vsock_sock *vsk) +{ + struct virtio_vsock_sock *vvs = vsk->trans; + + kfree(vvs); +} +EXPORT_SYMBOL_GPL(virtio_transport_destruct); + +static int virtio_transport_reset(struct vsock_sock *vsk, + struct virtio_vsock_pkt *pkt) +{ + struct virtio_vsock_pkt_info info = { + .op = VIRTIO_VSOCK_OP_RST, + .type = VIRTIO_VSOCK_TYPE_STREAM, + .reply = !!pkt, + }; + + /* Send RST only if the original pkt is not a RST pkt */ + if (pkt && le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST) + return 0; + + return virtio_transport_send_pkt_info(vsk, &info); +} + +/* Normally packets are associated with a socket. There may be no socket if an + * attempt was made to connect to a socket that does not exist. + */ +static int virtio_transport_reset_no_sock(struct virtio_vsock_pkt *pkt) +{ + struct virtio_vsock_pkt_info info = { + .op = VIRTIO_VSOCK_OP_RST, + .type = le16_to_cpu(pkt->hdr.type), + .reply = true, + }; + + /* Send RST only if the original pkt is not a RST pkt */ + if (le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST) + return 0; + + pkt = virtio_transport_alloc_pkt(&info, 0, + le32_to_cpu(pkt->hdr.dst_cid), + le32_to_cpu(pkt->hdr.dst_port), + le32_to_cpu(pkt->hdr.src_cid), + le32_to_cpu(pkt->hdr.src_port)); + if (!pkt) + return -ENOMEM; + + return virtio_transport_get_ops()->send_pkt(pkt); +} + +static void virtio_transport_wait_close(struct sock *sk, long timeout) +{ + if (timeout) { + DEFINE_WAIT(wait); + + do { + prepare_to_wait(sk_sleep(sk), &wait, + TASK_INTERRUPTIBLE); + if (sk_wait_event(sk, &timeout, + sock_flag(sk, SOCK_DONE))) + break; + } while (!signal_pending(current) && timeout); + + finish_wait(sk_sleep(sk), &wait); + } +} + +static void virtio_transport_do_close(struct vsock_sock *vsk, + bool cancel_timeout) +{ + struct sock *sk = sk_vsock(vsk); + + sock_set_flag(sk, SOCK_DONE); + vsk->peer_shutdown = SHUTDOWN_MASK; + if (vsock_stream_has_data(vsk) <= 0) + sk->sk_state = SS_DISCONNECTING; + sk->sk_state_change(sk); + + if (vsk->close_work_scheduled && + (!cancel_timeout || cancel_delayed_work(&vsk->close_work))) { + vsk->close_work_scheduled = false; + + vsock_remove_sock(vsk); + + /* Release refcnt obtained when we scheduled the timeout */ + sock_put(sk); + } +} + +static void virtio_transport_close_timeout(struct work_struct *work) +{ + struct vsock_sock *vsk = + container_of(work, struct vsock_sock, close_work.work); + struct sock *sk = sk_vsock(vsk); + + sock_hold(sk); + lock_sock(sk); + + if (!sock_flag(sk, SOCK_DONE)) { + (void)virtio_transport_reset(vsk, NULL); + + virtio_transport_do_close(vsk, false); + } + + vsk->close_work_scheduled = false; + + release_sock(sk); + sock_put(sk); +} + +/* User context, vsk->sk is locked */ +static bool virtio_transport_close(struct vsock_sock *vsk) +{ + struct sock *sk = &vsk->sk; + + if (!(sk->sk_state == SS_CONNECTED || + sk->sk_state == SS_DISCONNECTING)) + return true; + + /* Already received SHUTDOWN from peer, reply with RST */ + if ((vsk->peer_shutdown & SHUTDOWN_MASK) == SHUTDOWN_MASK) { + (void)virtio_transport_reset(vsk, NULL); + return true; + } + + if ((sk->sk_shutdown & SHUTDOWN_MASK) != SHUTDOWN_MASK) + (void)virtio_transport_shutdown(vsk, SHUTDOWN_MASK); + + if (sock_flag(sk, SOCK_LINGER) && !(current->flags & PF_EXITING)) + virtio_transport_wait_close(sk, sk->sk_lingertime); + + if (sock_flag(sk, SOCK_DONE)) { + return true; + } + + sock_hold(sk); + INIT_DELAYED_WORK(&vsk->close_work, + virtio_transport_close_timeout); + vsk->close_work_scheduled = true; + schedule_delayed_work(&vsk->close_work, VSOCK_CLOSE_TIMEOUT); + return false; +} + +void virtio_transport_release(struct vsock_sock *vsk) +{ + struct sock *sk = &vsk->sk; + bool remove_sock = true; + + lock_sock(sk); + if (sk->sk_type == SOCK_STREAM) + remove_sock = virtio_transport_close(vsk); + release_sock(sk); + + if (remove_sock) + vsock_remove_sock(vsk); +} +EXPORT_SYMBOL_GPL(virtio_transport_release); + +static int +virtio_transport_recv_connecting(struct sock *sk, + struct virtio_vsock_pkt *pkt) +{ + struct vsock_sock *vsk = vsock_sk(sk); + int err; + int skerr; + + switch (le16_to_cpu(pkt->hdr.op)) { + case VIRTIO_VSOCK_OP_RESPONSE: + sk->sk_state = SS_CONNECTED; + sk->sk_socket->state = SS_CONNECTED; + vsock_insert_connected(vsk); + sk->sk_state_change(sk); + break; + case VIRTIO_VSOCK_OP_INVALID: + break; + case VIRTIO_VSOCK_OP_RST: + skerr = ECONNRESET; + err = 0; + goto destroy; + default: + skerr = EPROTO; + err = -EINVAL; + goto destroy; + } + return 0; + +destroy: + virtio_transport_reset(vsk, pkt); + sk->sk_state = SS_UNCONNECTED; + sk->sk_err = skerr; + sk->sk_error_report(sk); + return err; +} + +static int +virtio_transport_recv_connected(struct sock *sk, + struct virtio_vsock_pkt *pkt) +{ + struct vsock_sock *vsk = vsock_sk(sk); + struct virtio_vsock_sock *vvs = vsk->trans; + int err = 0; + + switch (le16_to_cpu(pkt->hdr.op)) { + case VIRTIO_VSOCK_OP_RW: + pkt->len = le32_to_cpu(pkt->hdr.len); + pkt->off = 0; + + spin_lock_bh(&vvs->rx_lock); + virtio_transport_inc_rx_pkt(vvs, pkt); + list_add_tail(&pkt->list, &vvs->rx_queue); + spin_unlock_bh(&vvs->rx_lock); + + sk->sk_data_ready(sk); + return err; + case VIRTIO_VSOCK_OP_CREDIT_UPDATE: + sk->sk_write_space(sk); + break; + case VIRTIO_VSOCK_OP_SHUTDOWN: + if (le32_to_cpu(pkt->hdr.flags) & VIRTIO_VSOCK_SHUTDOWN_RCV) + vsk->peer_shutdown |= RCV_SHUTDOWN; + if (le32_to_cpu(pkt->hdr.flags) & VIRTIO_VSOCK_SHUTDOWN_SEND) + vsk->peer_shutdown |= SEND_SHUTDOWN; + if (vsk->peer_shutdown == SHUTDOWN_MASK && + vsock_stream_has_data(vsk) <= 0) + sk->sk_state = SS_DISCONNECTING; + if (le32_to_cpu(pkt->hdr.flags)) + sk->sk_state_change(sk); + break; + case VIRTIO_VSOCK_OP_RST: + virtio_transport_do_close(vsk, true); + break; + default: + err = -EINVAL; + break; + } + + virtio_transport_free_pkt(pkt); + return err; +} + +static void +virtio_transport_recv_disconnecting(struct sock *sk, + struct virtio_vsock_pkt *pkt) +{ + struct vsock_sock *vsk = vsock_sk(sk); + + if (le16_to_cpu(pkt->hdr.op) == VIRTIO_VSOCK_OP_RST) + virtio_transport_do_close(vsk, true); +} + +static int +virtio_transport_send_response(struct vsock_sock *vsk, + struct virtio_vsock_pkt *pkt) +{ + struct virtio_vsock_pkt_info info = { + .op = VIRTIO_VSOCK_OP_RESPONSE, + .type = VIRTIO_VSOCK_TYPE_STREAM, + .remote_cid = le32_to_cpu(pkt->hdr.src_cid), + .remote_port = le32_to_cpu(pkt->hdr.src_port), + .reply = true, + }; + + return virtio_transport_send_pkt_info(vsk, &info); +} + +/* Handle server socket */ +static int +virtio_transport_recv_listen(struct sock *sk, struct virtio_vsock_pkt *pkt) +{ + struct vsock_sock *vsk = vsock_sk(sk); + struct vsock_sock *vchild; + struct sock *child; + + if (le16_to_cpu(pkt->hdr.op) != VIRTIO_VSOCK_OP_REQUEST) { + virtio_transport_reset(vsk, pkt); + return -EINVAL; + } + + if (sk_acceptq_is_full(sk)) { + virtio_transport_reset(vsk, pkt); + return -ENOMEM; + } + + child = __vsock_create(sock_net(sk), NULL, sk, GFP_KERNEL, + sk->sk_type, 0); + if (!child) { + virtio_transport_reset(vsk, pkt); + return -ENOMEM; + } + + sk->sk_ack_backlog++; + + lock_sock_nested(child, SINGLE_DEPTH_NESTING); + + child->sk_state = SS_CONNECTED; + + vchild = vsock_sk(child); + vsock_addr_init(&vchild->local_addr, le32_to_cpu(pkt->hdr.dst_cid), + le32_to_cpu(pkt->hdr.dst_port)); + vsock_addr_init(&vchild->remote_addr, le32_to_cpu(pkt->hdr.src_cid), + le32_to_cpu(pkt->hdr.src_port)); + + vsock_insert_connected(vchild); + vsock_enqueue_accept(sk, child); + virtio_transport_send_response(vchild, pkt); + + release_sock(child); + + sk->sk_data_ready(sk); + return 0; +} + +static bool virtio_transport_space_update(struct sock *sk, + struct virtio_vsock_pkt *pkt) +{ + struct vsock_sock *vsk = vsock_sk(sk); + struct virtio_vsock_sock *vvs = vsk->trans; + bool space_available; + + /* buf_alloc and fwd_cnt is always included in the hdr */ + spin_lock_bh(&vvs->tx_lock); + vvs->peer_buf_alloc = le32_to_cpu(pkt->hdr.buf_alloc); + vvs->peer_fwd_cnt = le32_to_cpu(pkt->hdr.fwd_cnt); + space_available = virtio_transport_has_space(vsk); + spin_unlock_bh(&vvs->tx_lock); + return space_available; +} + +/* We are under the virtio-vsock's vsock->rx_lock or vhost-vsock's vq->mutex + * lock. + */ +void virtio_transport_recv_pkt(struct virtio_vsock_pkt *pkt) +{ + struct sockaddr_vm src, dst; + struct vsock_sock *vsk; + struct sock *sk; + bool space_available; + + vsock_addr_init(&src, le32_to_cpu(pkt->hdr.src_cid), + le32_to_cpu(pkt->hdr.src_port)); + vsock_addr_init(&dst, le32_to_cpu(pkt->hdr.dst_cid), + le32_to_cpu(pkt->hdr.dst_port)); + + trace_virtio_transport_recv_pkt(src.svm_cid, src.svm_port, + dst.svm_cid, dst.svm_port, + le32_to_cpu(pkt->hdr.len), + le16_to_cpu(pkt->hdr.type), + le16_to_cpu(pkt->hdr.op), + le32_to_cpu(pkt->hdr.flags), + le32_to_cpu(pkt->hdr.buf_alloc), + le32_to_cpu(pkt->hdr.fwd_cnt)); + + if (le16_to_cpu(pkt->hdr.type) != VIRTIO_VSOCK_TYPE_STREAM) { + (void)virtio_transport_reset_no_sock(pkt); + goto free_pkt; + } + + /* The socket must be in connected or bound table + * otherwise send reset back + */ + sk = vsock_find_connected_socket(&src, &dst); + if (!sk) { + sk = vsock_find_bound_socket(&dst); + if (!sk) { + (void)virtio_transport_reset_no_sock(pkt); + goto free_pkt; + } + } + + vsk = vsock_sk(sk); + + space_available = virtio_transport_space_update(sk, pkt); + + lock_sock(sk); + + /* Update CID in case it has changed after a transport reset event */ + vsk->local_addr.svm_cid = dst.svm_cid; + + if (space_available) + sk->sk_write_space(sk); + + switch (sk->sk_state) { + case VSOCK_SS_LISTEN: + virtio_transport_recv_listen(sk, pkt); + virtio_transport_free_pkt(pkt); + break; + case SS_CONNECTING: + virtio_transport_recv_connecting(sk, pkt); + virtio_transport_free_pkt(pkt); + break; + case SS_CONNECTED: + virtio_transport_recv_connected(sk, pkt); + break; + case SS_DISCONNECTING: + virtio_transport_recv_disconnecting(sk, pkt); + virtio_transport_free_pkt(pkt); + break; + default: + virtio_transport_free_pkt(pkt); + break; + } + release_sock(sk); + + /* Release refcnt obtained when we fetched this socket out of the + * bound or connected list. + */ + sock_put(sk); + return; + +free_pkt: + virtio_transport_free_pkt(pkt); +} +EXPORT_SYMBOL_GPL(virtio_transport_recv_pkt); + +void virtio_transport_free_pkt(struct virtio_vsock_pkt *pkt) +{ + kfree(pkt->buf); + kfree(pkt); +} +EXPORT_SYMBOL_GPL(virtio_transport_free_pkt); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Asias He"); +MODULE_DESCRIPTION("common code for virtio vsock"); -- cgit v1.2.3 From 90242599969dd319bcd69757459a929bfc89d1c8 Mon Sep 17 00:00:00 2001 From: Asias He Date: Thu, 28 Jul 2016 15:36:33 +0100 Subject: UPSTREAM: VSOCK: Introduce virtio_transport.ko VM sockets virtio transport implementation. This driver runs in the guest. Signed-off-by: Asias He Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin (cherry picked from commit 0ea9e1d3a9e3ef7d2a1462d3de6b95131dc7d872) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Cody Schuffelen Change-Id: Ib12e1e4d21183ac3d917316566694758717596bd --- MAINTAINERS | 1 + net/vmw_vsock/virtio_transport.c | 624 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 625 insertions(+) create mode 100644 net/vmw_vsock/virtio_transport.c diff --git a/MAINTAINERS b/MAINTAINERS index 6f23bb412b98..4098f22546ef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11457,6 +11457,7 @@ S: Maintained F: include/linux/virtio_vsock.h F: include/uapi/linux/virtio_vsock.h F: net/vmw_vsock/virtio_transport_common.c +F: net/vmw_vsock/virtio_transport.c VIRTUAL SERIO DEVICE DRIVER M: Stephen Chandler Paul diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c new file mode 100644 index 000000000000..699dfabdbccd --- /dev/null +++ b/net/vmw_vsock/virtio_transport.c @@ -0,0 +1,624 @@ +/* + * virtio transport for vsock + * + * Copyright (C) 2013-2015 Red Hat, Inc. + * Author: Asias He + * Stefan Hajnoczi + * + * Some of the code is take from Gerd Hoffmann 's + * early virtio-vsock proof-of-concept bits. + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct workqueue_struct *virtio_vsock_workqueue; +static struct virtio_vsock *the_virtio_vsock; +static DEFINE_MUTEX(the_virtio_vsock_mutex); /* protects the_virtio_vsock */ + +struct virtio_vsock { + struct virtio_device *vdev; + struct virtqueue *vqs[VSOCK_VQ_MAX]; + + /* Virtqueue processing is deferred to a workqueue */ + struct work_struct tx_work; + struct work_struct rx_work; + struct work_struct event_work; + + /* The following fields are protected by tx_lock. vqs[VSOCK_VQ_TX] + * must be accessed with tx_lock held. + */ + struct mutex tx_lock; + + struct work_struct send_pkt_work; + spinlock_t send_pkt_list_lock; + struct list_head send_pkt_list; + + atomic_t queued_replies; + + /* The following fields are protected by rx_lock. vqs[VSOCK_VQ_RX] + * must be accessed with rx_lock held. + */ + struct mutex rx_lock; + int rx_buf_nr; + int rx_buf_max_nr; + + /* The following fields are protected by event_lock. + * vqs[VSOCK_VQ_EVENT] must be accessed with event_lock held. + */ + struct mutex event_lock; + struct virtio_vsock_event event_list[8]; + + u32 guest_cid; +}; + +static struct virtio_vsock *virtio_vsock_get(void) +{ + return the_virtio_vsock; +} + +static u32 virtio_transport_get_local_cid(void) +{ + struct virtio_vsock *vsock = virtio_vsock_get(); + + return vsock->guest_cid; +} + +static void +virtio_transport_send_pkt_work(struct work_struct *work) +{ + struct virtio_vsock *vsock = + container_of(work, struct virtio_vsock, send_pkt_work); + struct virtqueue *vq; + bool added = false; + bool restart_rx = false; + + mutex_lock(&vsock->tx_lock); + + vq = vsock->vqs[VSOCK_VQ_TX]; + + /* Avoid unnecessary interrupts while we're processing the ring */ + virtqueue_disable_cb(vq); + + for (;;) { + struct virtio_vsock_pkt *pkt; + struct scatterlist hdr, buf, *sgs[2]; + int ret, in_sg = 0, out_sg = 0; + bool reply; + + spin_lock_bh(&vsock->send_pkt_list_lock); + if (list_empty(&vsock->send_pkt_list)) { + spin_unlock_bh(&vsock->send_pkt_list_lock); + virtqueue_enable_cb(vq); + break; + } + + pkt = list_first_entry(&vsock->send_pkt_list, + struct virtio_vsock_pkt, list); + list_del_init(&pkt->list); + spin_unlock_bh(&vsock->send_pkt_list_lock); + + reply = pkt->reply; + + sg_init_one(&hdr, &pkt->hdr, sizeof(pkt->hdr)); + sgs[out_sg++] = &hdr; + if (pkt->buf) { + sg_init_one(&buf, pkt->buf, pkt->len); + sgs[out_sg++] = &buf; + } + + ret = virtqueue_add_sgs(vq, sgs, out_sg, in_sg, pkt, GFP_KERNEL); + if (ret < 0) { + spin_lock_bh(&vsock->send_pkt_list_lock); + list_add(&pkt->list, &vsock->send_pkt_list); + spin_unlock_bh(&vsock->send_pkt_list_lock); + + if (!virtqueue_enable_cb(vq) && ret == -ENOSPC) + continue; /* retry now that we have more space */ + break; + } + + if (reply) { + struct virtqueue *rx_vq = vsock->vqs[VSOCK_VQ_RX]; + int val; + + val = atomic_dec_return(&vsock->queued_replies); + + /* Do we now have resources to resume rx processing? */ + if (val + 1 == virtqueue_get_vring_size(rx_vq)) + restart_rx = true; + } + + added = true; + } + + if (added) + virtqueue_kick(vq); + + mutex_unlock(&vsock->tx_lock); + + if (restart_rx) + queue_work(virtio_vsock_workqueue, &vsock->rx_work); +} + +static int +virtio_transport_send_pkt(struct virtio_vsock_pkt *pkt) +{ + struct virtio_vsock *vsock; + int len = pkt->len; + + vsock = virtio_vsock_get(); + if (!vsock) { + virtio_transport_free_pkt(pkt); + return -ENODEV; + } + + if (pkt->reply) + atomic_inc(&vsock->queued_replies); + + spin_lock_bh(&vsock->send_pkt_list_lock); + list_add_tail(&pkt->list, &vsock->send_pkt_list); + spin_unlock_bh(&vsock->send_pkt_list_lock); + + queue_work(virtio_vsock_workqueue, &vsock->send_pkt_work); + return len; +} + +static void virtio_vsock_rx_fill(struct virtio_vsock *vsock) +{ + int buf_len = VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE; + struct virtio_vsock_pkt *pkt; + struct scatterlist hdr, buf, *sgs[2]; + struct virtqueue *vq; + int ret; + + vq = vsock->vqs[VSOCK_VQ_RX]; + + do { + pkt = kzalloc(sizeof(*pkt), GFP_KERNEL); + if (!pkt) + break; + + pkt->buf = kmalloc(buf_len, GFP_KERNEL); + if (!pkt->buf) { + virtio_transport_free_pkt(pkt); + break; + } + + pkt->len = buf_len; + + sg_init_one(&hdr, &pkt->hdr, sizeof(pkt->hdr)); + sgs[0] = &hdr; + + sg_init_one(&buf, pkt->buf, buf_len); + sgs[1] = &buf; + ret = virtqueue_add_sgs(vq, sgs, 0, 2, pkt, GFP_KERNEL); + if (ret) { + virtio_transport_free_pkt(pkt); + break; + } + vsock->rx_buf_nr++; + } while (vq->num_free); + if (vsock->rx_buf_nr > vsock->rx_buf_max_nr) + vsock->rx_buf_max_nr = vsock->rx_buf_nr; + virtqueue_kick(vq); +} + +static void virtio_transport_tx_work(struct work_struct *work) +{ + struct virtio_vsock *vsock = + container_of(work, struct virtio_vsock, tx_work); + struct virtqueue *vq; + bool added = false; + + vq = vsock->vqs[VSOCK_VQ_TX]; + mutex_lock(&vsock->tx_lock); + do { + struct virtio_vsock_pkt *pkt; + unsigned int len; + + virtqueue_disable_cb(vq); + while ((pkt = virtqueue_get_buf(vq, &len)) != NULL) { + virtio_transport_free_pkt(pkt); + added = true; + } + } while (!virtqueue_enable_cb(vq)); + mutex_unlock(&vsock->tx_lock); + + if (added) + queue_work(virtio_vsock_workqueue, &vsock->send_pkt_work); +} + +/* Is there space left for replies to rx packets? */ +static bool virtio_transport_more_replies(struct virtio_vsock *vsock) +{ + struct virtqueue *vq = vsock->vqs[VSOCK_VQ_RX]; + int val; + + smp_rmb(); /* paired with atomic_inc() and atomic_dec_return() */ + val = atomic_read(&vsock->queued_replies); + + return val < virtqueue_get_vring_size(vq); +} + +static void virtio_transport_rx_work(struct work_struct *work) +{ + struct virtio_vsock *vsock = + container_of(work, struct virtio_vsock, rx_work); + struct virtqueue *vq; + + vq = vsock->vqs[VSOCK_VQ_RX]; + + mutex_lock(&vsock->rx_lock); + + do { + virtqueue_disable_cb(vq); + for (;;) { + struct virtio_vsock_pkt *pkt; + unsigned int len; + + if (!virtio_transport_more_replies(vsock)) { + /* Stop rx until the device processes already + * pending replies. Leave rx virtqueue + * callbacks disabled. + */ + goto out; + } + + pkt = virtqueue_get_buf(vq, &len); + if (!pkt) { + break; + } + + vsock->rx_buf_nr--; + + /* Drop short/long packets */ + if (unlikely(len < sizeof(pkt->hdr) || + len > sizeof(pkt->hdr) + pkt->len)) { + virtio_transport_free_pkt(pkt); + continue; + } + + pkt->len = len - sizeof(pkt->hdr); + virtio_transport_recv_pkt(pkt); + } + } while (!virtqueue_enable_cb(vq)); + +out: + if (vsock->rx_buf_nr < vsock->rx_buf_max_nr / 2) + virtio_vsock_rx_fill(vsock); + mutex_unlock(&vsock->rx_lock); +} + +/* event_lock must be held */ +static int virtio_vsock_event_fill_one(struct virtio_vsock *vsock, + struct virtio_vsock_event *event) +{ + struct scatterlist sg; + struct virtqueue *vq; + + vq = vsock->vqs[VSOCK_VQ_EVENT]; + + sg_init_one(&sg, event, sizeof(*event)); + + return virtqueue_add_inbuf(vq, &sg, 1, event, GFP_KERNEL); +} + +/* event_lock must be held */ +static void virtio_vsock_event_fill(struct virtio_vsock *vsock) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(vsock->event_list); i++) { + struct virtio_vsock_event *event = &vsock->event_list[i]; + + virtio_vsock_event_fill_one(vsock, event); + } + + virtqueue_kick(vsock->vqs[VSOCK_VQ_EVENT]); +} + +static void virtio_vsock_reset_sock(struct sock *sk) +{ + lock_sock(sk); + sk->sk_state = SS_UNCONNECTED; + sk->sk_err = ECONNRESET; + sk->sk_error_report(sk); + release_sock(sk); +} + +static void virtio_vsock_update_guest_cid(struct virtio_vsock *vsock) +{ + struct virtio_device *vdev = vsock->vdev; + u64 guest_cid; + + vdev->config->get(vdev, offsetof(struct virtio_vsock_config, guest_cid), + &guest_cid, sizeof(guest_cid)); + vsock->guest_cid = le64_to_cpu(guest_cid); +} + +/* event_lock must be held */ +static void virtio_vsock_event_handle(struct virtio_vsock *vsock, + struct virtio_vsock_event *event) +{ + switch (le32_to_cpu(event->id)) { + case VIRTIO_VSOCK_EVENT_TRANSPORT_RESET: + virtio_vsock_update_guest_cid(vsock); + vsock_for_each_connected_socket(virtio_vsock_reset_sock); + break; + } +} + +static void virtio_transport_event_work(struct work_struct *work) +{ + struct virtio_vsock *vsock = + container_of(work, struct virtio_vsock, event_work); + struct virtqueue *vq; + + vq = vsock->vqs[VSOCK_VQ_EVENT]; + + mutex_lock(&vsock->event_lock); + + do { + struct virtio_vsock_event *event; + unsigned int len; + + virtqueue_disable_cb(vq); + while ((event = virtqueue_get_buf(vq, &len)) != NULL) { + if (len == sizeof(*event)) + virtio_vsock_event_handle(vsock, event); + + virtio_vsock_event_fill_one(vsock, event); + } + } while (!virtqueue_enable_cb(vq)); + + virtqueue_kick(vsock->vqs[VSOCK_VQ_EVENT]); + + mutex_unlock(&vsock->event_lock); +} + +static void virtio_vsock_event_done(struct virtqueue *vq) +{ + struct virtio_vsock *vsock = vq->vdev->priv; + + if (!vsock) + return; + queue_work(virtio_vsock_workqueue, &vsock->event_work); +} + +static void virtio_vsock_tx_done(struct virtqueue *vq) +{ + struct virtio_vsock *vsock = vq->vdev->priv; + + if (!vsock) + return; + queue_work(virtio_vsock_workqueue, &vsock->tx_work); +} + +static void virtio_vsock_rx_done(struct virtqueue *vq) +{ + struct virtio_vsock *vsock = vq->vdev->priv; + + if (!vsock) + return; + queue_work(virtio_vsock_workqueue, &vsock->rx_work); +} + +static struct virtio_transport virtio_transport = { + .transport = { + .get_local_cid = virtio_transport_get_local_cid, + + .init = virtio_transport_do_socket_init, + .destruct = virtio_transport_destruct, + .release = virtio_transport_release, + .connect = virtio_transport_connect, + .shutdown = virtio_transport_shutdown, + + .dgram_bind = virtio_transport_dgram_bind, + .dgram_dequeue = virtio_transport_dgram_dequeue, + .dgram_enqueue = virtio_transport_dgram_enqueue, + .dgram_allow = virtio_transport_dgram_allow, + + .stream_dequeue = virtio_transport_stream_dequeue, + .stream_enqueue = virtio_transport_stream_enqueue, + .stream_has_data = virtio_transport_stream_has_data, + .stream_has_space = virtio_transport_stream_has_space, + .stream_rcvhiwat = virtio_transport_stream_rcvhiwat, + .stream_is_active = virtio_transport_stream_is_active, + .stream_allow = virtio_transport_stream_allow, + + .notify_poll_in = virtio_transport_notify_poll_in, + .notify_poll_out = virtio_transport_notify_poll_out, + .notify_recv_init = virtio_transport_notify_recv_init, + .notify_recv_pre_block = virtio_transport_notify_recv_pre_block, + .notify_recv_pre_dequeue = virtio_transport_notify_recv_pre_dequeue, + .notify_recv_post_dequeue = virtio_transport_notify_recv_post_dequeue, + .notify_send_init = virtio_transport_notify_send_init, + .notify_send_pre_block = virtio_transport_notify_send_pre_block, + .notify_send_pre_enqueue = virtio_transport_notify_send_pre_enqueue, + .notify_send_post_enqueue = virtio_transport_notify_send_post_enqueue, + + .set_buffer_size = virtio_transport_set_buffer_size, + .set_min_buffer_size = virtio_transport_set_min_buffer_size, + .set_max_buffer_size = virtio_transport_set_max_buffer_size, + .get_buffer_size = virtio_transport_get_buffer_size, + .get_min_buffer_size = virtio_transport_get_min_buffer_size, + .get_max_buffer_size = virtio_transport_get_max_buffer_size, + }, + + .send_pkt = virtio_transport_send_pkt, +}; + +static int virtio_vsock_probe(struct virtio_device *vdev) +{ + vq_callback_t *callbacks[] = { + virtio_vsock_rx_done, + virtio_vsock_tx_done, + virtio_vsock_event_done, + }; + static const char * const names[] = { + "rx", + "tx", + "event", + }; + struct virtio_vsock *vsock = NULL; + int ret; + + ret = mutex_lock_interruptible(&the_virtio_vsock_mutex); + if (ret) + return ret; + + /* Only one virtio-vsock device per guest is supported */ + if (the_virtio_vsock) { + ret = -EBUSY; + goto out; + } + + vsock = kzalloc(sizeof(*vsock), GFP_KERNEL); + if (!vsock) { + ret = -ENOMEM; + goto out; + } + + vsock->vdev = vdev; + + ret = vsock->vdev->config->find_vqs(vsock->vdev, VSOCK_VQ_MAX, + vsock->vqs, callbacks, names); + if (ret < 0) + goto out; + + virtio_vsock_update_guest_cid(vsock); + + ret = vsock_core_init(&virtio_transport.transport); + if (ret < 0) + goto out_vqs; + + vsock->rx_buf_nr = 0; + vsock->rx_buf_max_nr = 0; + atomic_set(&vsock->queued_replies, 0); + + vdev->priv = vsock; + the_virtio_vsock = vsock; + mutex_init(&vsock->tx_lock); + mutex_init(&vsock->rx_lock); + mutex_init(&vsock->event_lock); + spin_lock_init(&vsock->send_pkt_list_lock); + INIT_LIST_HEAD(&vsock->send_pkt_list); + INIT_WORK(&vsock->rx_work, virtio_transport_rx_work); + INIT_WORK(&vsock->tx_work, virtio_transport_tx_work); + INIT_WORK(&vsock->event_work, virtio_transport_event_work); + INIT_WORK(&vsock->send_pkt_work, virtio_transport_send_pkt_work); + + mutex_lock(&vsock->rx_lock); + virtio_vsock_rx_fill(vsock); + mutex_unlock(&vsock->rx_lock); + + mutex_lock(&vsock->event_lock); + virtio_vsock_event_fill(vsock); + mutex_unlock(&vsock->event_lock); + + mutex_unlock(&the_virtio_vsock_mutex); + return 0; + +out_vqs: + vsock->vdev->config->del_vqs(vsock->vdev); +out: + kfree(vsock); + mutex_unlock(&the_virtio_vsock_mutex); + return ret; +} + +static void virtio_vsock_remove(struct virtio_device *vdev) +{ + struct virtio_vsock *vsock = vdev->priv; + struct virtio_vsock_pkt *pkt; + + flush_work(&vsock->rx_work); + flush_work(&vsock->tx_work); + flush_work(&vsock->event_work); + flush_work(&vsock->send_pkt_work); + + vdev->config->reset(vdev); + + mutex_lock(&vsock->rx_lock); + while ((pkt = virtqueue_detach_unused_buf(vsock->vqs[VSOCK_VQ_RX]))) + virtio_transport_free_pkt(pkt); + mutex_unlock(&vsock->rx_lock); + + mutex_lock(&vsock->tx_lock); + while ((pkt = virtqueue_detach_unused_buf(vsock->vqs[VSOCK_VQ_TX]))) + virtio_transport_free_pkt(pkt); + mutex_unlock(&vsock->tx_lock); + + spin_lock_bh(&vsock->send_pkt_list_lock); + while (!list_empty(&vsock->send_pkt_list)) { + pkt = list_first_entry(&vsock->send_pkt_list, + struct virtio_vsock_pkt, list); + list_del(&pkt->list); + virtio_transport_free_pkt(pkt); + } + spin_unlock_bh(&vsock->send_pkt_list_lock); + + mutex_lock(&the_virtio_vsock_mutex); + the_virtio_vsock = NULL; + vsock_core_exit(); + mutex_unlock(&the_virtio_vsock_mutex); + + vdev->config->del_vqs(vdev); + + kfree(vsock); +} + +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_VSOCK, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static unsigned int features[] = { +}; + +static struct virtio_driver virtio_vsock_driver = { + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virtio_vsock_probe, + .remove = virtio_vsock_remove, +}; + +static int __init virtio_vsock_init(void) +{ + int ret; + + virtio_vsock_workqueue = alloc_workqueue("virtio_vsock", 0, 0); + if (!virtio_vsock_workqueue) + return -ENOMEM; + ret = register_virtio_driver(&virtio_vsock_driver); + if (ret) + destroy_workqueue(virtio_vsock_workqueue); + return ret; +} + +static void __exit virtio_vsock_exit(void) +{ + unregister_virtio_driver(&virtio_vsock_driver); + destroy_workqueue(virtio_vsock_workqueue); +} + +module_init(virtio_vsock_init); +module_exit(virtio_vsock_exit); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Asias He"); +MODULE_DESCRIPTION("virtio transport for vsock"); +MODULE_DEVICE_TABLE(virtio, id_table); -- cgit v1.2.3 From 9418de5f27b83cdbd283202f3bf9c75e09ee5470 Mon Sep 17 00:00:00 2001 From: Asias He Date: Thu, 28 Jul 2016 15:36:34 +0100 Subject: UPSTREAM: VSOCK: Introduce vhost_vsock.ko VM sockets vhost transport implementation. This driver runs on the host. Signed-off-by: Asias He Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin (cherry picked from commit 433fc58e6bf2c8bd97e57153ed28e64fd78207b8) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Cody Schuffelen Change-Id: Id90d852ffd498a7d89075cddb6d8ed0b9af5e69f --- MAINTAINERS | 2 + drivers/vhost/vsock.c | 722 +++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/vhost.h | 5 + 3 files changed, 729 insertions(+) create mode 100644 drivers/vhost/vsock.c diff --git a/MAINTAINERS b/MAINTAINERS index 4098f22546ef..3ae7b57b5f1a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11458,6 +11458,8 @@ F: include/linux/virtio_vsock.h F: include/uapi/linux/virtio_vsock.h F: net/vmw_vsock/virtio_transport_common.c F: net/vmw_vsock/virtio_transport.c +F: drivers/vhost/vsock.c +F: drivers/vhost/vsock.h VIRTUAL SERIO DEVICE DRIVER M: Stephen Chandler Paul diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c new file mode 100644 index 000000000000..028ca16c2d36 --- /dev/null +++ b/drivers/vhost/vsock.c @@ -0,0 +1,722 @@ +/* + * vhost transport for vsock + * + * Copyright (C) 2013-2015 Red Hat, Inc. + * Author: Asias He + * Stefan Hajnoczi + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "vhost.h" + +#define VHOST_VSOCK_DEFAULT_HOST_CID 2 + +enum { + VHOST_VSOCK_FEATURES = VHOST_FEATURES, +}; + +/* Used to track all the vhost_vsock instances on the system. */ +static DEFINE_SPINLOCK(vhost_vsock_lock); +static LIST_HEAD(vhost_vsock_list); + +struct vhost_vsock { + struct vhost_dev dev; + struct vhost_virtqueue vqs[2]; + + /* Link to global vhost_vsock_list, protected by vhost_vsock_lock */ + struct list_head list; + + struct vhost_work send_pkt_work; + spinlock_t send_pkt_list_lock; + struct list_head send_pkt_list; /* host->guest pending packets */ + + atomic_t queued_replies; + + u32 guest_cid; +}; + +static u32 vhost_transport_get_local_cid(void) +{ + return VHOST_VSOCK_DEFAULT_HOST_CID; +} + +static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) +{ + struct vhost_vsock *vsock; + + spin_lock_bh(&vhost_vsock_lock); + list_for_each_entry(vsock, &vhost_vsock_list, list) { + u32 other_cid = vsock->guest_cid; + + /* Skip instances that have no CID yet */ + if (other_cid == 0) + continue; + + if (other_cid == guest_cid) { + spin_unlock_bh(&vhost_vsock_lock); + return vsock; + } + } + spin_unlock_bh(&vhost_vsock_lock); + + return NULL; +} + +static void +vhost_transport_do_send_pkt(struct vhost_vsock *vsock, + struct vhost_virtqueue *vq) +{ + struct vhost_virtqueue *tx_vq = &vsock->vqs[VSOCK_VQ_TX]; + bool added = false; + bool restart_tx = false; + + mutex_lock(&vq->mutex); + + if (!vq->private_data) + goto out; + + /* Avoid further vmexits, we're already processing the virtqueue */ + vhost_disable_notify(&vsock->dev, vq); + + for (;;) { + struct virtio_vsock_pkt *pkt; + struct iov_iter iov_iter; + unsigned out, in; + size_t nbytes; + size_t len; + int head; + + spin_lock_bh(&vsock->send_pkt_list_lock); + if (list_empty(&vsock->send_pkt_list)) { + spin_unlock_bh(&vsock->send_pkt_list_lock); + vhost_enable_notify(&vsock->dev, vq); + break; + } + + pkt = list_first_entry(&vsock->send_pkt_list, + struct virtio_vsock_pkt, list); + list_del_init(&pkt->list); + spin_unlock_bh(&vsock->send_pkt_list_lock); + + head = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov), + &out, &in, NULL, NULL); + if (head < 0) { + spin_lock_bh(&vsock->send_pkt_list_lock); + list_add(&pkt->list, &vsock->send_pkt_list); + spin_unlock_bh(&vsock->send_pkt_list_lock); + break; + } + + if (head == vq->num) { + spin_lock_bh(&vsock->send_pkt_list_lock); + list_add(&pkt->list, &vsock->send_pkt_list); + spin_unlock_bh(&vsock->send_pkt_list_lock); + + /* We cannot finish yet if more buffers snuck in while + * re-enabling notify. + */ + if (unlikely(vhost_enable_notify(&vsock->dev, vq))) { + vhost_disable_notify(&vsock->dev, vq); + continue; + } + break; + } + + if (out) { + virtio_transport_free_pkt(pkt); + vq_err(vq, "Expected 0 output buffers, got %u\n", out); + break; + } + + len = iov_length(&vq->iov[out], in); + iov_iter_init(&iov_iter, READ, &vq->iov[out], in, len); + + nbytes = copy_to_iter(&pkt->hdr, sizeof(pkt->hdr), &iov_iter); + if (nbytes != sizeof(pkt->hdr)) { + virtio_transport_free_pkt(pkt); + vq_err(vq, "Faulted on copying pkt hdr\n"); + break; + } + + nbytes = copy_to_iter(pkt->buf, pkt->len, &iov_iter); + if (nbytes != pkt->len) { + virtio_transport_free_pkt(pkt); + vq_err(vq, "Faulted on copying pkt buf\n"); + break; + } + + vhost_add_used(vq, head, sizeof(pkt->hdr) + pkt->len); + added = true; + + if (pkt->reply) { + int val; + + val = atomic_dec_return(&vsock->queued_replies); + + /* Do we have resources to resume tx processing? */ + if (val + 1 == tx_vq->num) + restart_tx = true; + } + + virtio_transport_free_pkt(pkt); + } + if (added) + vhost_signal(&vsock->dev, vq); + +out: + mutex_unlock(&vq->mutex); + + if (restart_tx) + vhost_poll_queue(&tx_vq->poll); +} + +static void vhost_transport_send_pkt_work(struct vhost_work *work) +{ + struct vhost_virtqueue *vq; + struct vhost_vsock *vsock; + + vsock = container_of(work, struct vhost_vsock, send_pkt_work); + vq = &vsock->vqs[VSOCK_VQ_RX]; + + vhost_transport_do_send_pkt(vsock, vq); +} + +static int +vhost_transport_send_pkt(struct virtio_vsock_pkt *pkt) +{ + struct vhost_vsock *vsock; + struct vhost_virtqueue *vq; + int len = pkt->len; + + /* Find the vhost_vsock according to guest context id */ + vsock = vhost_vsock_get(le64_to_cpu(pkt->hdr.dst_cid)); + if (!vsock) { + virtio_transport_free_pkt(pkt); + return -ENODEV; + } + + vq = &vsock->vqs[VSOCK_VQ_RX]; + + if (pkt->reply) + atomic_inc(&vsock->queued_replies); + + spin_lock_bh(&vsock->send_pkt_list_lock); + list_add_tail(&pkt->list, &vsock->send_pkt_list); + spin_unlock_bh(&vsock->send_pkt_list_lock); + + vhost_work_queue(&vsock->dev, &vsock->send_pkt_work); + return len; +} + +static struct virtio_vsock_pkt * +vhost_vsock_alloc_pkt(struct vhost_virtqueue *vq, + unsigned int out, unsigned int in) +{ + struct virtio_vsock_pkt *pkt; + struct iov_iter iov_iter; + size_t nbytes; + size_t len; + + if (in != 0) { + vq_err(vq, "Expected 0 input buffers, got %u\n", in); + return NULL; + } + + pkt = kzalloc(sizeof(*pkt), GFP_KERNEL); + if (!pkt) + return NULL; + + len = iov_length(vq->iov, out); + iov_iter_init(&iov_iter, WRITE, vq->iov, out, len); + + nbytes = copy_from_iter(&pkt->hdr, sizeof(pkt->hdr), &iov_iter); + if (nbytes != sizeof(pkt->hdr)) { + vq_err(vq, "Expected %zu bytes for pkt->hdr, got %zu bytes\n", + sizeof(pkt->hdr), nbytes); + kfree(pkt); + return NULL; + } + + if (le16_to_cpu(pkt->hdr.type) == VIRTIO_VSOCK_TYPE_STREAM) + pkt->len = le32_to_cpu(pkt->hdr.len); + + /* No payload */ + if (!pkt->len) + return pkt; + + /* The pkt is too big */ + if (pkt->len > VIRTIO_VSOCK_MAX_PKT_BUF_SIZE) { + kfree(pkt); + return NULL; + } + + pkt->buf = kmalloc(pkt->len, GFP_KERNEL); + if (!pkt->buf) { + kfree(pkt); + return NULL; + } + + nbytes = copy_from_iter(pkt->buf, pkt->len, &iov_iter); + if (nbytes != pkt->len) { + vq_err(vq, "Expected %u byte payload, got %zu bytes\n", + pkt->len, nbytes); + virtio_transport_free_pkt(pkt); + return NULL; + } + + return pkt; +} + +/* Is there space left for replies to rx packets? */ +static bool vhost_vsock_more_replies(struct vhost_vsock *vsock) +{ + struct vhost_virtqueue *vq = &vsock->vqs[VSOCK_VQ_TX]; + int val; + + smp_rmb(); /* paired with atomic_inc() and atomic_dec_return() */ + val = atomic_read(&vsock->queued_replies); + + return val < vq->num; +} + +static void vhost_vsock_handle_tx_kick(struct vhost_work *work) +{ + struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue, + poll.work); + struct vhost_vsock *vsock = container_of(vq->dev, struct vhost_vsock, + dev); + struct virtio_vsock_pkt *pkt; + int head; + unsigned int out, in; + bool added = false; + + mutex_lock(&vq->mutex); + + if (!vq->private_data) + goto out; + + vhost_disable_notify(&vsock->dev, vq); + for (;;) { + if (!vhost_vsock_more_replies(vsock)) { + /* Stop tx until the device processes already + * pending replies. Leave tx virtqueue + * callbacks disabled. + */ + goto no_more_replies; + } + + head = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov), + &out, &in, NULL, NULL); + if (head < 0) + break; + + if (head == vq->num) { + if (unlikely(vhost_enable_notify(&vsock->dev, vq))) { + vhost_disable_notify(&vsock->dev, vq); + continue; + } + break; + } + + pkt = vhost_vsock_alloc_pkt(vq, out, in); + if (!pkt) { + vq_err(vq, "Faulted on pkt\n"); + continue; + } + + /* Only accept correctly addressed packets */ + if (le64_to_cpu(pkt->hdr.src_cid) == vsock->guest_cid) + virtio_transport_recv_pkt(pkt); + else + virtio_transport_free_pkt(pkt); + + vhost_add_used(vq, head, sizeof(pkt->hdr) + pkt->len); + added = true; + } + +no_more_replies: + if (added) + vhost_signal(&vsock->dev, vq); + +out: + mutex_unlock(&vq->mutex); +} + +static void vhost_vsock_handle_rx_kick(struct vhost_work *work) +{ + struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue, + poll.work); + struct vhost_vsock *vsock = container_of(vq->dev, struct vhost_vsock, + dev); + + vhost_transport_do_send_pkt(vsock, vq); +} + +static int vhost_vsock_start(struct vhost_vsock *vsock) +{ + size_t i; + int ret; + + mutex_lock(&vsock->dev.mutex); + + ret = vhost_dev_check_owner(&vsock->dev); + if (ret) + goto err; + + for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) { + struct vhost_virtqueue *vq = &vsock->vqs[i]; + + mutex_lock(&vq->mutex); + + if (!vhost_vq_access_ok(vq)) { + ret = -EFAULT; + mutex_unlock(&vq->mutex); + goto err_vq; + } + + if (!vq->private_data) { + vq->private_data = vsock; + vhost_vq_init_access(vq); + } + + mutex_unlock(&vq->mutex); + } + + mutex_unlock(&vsock->dev.mutex); + return 0; + +err_vq: + for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) { + struct vhost_virtqueue *vq = &vsock->vqs[i]; + + mutex_lock(&vq->mutex); + vq->private_data = NULL; + mutex_unlock(&vq->mutex); + } +err: + mutex_unlock(&vsock->dev.mutex); + return ret; +} + +static int vhost_vsock_stop(struct vhost_vsock *vsock) +{ + size_t i; + int ret; + + mutex_lock(&vsock->dev.mutex); + + ret = vhost_dev_check_owner(&vsock->dev); + if (ret) + goto err; + + for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) { + struct vhost_virtqueue *vq = &vsock->vqs[i]; + + mutex_lock(&vq->mutex); + vq->private_data = NULL; + mutex_unlock(&vq->mutex); + } + +err: + mutex_unlock(&vsock->dev.mutex); + return ret; +} + +static void vhost_vsock_free(struct vhost_vsock *vsock) +{ + if (is_vmalloc_addr(vsock)) + vfree(vsock); + else + kfree(vsock); +} + +static int vhost_vsock_dev_open(struct inode *inode, struct file *file) +{ + struct vhost_virtqueue **vqs; + struct vhost_vsock *vsock; + int ret; + + /* This struct is large and allocation could fail, fall back to vmalloc + * if there is no other way. + */ + vsock = kzalloc(sizeof(*vsock), GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); + if (!vsock) { + vsock = vmalloc(sizeof(*vsock)); + if (!vsock) + return -ENOMEM; + } + + vqs = kmalloc_array(ARRAY_SIZE(vsock->vqs), sizeof(*vqs), GFP_KERNEL); + if (!vqs) { + ret = -ENOMEM; + goto out; + } + + atomic_set(&vsock->queued_replies, 0); + + vqs[VSOCK_VQ_TX] = &vsock->vqs[VSOCK_VQ_TX]; + vqs[VSOCK_VQ_RX] = &vsock->vqs[VSOCK_VQ_RX]; + vsock->vqs[VSOCK_VQ_TX].handle_kick = vhost_vsock_handle_tx_kick; + vsock->vqs[VSOCK_VQ_RX].handle_kick = vhost_vsock_handle_rx_kick; + + vhost_dev_init(&vsock->dev, vqs, ARRAY_SIZE(vsock->vqs)); + + file->private_data = vsock; + spin_lock_init(&vsock->send_pkt_list_lock); + INIT_LIST_HEAD(&vsock->send_pkt_list); + vhost_work_init(&vsock->send_pkt_work, vhost_transport_send_pkt_work); + + spin_lock_bh(&vhost_vsock_lock); + list_add_tail(&vsock->list, &vhost_vsock_list); + spin_unlock_bh(&vhost_vsock_lock); + return 0; + +out: + vhost_vsock_free(vsock); + return ret; +} + +static void vhost_vsock_flush(struct vhost_vsock *vsock) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) + if (vsock->vqs[i].handle_kick) + vhost_poll_flush(&vsock->vqs[i].poll); + vhost_work_flush(&vsock->dev, &vsock->send_pkt_work); +} + +static void vhost_vsock_reset_orphans(struct sock *sk) +{ + struct vsock_sock *vsk = vsock_sk(sk); + + /* vmci_transport.c doesn't take sk_lock here either. At least we're + * under vsock_table_lock so the sock cannot disappear while we're + * executing. + */ + + if (!vhost_vsock_get(vsk->local_addr.svm_cid)) { + sock_set_flag(sk, SOCK_DONE); + vsk->peer_shutdown = SHUTDOWN_MASK; + sk->sk_state = SS_UNCONNECTED; + sk->sk_err = ECONNRESET; + sk->sk_error_report(sk); + } +} + +static int vhost_vsock_dev_release(struct inode *inode, struct file *file) +{ + struct vhost_vsock *vsock = file->private_data; + + spin_lock_bh(&vhost_vsock_lock); + list_del(&vsock->list); + spin_unlock_bh(&vhost_vsock_lock); + + /* Iterating over all connections for all CIDs to find orphans is + * inefficient. Room for improvement here. */ + vsock_for_each_connected_socket(vhost_vsock_reset_orphans); + + vhost_vsock_stop(vsock); + vhost_vsock_flush(vsock); + vhost_dev_stop(&vsock->dev); + + spin_lock_bh(&vsock->send_pkt_list_lock); + while (!list_empty(&vsock->send_pkt_list)) { + struct virtio_vsock_pkt *pkt; + + pkt = list_first_entry(&vsock->send_pkt_list, + struct virtio_vsock_pkt, list); + list_del_init(&pkt->list); + virtio_transport_free_pkt(pkt); + } + spin_unlock_bh(&vsock->send_pkt_list_lock); + + vhost_dev_cleanup(&vsock->dev, false); + kfree(vsock->dev.vqs); + vhost_vsock_free(vsock); + return 0; +} + +static int vhost_vsock_set_cid(struct vhost_vsock *vsock, u64 guest_cid) +{ + struct vhost_vsock *other; + + /* Refuse reserved CIDs */ + if (guest_cid <= VMADDR_CID_HOST || + guest_cid == U32_MAX) + return -EINVAL; + + /* 64-bit CIDs are not yet supported */ + if (guest_cid > U32_MAX) + return -EINVAL; + + /* Refuse if CID is already in use */ + other = vhost_vsock_get(guest_cid); + if (other && other != vsock) + return -EADDRINUSE; + + spin_lock_bh(&vhost_vsock_lock); + vsock->guest_cid = guest_cid; + spin_unlock_bh(&vhost_vsock_lock); + + return 0; +} + +static int vhost_vsock_set_features(struct vhost_vsock *vsock, u64 features) +{ + struct vhost_virtqueue *vq; + int i; + + if (features & ~VHOST_VSOCK_FEATURES) + return -EOPNOTSUPP; + + mutex_lock(&vsock->dev.mutex); + if ((features & (1 << VHOST_F_LOG_ALL)) && + !vhost_log_access_ok(&vsock->dev)) { + mutex_unlock(&vsock->dev.mutex); + return -EFAULT; + } + + for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) { + vq = &vsock->vqs[i]; + mutex_lock(&vq->mutex); + vq->acked_features = features; + mutex_unlock(&vq->mutex); + } + mutex_unlock(&vsock->dev.mutex); + return 0; +} + +static long vhost_vsock_dev_ioctl(struct file *f, unsigned int ioctl, + unsigned long arg) +{ + struct vhost_vsock *vsock = f->private_data; + void __user *argp = (void __user *)arg; + u64 guest_cid; + u64 features; + int start; + int r; + + switch (ioctl) { + case VHOST_VSOCK_SET_GUEST_CID: + if (copy_from_user(&guest_cid, argp, sizeof(guest_cid))) + return -EFAULT; + return vhost_vsock_set_cid(vsock, guest_cid); + case VHOST_VSOCK_SET_RUNNING: + if (copy_from_user(&start, argp, sizeof(start))) + return -EFAULT; + if (start) + return vhost_vsock_start(vsock); + else + return vhost_vsock_stop(vsock); + case VHOST_GET_FEATURES: + features = VHOST_VSOCK_FEATURES; + if (copy_to_user(argp, &features, sizeof(features))) + return -EFAULT; + return 0; + case VHOST_SET_FEATURES: + if (copy_from_user(&features, argp, sizeof(features))) + return -EFAULT; + return vhost_vsock_set_features(vsock, features); + default: + mutex_lock(&vsock->dev.mutex); + r = vhost_dev_ioctl(&vsock->dev, ioctl, argp); + if (r == -ENOIOCTLCMD) + r = vhost_vring_ioctl(&vsock->dev, ioctl, argp); + else + vhost_vsock_flush(vsock); + mutex_unlock(&vsock->dev.mutex); + return r; + } +} + +static const struct file_operations vhost_vsock_fops = { + .owner = THIS_MODULE, + .open = vhost_vsock_dev_open, + .release = vhost_vsock_dev_release, + .llseek = noop_llseek, + .unlocked_ioctl = vhost_vsock_dev_ioctl, +}; + +static struct miscdevice vhost_vsock_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "vhost-vsock", + .fops = &vhost_vsock_fops, +}; + +static struct virtio_transport vhost_transport = { + .transport = { + .get_local_cid = vhost_transport_get_local_cid, + + .init = virtio_transport_do_socket_init, + .destruct = virtio_transport_destruct, + .release = virtio_transport_release, + .connect = virtio_transport_connect, + .shutdown = virtio_transport_shutdown, + + .dgram_enqueue = virtio_transport_dgram_enqueue, + .dgram_dequeue = virtio_transport_dgram_dequeue, + .dgram_bind = virtio_transport_dgram_bind, + .dgram_allow = virtio_transport_dgram_allow, + + .stream_enqueue = virtio_transport_stream_enqueue, + .stream_dequeue = virtio_transport_stream_dequeue, + .stream_has_data = virtio_transport_stream_has_data, + .stream_has_space = virtio_transport_stream_has_space, + .stream_rcvhiwat = virtio_transport_stream_rcvhiwat, + .stream_is_active = virtio_transport_stream_is_active, + .stream_allow = virtio_transport_stream_allow, + + .notify_poll_in = virtio_transport_notify_poll_in, + .notify_poll_out = virtio_transport_notify_poll_out, + .notify_recv_init = virtio_transport_notify_recv_init, + .notify_recv_pre_block = virtio_transport_notify_recv_pre_block, + .notify_recv_pre_dequeue = virtio_transport_notify_recv_pre_dequeue, + .notify_recv_post_dequeue = virtio_transport_notify_recv_post_dequeue, + .notify_send_init = virtio_transport_notify_send_init, + .notify_send_pre_block = virtio_transport_notify_send_pre_block, + .notify_send_pre_enqueue = virtio_transport_notify_send_pre_enqueue, + .notify_send_post_enqueue = virtio_transport_notify_send_post_enqueue, + + .set_buffer_size = virtio_transport_set_buffer_size, + .set_min_buffer_size = virtio_transport_set_min_buffer_size, + .set_max_buffer_size = virtio_transport_set_max_buffer_size, + .get_buffer_size = virtio_transport_get_buffer_size, + .get_min_buffer_size = virtio_transport_get_min_buffer_size, + .get_max_buffer_size = virtio_transport_get_max_buffer_size, + }, + + .send_pkt = vhost_transport_send_pkt, +}; + +static int __init vhost_vsock_init(void) +{ + int ret; + + ret = vsock_core_init(&vhost_transport.transport); + if (ret < 0) + return ret; + return misc_register(&vhost_vsock_misc); +}; + +static void __exit vhost_vsock_exit(void) +{ + misc_deregister(&vhost_vsock_misc); + vsock_core_exit(); +}; + +module_init(vhost_vsock_init); +module_exit(vhost_vsock_exit); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Asias He"); +MODULE_DESCRIPTION("vhost transport for vsock "); diff --git a/include/uapi/linux/vhost.h b/include/uapi/linux/vhost.h index 8cb0a65afd64..56b7ab584cc0 100644 --- a/include/uapi/linux/vhost.h +++ b/include/uapi/linux/vhost.h @@ -203,4 +203,9 @@ struct vhost_scsi_target { #define VHOST_SCSI_SET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x43, __u32) #define VHOST_SCSI_GET_EVENTS_MISSED _IOW(VHOST_VIRTIO, 0x44, __u32) +/* VHOST_VSOCK specific defines */ + +#define VHOST_VSOCK_SET_GUEST_CID _IOW(VHOST_VIRTIO, 0x60, __u64) +#define VHOST_VSOCK_SET_RUNNING _IOW(VHOST_VIRTIO, 0x61, int) + #endif -- cgit v1.2.3 From c8d4b9c34caf8525ae8bee32daf743b5adc5a434 Mon Sep 17 00:00:00 2001 From: Asias He Date: Thu, 28 Jul 2016 15:36:35 +0100 Subject: UPSTREAM: VSOCK: Add Makefile and Kconfig Enable virtio-vsock and vhost-vsock. Signed-off-by: Asias He Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin (cherry picked from commit 304ba62fd4e670c1a5784585da0fac9f7309ef6c) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: I0b0f08cd28a94516903dbf3452e5999375e0f85a --- drivers/vhost/Kconfig | 14 ++++++++++++++ drivers/vhost/Makefile | 4 ++++ net/vmw_vsock/Kconfig | 20 ++++++++++++++++++++ net/vmw_vsock/Makefile | 6 ++++++ 4 files changed, 44 insertions(+) diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index 533eaf04f12f..2b5f588f5b1e 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -21,6 +21,20 @@ config VHOST_SCSI Say M here to enable the vhost_scsi TCM fabric module for use with virtio-scsi guests +config VHOST_VSOCK + tristate "vhost virtio-vsock driver" + depends on VSOCKETS && EVENTFD + select VIRTIO_VSOCKETS_COMMON + select VHOST + default n + ---help--- + This kernel module can be loaded in the host kernel to provide AF_VSOCK + sockets for communicating with guests. The guests must have the + virtio_transport.ko driver loaded to use the virtio-vsock device. + + To compile this driver as a module, choose M here: the module will be called + vhost_vsock. + config VHOST_RING tristate ---help--- diff --git a/drivers/vhost/Makefile b/drivers/vhost/Makefile index e0441c34db1c..6b012b986b57 100644 --- a/drivers/vhost/Makefile +++ b/drivers/vhost/Makefile @@ -4,5 +4,9 @@ vhost_net-y := net.o obj-$(CONFIG_VHOST_SCSI) += vhost_scsi.o vhost_scsi-y := scsi.o +obj-$(CONFIG_VHOST_VSOCK) += vhost_vsock.o +vhost_vsock-y := vsock.o + obj-$(CONFIG_VHOST_RING) += vringh.o + obj-$(CONFIG_VHOST) += vhost.o diff --git a/net/vmw_vsock/Kconfig b/net/vmw_vsock/Kconfig index 14810abedc2e..8831e7c42167 100644 --- a/net/vmw_vsock/Kconfig +++ b/net/vmw_vsock/Kconfig @@ -26,3 +26,23 @@ config VMWARE_VMCI_VSOCKETS To compile this driver as a module, choose M here: the module will be called vmw_vsock_vmci_transport. If unsure, say N. + +config VIRTIO_VSOCKETS + tristate "virtio transport for Virtual Sockets" + depends on VSOCKETS && VIRTIO + select VIRTIO_VSOCKETS_COMMON + help + This module implements a virtio transport for Virtual Sockets. + + Enable this transport if your Virtual Machine host supports Virtual + Sockets over virtio. + + To compile this driver as a module, choose M here: the module will be + called vmw_vsock_virtio_transport. If unsure, say N. + +config VIRTIO_VSOCKETS_COMMON + tristate + help + This option is selected by any driver which needs to access + the virtio_vsock. The module will be called + vmw_vsock_virtio_transport_common. diff --git a/net/vmw_vsock/Makefile b/net/vmw_vsock/Makefile index 2ce52d70f224..bc27c70e0e59 100644 --- a/net/vmw_vsock/Makefile +++ b/net/vmw_vsock/Makefile @@ -1,7 +1,13 @@ obj-$(CONFIG_VSOCKETS) += vsock.o obj-$(CONFIG_VMWARE_VMCI_VSOCKETS) += vmw_vsock_vmci_transport.o +obj-$(CONFIG_VIRTIO_VSOCKETS) += vmw_vsock_virtio_transport.o +obj-$(CONFIG_VIRTIO_VSOCKETS_COMMON) += vmw_vsock_virtio_transport_common.o vsock-y += af_vsock.o vsock_addr.o vmw_vsock_vmci_transport-y += vmci_transport.o vmci_transport_notify.o \ vmci_transport_notify_qstate.o + +vmw_vsock_virtio_transport-y += virtio_transport.o + +vmw_vsock_virtio_transport_common-y += virtio_transport_common.o -- cgit v1.2.3 From e3331f90e050e810c312fdda9d135952607684e9 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 1 Aug 2016 23:20:53 +0300 Subject: UPSTREAM: vhost: detect 32 bit integer wrap around Detect and fail early if long wrap around is triggered. Signed-off-by: Michael S. Tsirkin (cherry picked from commit ec33d031a14b3c5dd516627139c9550350dbba3e) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: Id71c1ea0355ce3e403bb5865dc3056d197fe218b --- drivers/vhost/vhost.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index bd3428ce6b9b..154a566f7b97 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -657,6 +657,12 @@ static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz) (sz + VHOST_PAGE_SIZE * 8 - 1) / VHOST_PAGE_SIZE / 8); } +static bool vhost_overflow(u64 uaddr, u64 size) +{ + /* Make sure 64 bit math will not overflow. */ + return uaddr > ULONG_MAX || size > ULONG_MAX || uaddr > ULONG_MAX - size; +} + /* Caller should have vq mutex and device mutex. */ static int vq_memory_access_ok(void __user *log_base, struct vhost_umem *umem, int log_all) @@ -669,9 +675,11 @@ static int vq_memory_access_ok(void __user *log_base, struct vhost_umem *umem, list_for_each_entry(node, &umem->umem_list, link) { unsigned long a = node->userspace_addr; - if (node->size > ULONG_MAX) + if (vhost_overflow(node->userspace_addr, node->size)) return 0; - else if (!access_ok(VERIFY_WRITE, (void __user *)a, + + + if (!access_ok(VERIFY_WRITE, (void __user *)a, node->size)) return 0; else if (log_all && !log_access_ok(log_base, @@ -913,6 +921,10 @@ static int umem_access_ok(u64 uaddr, u64 size, int access) { unsigned long a = uaddr; + /* Make sure 64 bit math will not overflow. */ + if (vhost_overflow(uaddr, size)) + return -EFAULT; + if ((access & VHOST_ACCESS_RO) && !access_ok(VERIFY_READ, (void __user *)a, size)) return -EFAULT; -- cgit v1.2.3 From f328aa45f9bc10286e07bc784195b4f0dac2fe37 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 2 Aug 2016 01:53:13 +0300 Subject: UPSTREAM: vhost: drop vringh dependency vringh isn't used by vhost net or scsi - it's used by CAIF only at the moment. Drop the dependency. Signed-off-by: Michael S. Tsirkin (cherry picked from commit 6190efb08c16dcd68c64b096a28f47ab33f017d7) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Cody Schuffelen Change-Id: I2373bf9a5cd21d350af3aca957df811c6aaeae63 --- drivers/vhost/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index 2b5f588f5b1e..f77f15bd3b0c 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -2,7 +2,6 @@ config VHOST_NET tristate "Host kernel accelerator for virtio net" depends on NET && EVENTFD && (TUN || !TUN) && (MACVTAP || !MACVTAP) select VHOST - select VHOST_RING ---help--- This kernel module can be loaded in host kernel to accelerate guest networking with virtio_net. Not to be confused with virtio_net @@ -15,7 +14,6 @@ config VHOST_SCSI tristate "VHOST_SCSI TCM fabric driver" depends on TARGET_CORE && EVENTFD && m select VHOST - select VHOST_RING default n ---help--- Say M here to enable the vhost_scsi TCM fabric module -- cgit v1.2.3 From 5479d8120dc01caa77ba005a6af1bc1153e337b3 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 2 Aug 2016 01:53:13 +0300 Subject: UPSTREAM: vhost: drop vringh dependency vringh isn't used by vhost net or scsi - it's used by CAIF only at the moment. Drop the dependency. Signed-off-by: Michael S. Tsirkin (cherry picked from commit 6190efb08c16dcd68c64b096a28f47ab33f017d7) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I9db24d3ced664637cffcf27fde8a1c08962bbebe --- drivers/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/Makefile b/drivers/Makefile index 69d2ec997564..a8167ee6d865 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -140,6 +140,7 @@ obj-$(CONFIG_OF) += of/ obj-$(CONFIG_SSB) += ssb/ obj-$(CONFIG_BCMA) += bcma/ obj-$(CONFIG_VHOST_RING) += vhost/ +obj-$(CONFIG_VHOST) += vhost/ obj-$(CONFIG_VLYNQ) += vlynq/ obj-$(CONFIG_STAGING) += staging/ obj-y += platform/ -- cgit v1.2.3 From ae42b74d774a515e1ac604ced5bbb7f48c383d4f Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 2 Aug 2016 03:03:35 +0300 Subject: BACKPORT: vhost: split out vringh Kconfig vringh is pulled in by caif and mic, but the other vhost config does not need to be there. In particular, it makes no sense to have vhost net/scsi/sock under caif/mic. Create a separate Kconfig file and put vringh bits there. Signed-off-by: Michael S. Tsirkin (cherry picked from commit 4d93824561057d54712066544609dfc7453b210f) [astrachan: Backported around no mic driver on 4.4] Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: I6e630228bf91a8569bc665e9ad5d399eca8f7384 --- drivers/net/caif/Kconfig | 2 +- drivers/vhost/Kconfig | 6 ------ drivers/vhost/Kconfig.vringh | 5 +++++ 3 files changed, 6 insertions(+), 7 deletions(-) create mode 100644 drivers/vhost/Kconfig.vringh diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig index 547098086773..f81df91a9ce1 100644 --- a/drivers/net/caif/Kconfig +++ b/drivers/net/caif/Kconfig @@ -52,5 +52,5 @@ config CAIF_VIRTIO The caif driver for CAIF over Virtio. if CAIF_VIRTIO -source "drivers/vhost/Kconfig" +source "drivers/vhost/Kconfig.vringh" endif diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index f77f15bd3b0c..40764ecad9ce 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -33,12 +33,6 @@ config VHOST_VSOCK To compile this driver as a module, choose M here: the module will be called vhost_vsock. -config VHOST_RING - tristate - ---help--- - This option is selected by any driver which needs to access - the host side of a virtio ring. - config VHOST tristate ---help--- diff --git a/drivers/vhost/Kconfig.vringh b/drivers/vhost/Kconfig.vringh new file mode 100644 index 000000000000..6a4490c09d7f --- /dev/null +++ b/drivers/vhost/Kconfig.vringh @@ -0,0 +1,5 @@ +config VHOST_RING + tristate + ---help--- + This option is selected by any driver which needs to access + the host side of a virtio ring. -- cgit v1.2.3 From c1763998238e1247aaf085c12a038fbaeab11305 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 2 Aug 2016 13:50:42 +0000 Subject: UPSTREAM: VSOCK: Use kvfree() Use kvfree() instead of open-coding it. Signed-off-by: Wei Yongjun Signed-off-by: Michael S. Tsirkin (cherry picked from commit b226acab2f6aaa45c2af27279b63f622b23a44bd) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: Ie270449a727baf74ee547137928e166e772b62ad --- drivers/vhost/vsock.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 028ca16c2d36..0ddf3a2dbfc4 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -434,10 +434,7 @@ err: static void vhost_vsock_free(struct vhost_vsock *vsock) { - if (is_vmalloc_addr(vsock)) - vfree(vsock); - else - kfree(vsock); + kvfree(vsock); } static int vhost_vsock_dev_open(struct inode *inode, struct file *file) -- cgit v1.2.3 From fcee01683f588fa81d4239ca67055bfef9e32211 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 4 Aug 2016 14:52:53 +0100 Subject: UPSTREAM: vhost/vsock: fix vhost virtio_vsock_pkt use-after-free Stash the packet length in a local variable before handing over ownership of the packet to virtio_transport_recv_pkt() or virtio_transport_free_pkt(). This patch solves the use-after-free since pkt is no longer guaranteed to be alive. Reported-by: Dan Carpenter Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin (cherry picked from commit 3fda5d6e580193fa005014355b3a61498f1b3ae0) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: I2a6a8b2eb1b647645ff7c76a37f61dce3b0fab9f --- drivers/vhost/vsock.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 0ddf3a2dbfc4..e3b30ea9ece5 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -307,6 +307,8 @@ static void vhost_vsock_handle_tx_kick(struct vhost_work *work) vhost_disable_notify(&vsock->dev, vq); for (;;) { + u32 len; + if (!vhost_vsock_more_replies(vsock)) { /* Stop tx until the device processes already * pending replies. Leave tx virtqueue @@ -334,13 +336,15 @@ static void vhost_vsock_handle_tx_kick(struct vhost_work *work) continue; } + len = pkt->len; + /* Only accept correctly addressed packets */ if (le64_to_cpu(pkt->hdr.src_cid) == vsock->guest_cid) virtio_transport_recv_pkt(pkt); else virtio_transport_free_pkt(pkt); - vhost_add_used(vq, head, sizeof(pkt->hdr) + pkt->len); + vhost_add_used(vq, head, sizeof(pkt->hdr) + len); added = true; } -- cgit v1.2.3 From 36586134a53ec0409d60260f3a84f17b8d2b519b Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Fri, 5 Aug 2016 13:52:09 +0100 Subject: UPSTREAM: virtio-vsock: fix include guard typo Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin (cherry picked from commit 28ad55578b8a76390d966b09da8c7fa3644f5140) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: I79c87359bb06f4f90bc2d2a09971b61a3a381499 --- include/uapi/linux/virtio_vsock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/virtio_vsock.h b/include/uapi/linux/virtio_vsock.h index 6b011c19b50f..1d57ed3d84d2 100644 --- a/include/uapi/linux/virtio_vsock.h +++ b/include/uapi/linux/virtio_vsock.h @@ -32,7 +32,7 @@ */ #ifndef _UAPI_LINUX_VIRTIO_VSOCK_H -#define _UAPI_LINUX_VIRTIO_VOSCK_H +#define _UAPI_LINUX_VIRTIO_VSOCK_H #include #include -- cgit v1.2.3 From 1708b8ff882ce34008a8928ff5ba2c97faae14bb Mon Sep 17 00:00:00 2001 From: Gerard Garcia Date: Wed, 10 Aug 2016 17:24:34 +0200 Subject: UPSTREAM: vhost/vsock: drop space available check for TX vq Remove unnecessary use of enable/disable callback notifications and the incorrect more space available check. The virtio_transport_tx_work handles when the TX virtqueue has more buffers available. Signed-off-by: Gerard Garcia Acked-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin (cherry picked from commit 21bc54fc0cdc31de72b57d2b3c79cf9c2b83cf39) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: Id76bb00fb4393add39d876e29b0e20617c6033e7 --- net/vmw_vsock/virtio_transport.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c index 699dfabdbccd..936d7eee62d0 100644 --- a/net/vmw_vsock/virtio_transport.c +++ b/net/vmw_vsock/virtio_transport.c @@ -87,9 +87,6 @@ virtio_transport_send_pkt_work(struct work_struct *work) vq = vsock->vqs[VSOCK_VQ_TX]; - /* Avoid unnecessary interrupts while we're processing the ring */ - virtqueue_disable_cb(vq); - for (;;) { struct virtio_vsock_pkt *pkt; struct scatterlist hdr, buf, *sgs[2]; @@ -99,7 +96,6 @@ virtio_transport_send_pkt_work(struct work_struct *work) spin_lock_bh(&vsock->send_pkt_list_lock); if (list_empty(&vsock->send_pkt_list)) { spin_unlock_bh(&vsock->send_pkt_list_lock); - virtqueue_enable_cb(vq); break; } @@ -118,13 +114,13 @@ virtio_transport_send_pkt_work(struct work_struct *work) } ret = virtqueue_add_sgs(vq, sgs, out_sg, in_sg, pkt, GFP_KERNEL); + /* Usually this means that there is no more space available in + * the vq + */ if (ret < 0) { spin_lock_bh(&vsock->send_pkt_list_lock); list_add(&pkt->list, &vsock->send_pkt_list); spin_unlock_bh(&vsock->send_pkt_list_lock); - - if (!virtqueue_enable_cb(vq) && ret == -ENOSPC) - continue; /* retry now that we have more space */ break; } -- cgit v1.2.3 From b3426d61a5625190a7a5609c06a76dd02733097c Mon Sep 17 00:00:00 2001 From: Jorgen Hansen Date: Mon, 26 Sep 2016 23:59:53 -0700 Subject: UPSTREAM: VSOCK: Don't dec ack backlog twice for rejected connections If a pending socket is marked as rejected, we will decrease the sk_ack_backlog twice. So don't decrement it for rejected sockets in vsock_pending_work(). Testing of the rejected socket path was done through code modifications. Reported-by: Stefan Hajnoczi Signed-off-by: Jorgen Hansen Reviewed-by: Adit Ranadive Reviewed-by: Aditya Sarwade Signed-off-by: David S. Miller (cherry picked from commit 1190cfdb1a19d89561ae51cff7d9c2ead24b3ebe) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: Ic610a13e81f53fc570e037d0685c1263dc646e70 --- net/vmw_vsock/af_vsock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index db7c6615371b..d646359bbf6d 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -465,6 +465,8 @@ static void vsock_pending_work(struct work_struct *work) if (vsock_is_pending(sk)) { vsock_remove_pending(listener, sk); + + listener->sk_ack_backlog--; } else if (!vsk->rejected) { /* We are not on the pending list and accept() did not reject * us, so we must have been accepted by our user process. We @@ -475,8 +477,6 @@ static void vsock_pending_work(struct work_struct *work) goto out; } - listener->sk_ack_backlog--; - /* We need to remove ourself from the global connected sockets list so * incoming packets can't find this socket, and to reduce the reference * count. @@ -2006,5 +2006,5 @@ EXPORT_SYMBOL_GPL(vsock_core_get_transport); MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMware Virtual Socket Family"); -MODULE_VERSION("1.0.1.0-k"); +MODULE_VERSION("1.0.2.0-k"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 4433966abe39e822b4e14b0347acb8bb65f01704 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 6 Dec 2016 06:07:15 +0200 Subject: UPSTREAM: vsock/virtio: fix src/dst cid format commit f83f12d660d11718d3eed9d979ee03e83aa55544 upstream. These fields are 64 bit, using le32_to_cpu and friends on these will not do the right thing. Fix this up. Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman (cherry picked from commit e80ceb2da52e0aae8e0ae9632c3abbfdd579cf61) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: Ieccae61162243040f9ad29dc465a50be7f45ee62 --- net/vmw_vsock/virtio_transport_common.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c index a53b3a16b4f1..62c056ea403b 100644 --- a/net/vmw_vsock/virtio_transport_common.c +++ b/net/vmw_vsock/virtio_transport_common.c @@ -606,9 +606,9 @@ static int virtio_transport_reset_no_sock(struct virtio_vsock_pkt *pkt) return 0; pkt = virtio_transport_alloc_pkt(&info, 0, - le32_to_cpu(pkt->hdr.dst_cid), + le64_to_cpu(pkt->hdr.dst_cid), le32_to_cpu(pkt->hdr.dst_port), - le32_to_cpu(pkt->hdr.src_cid), + le64_to_cpu(pkt->hdr.src_cid), le32_to_cpu(pkt->hdr.src_port)); if (!pkt) return -ENOMEM; @@ -823,7 +823,7 @@ virtio_transport_send_response(struct vsock_sock *vsk, struct virtio_vsock_pkt_info info = { .op = VIRTIO_VSOCK_OP_RESPONSE, .type = VIRTIO_VSOCK_TYPE_STREAM, - .remote_cid = le32_to_cpu(pkt->hdr.src_cid), + .remote_cid = le64_to_cpu(pkt->hdr.src_cid), .remote_port = le32_to_cpu(pkt->hdr.src_port), .reply = true, }; @@ -863,9 +863,9 @@ virtio_transport_recv_listen(struct sock *sk, struct virtio_vsock_pkt *pkt) child->sk_state = SS_CONNECTED; vchild = vsock_sk(child); - vsock_addr_init(&vchild->local_addr, le32_to_cpu(pkt->hdr.dst_cid), + vsock_addr_init(&vchild->local_addr, le64_to_cpu(pkt->hdr.dst_cid), le32_to_cpu(pkt->hdr.dst_port)); - vsock_addr_init(&vchild->remote_addr, le32_to_cpu(pkt->hdr.src_cid), + vsock_addr_init(&vchild->remote_addr, le64_to_cpu(pkt->hdr.src_cid), le32_to_cpu(pkt->hdr.src_port)); vsock_insert_connected(vchild); @@ -904,9 +904,9 @@ void virtio_transport_recv_pkt(struct virtio_vsock_pkt *pkt) struct sock *sk; bool space_available; - vsock_addr_init(&src, le32_to_cpu(pkt->hdr.src_cid), + vsock_addr_init(&src, le64_to_cpu(pkt->hdr.src_cid), le32_to_cpu(pkt->hdr.src_port)); - vsock_addr_init(&dst, le32_to_cpu(pkt->hdr.dst_cid), + vsock_addr_init(&dst, le64_to_cpu(pkt->hdr.dst_cid), le32_to_cpu(pkt->hdr.dst_port)); trace_virtio_transport_recv_pkt(src.svm_cid, src.svm_port, -- cgit v1.2.3 From e1a839896df5e654f733dc3573c68a8e16f58d74 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Fri, 9 Dec 2016 01:10:46 +0800 Subject: UPSTREAM: vhost-vsock: fix orphan connection reset local_addr.svm_cid is host cid. We should check guest cid instead, which is remote_addr.svm_cid. Otherwise we end up resetting all connections to all guests. Cc: stable@vger.kernel.org [4.8+] Reviewed-by: Stefan Hajnoczi Signed-off-by: Peng Tao Signed-off-by: David S. Miller (cherry picked from commit c4587631c7bad47c045e081d1553cd73a23be59a) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: Ib9bf9e1f0befa71f4ebc0ff0cdcef7115a41b110 --- drivers/vhost/vsock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index e3b30ea9ece5..a504e2e003da 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -506,7 +506,7 @@ static void vhost_vsock_reset_orphans(struct sock *sk) * executing. */ - if (!vhost_vsock_get(vsk->local_addr.svm_cid)) { + if (!vhost_vsock_get(vsk->remote_addr.svm_cid)) { sock_set_flag(sk, SOCK_DONE); vsk->peer_shutdown = SHUTDOWN_MASK; sk->sk_state = SS_UNCONNECTED; -- cgit v1.2.3 From 68f96127aa7dcfbf9068d8e8e79bc0e8ee1156d7 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Wed, 14 Dec 2016 19:24:36 +0800 Subject: UPSTREAM: vsock: lookup and setup guest_cid inside vhost_vsock_lock [ Upstream commit 6c083c2b8a0a110cad936bc0a2c089f0d8115175 ] Multi vsocks may setup the same cid at the same time. Signed-off-by: Gao feng Signed-off-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi Signed-off-by: Sasha Levin (cherry picked from commit 2d5a1b31799efcd37a57fe4d2f492d8dc2a0a334) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: Ic2fa852a2080a4df1cb3b823c02d65a354c15b34 --- drivers/vhost/vsock.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index a504e2e003da..4db3a487867a 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -50,11 +50,10 @@ static u32 vhost_transport_get_local_cid(void) return VHOST_VSOCK_DEFAULT_HOST_CID; } -static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) +static struct vhost_vsock *__vhost_vsock_get(u32 guest_cid) { struct vhost_vsock *vsock; - spin_lock_bh(&vhost_vsock_lock); list_for_each_entry(vsock, &vhost_vsock_list, list) { u32 other_cid = vsock->guest_cid; @@ -63,15 +62,24 @@ static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) continue; if (other_cid == guest_cid) { - spin_unlock_bh(&vhost_vsock_lock); return vsock; } } - spin_unlock_bh(&vhost_vsock_lock); return NULL; } +static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) +{ + struct vhost_vsock *vsock; + + spin_lock_bh(&vhost_vsock_lock); + vsock = __vhost_vsock_get(guest_cid); + spin_unlock_bh(&vhost_vsock_lock); + + return vsock; +} + static void vhost_transport_do_send_pkt(struct vhost_vsock *vsock, struct vhost_virtqueue *vq) @@ -562,11 +570,12 @@ static int vhost_vsock_set_cid(struct vhost_vsock *vsock, u64 guest_cid) return -EINVAL; /* Refuse if CID is already in use */ - other = vhost_vsock_get(guest_cid); - if (other && other != vsock) - return -EADDRINUSE; - spin_lock_bh(&vhost_vsock_lock); + other = __vhost_vsock_get(guest_cid); + if (other && other != vsock) { + spin_unlock_bh(&vhost_vsock_lock); + return -EADDRINUSE; + } vsock->guest_cid = guest_cid; spin_unlock_bh(&vhost_vsock_lock); -- cgit v1.2.3 From a81e09a33fd40b70db39d08031e6b5580d19e2f4 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 19 Jan 2017 10:43:53 +0000 Subject: UPSTREAM: vhost/vsock: handle vhost_vq_init_access() error [ Upstream commit 0516ffd88fa0d006ee80389ce14a9ca5ae45e845 ] Propagate the error when vhost_vq_init_access() fails and set vq->private_data to NULL. Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman (cherry picked from commit ae36f6a65af6f4eaca01cc5b68d8ecb266dbcc17) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: I1e062ae003b92d000967921014a31bfc574632d8 --- drivers/vhost/vsock.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 4db3a487867a..e398a4dbba59 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -376,6 +376,7 @@ static void vhost_vsock_handle_rx_kick(struct vhost_work *work) static int vhost_vsock_start(struct vhost_vsock *vsock) { + struct vhost_virtqueue *vq; size_t i; int ret; @@ -386,19 +387,20 @@ static int vhost_vsock_start(struct vhost_vsock *vsock) goto err; for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) { - struct vhost_virtqueue *vq = &vsock->vqs[i]; + vq = &vsock->vqs[i]; mutex_lock(&vq->mutex); if (!vhost_vq_access_ok(vq)) { ret = -EFAULT; - mutex_unlock(&vq->mutex); goto err_vq; } if (!vq->private_data) { vq->private_data = vsock; - vhost_vq_init_access(vq); + ret = vhost_vq_init_access(vq); + if (ret) + goto err_vq; } mutex_unlock(&vq->mutex); @@ -408,8 +410,11 @@ static int vhost_vsock_start(struct vhost_vsock *vsock) return 0; err_vq: + vq->private_data = NULL; + mutex_unlock(&vq->mutex); + for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) { - struct vhost_virtqueue *vq = &vsock->vqs[i]; + vq = &vsock->vqs[i]; mutex_lock(&vq->mutex); vq->private_data = NULL; -- cgit v1.2.3 From 78a8383251060fd136295824dd55711b33f1c073 Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Mon, 30 Jan 2017 11:09:36 +0100 Subject: UPSTREAM: vhost: fix initialization for vq->is_le commit cda8bba0f99d25d2061c531113c14fa41effc3ae upstream. Currently, under certain circumstances vhost_init_is_le does just a part of the initialization job, and depends on vhost_reset_is_le being called too. For this reason vhost_vq_init_access used to call vhost_reset_is_le when vq->private_data is NULL. This is not only counter intuitive, but also real a problem because it breaks vhost_net. The bug was introduced to vhost_net with commit 2751c9882b94 ("vhost: cross-endian support for legacy devices"). The symptom is corruption of the vq's used.idx field (virtio) after VHOST_NET_SET_BACKEND was issued as a part of the vhost shutdown on a vq with pending descriptors. Let us make sure the outcome of vhost_init_is_le never depend on the state it is actually supposed to initialize, and fix virtio_net by removing the reset from vhost_vq_init_access. With the above, there is no reason for vhost_reset_is_le to do just half of the job. Let us make vhost_reset_is_le reinitialize is_le. Signed-off-by: Halil Pasic Reported-by: Michael A. Tebolt Reported-by: Dr. David Alan Gilbert Fixes: commit 2751c9882b94 ("vhost: cross-endian support for legacy devices") Signed-off-by: Michael S. Tsirkin Reviewed-by: Greg Kurz Tested-by: Michael A. Tebolt Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 1594edd9ea0d75ef106bffc23c2b07b509f3301c) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I5436f3410dc32fe059c904c8001fbe05feae756d --- drivers/vhost/vhost.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 154a566f7b97..80013975cfac 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -131,14 +131,14 @@ static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx, static void vhost_init_is_le(struct vhost_virtqueue *vq) { - if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) - vq->is_le = true; + vq->is_le = vhost_has_feature(vq, VIRTIO_F_VERSION_1) + || virtio_legacy_is_little_endian(); } #endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ static void vhost_reset_is_le(struct vhost_virtqueue *vq) { - vq->is_le = virtio_legacy_is_little_endian(); + vhost_init_is_le(vq); } struct vhost_flush_struct { @@ -1714,10 +1714,8 @@ int vhost_vq_init_access(struct vhost_virtqueue *vq) int r; bool is_le = vq->is_le; - if (!vq->private_data) { - vhost_reset_is_le(vq); + if (!vq->private_data) return 0; - } vhost_init_is_le(vq); -- cgit v1.2.3 From 45b7ae6f4d24f17a3a698069f7083110407dc5fa Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Wed, 15 Mar 2017 09:32:14 +0800 Subject: UPSTREAM: vsock: track pkt owner vsock [ Upstream commit 36d277bac8080202684e67162ebb157f16631581 ] So that we can cancel a queued pkt later if necessary. Signed-off-by: Peng Tao Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 6f1848e778d9a9f9dd89abee53d2a688277d1784) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: I29b8bacf06eaf57a91291c1d088802c0dea7fed0 --- include/linux/virtio_vsock.h | 3 +++ net/vmw_vsock/virtio_transport_common.c | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h index 9638bfeb0d1f..584f9a647ad4 100644 --- a/include/linux/virtio_vsock.h +++ b/include/linux/virtio_vsock.h @@ -48,6 +48,8 @@ struct virtio_vsock_pkt { struct virtio_vsock_hdr hdr; struct work_struct work; struct list_head list; + /* socket refcnt not held, only use for cancellation */ + struct vsock_sock *vsk; void *buf; u32 len; u32 off; @@ -56,6 +58,7 @@ struct virtio_vsock_pkt { struct virtio_vsock_pkt_info { u32 remote_cid, remote_port; + struct vsock_sock *vsk; struct msghdr *msg; u32 pkt_len; u16 type; diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c index 62c056ea403b..9c07c76c504d 100644 --- a/net/vmw_vsock/virtio_transport_common.c +++ b/net/vmw_vsock/virtio_transport_common.c @@ -57,6 +57,7 @@ virtio_transport_alloc_pkt(struct virtio_vsock_pkt_info *info, pkt->len = len; pkt->hdr.len = cpu_to_le32(len); pkt->reply = info->reply; + pkt->vsk = info->vsk; if (info->msg && len > 0) { pkt->buf = kmalloc(len, GFP_KERNEL); @@ -180,6 +181,7 @@ static int virtio_transport_send_credit_update(struct vsock_sock *vsk, struct virtio_vsock_pkt_info info = { .op = VIRTIO_VSOCK_OP_CREDIT_UPDATE, .type = type, + .vsk = vsk, }; return virtio_transport_send_pkt_info(vsk, &info); @@ -519,6 +521,7 @@ int virtio_transport_connect(struct vsock_sock *vsk) struct virtio_vsock_pkt_info info = { .op = VIRTIO_VSOCK_OP_REQUEST, .type = VIRTIO_VSOCK_TYPE_STREAM, + .vsk = vsk, }; return virtio_transport_send_pkt_info(vsk, &info); @@ -534,6 +537,7 @@ int virtio_transport_shutdown(struct vsock_sock *vsk, int mode) VIRTIO_VSOCK_SHUTDOWN_RCV : 0) | (mode & SEND_SHUTDOWN ? VIRTIO_VSOCK_SHUTDOWN_SEND : 0), + .vsk = vsk, }; return virtio_transport_send_pkt_info(vsk, &info); @@ -560,6 +564,7 @@ virtio_transport_stream_enqueue(struct vsock_sock *vsk, .type = VIRTIO_VSOCK_TYPE_STREAM, .msg = msg, .pkt_len = len, + .vsk = vsk, }; return virtio_transport_send_pkt_info(vsk, &info); @@ -581,6 +586,7 @@ static int virtio_transport_reset(struct vsock_sock *vsk, .op = VIRTIO_VSOCK_OP_RST, .type = VIRTIO_VSOCK_TYPE_STREAM, .reply = !!pkt, + .vsk = vsk, }; /* Send RST only if the original pkt is not a RST pkt */ @@ -826,6 +832,7 @@ virtio_transport_send_response(struct vsock_sock *vsk, .remote_cid = le64_to_cpu(pkt->hdr.src_cid), .remote_port = le32_to_cpu(pkt->hdr.src_port), .reply = true, + .vsk = vsk, }; return virtio_transport_send_pkt_info(vsk, &info); -- cgit v1.2.3 From 50c1c72f8986a816f375508833bae177bd7f34ac Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Wed, 15 Mar 2017 09:32:15 +0800 Subject: UPSTREAM: vhost-vsock: add pkt cancel capability [ Upstream commit 16320f363ae128d9b9c70e60f00f2a572f57c23d ] To allow canceling all packets of a connection. Reviewed-by: Stefan Hajnoczi Reviewed-by: Jorgen Hansen Signed-off-by: Peng Tao Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 482b3f92aea249b031ba0bc24df73f3c48f1f5c2) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: I1a06010bbcbcf03e1557d053b773cd6a2c1c0b02 --- drivers/vhost/vsock.c | 41 +++++++++++++++++++++++++++++++++++++++++ include/net/af_vsock.h | 3 +++ 2 files changed, 44 insertions(+) diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index e398a4dbba59..6bca57896915 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -226,6 +226,46 @@ vhost_transport_send_pkt(struct virtio_vsock_pkt *pkt) return len; } +static int +vhost_transport_cancel_pkt(struct vsock_sock *vsk) +{ + struct vhost_vsock *vsock; + struct virtio_vsock_pkt *pkt, *n; + int cnt = 0; + LIST_HEAD(freeme); + + /* Find the vhost_vsock according to guest context id */ + vsock = vhost_vsock_get(vsk->remote_addr.svm_cid); + if (!vsock) + return -ENODEV; + + spin_lock_bh(&vsock->send_pkt_list_lock); + list_for_each_entry_safe(pkt, n, &vsock->send_pkt_list, list) { + if (pkt->vsk != vsk) + continue; + list_move(&pkt->list, &freeme); + } + spin_unlock_bh(&vsock->send_pkt_list_lock); + + list_for_each_entry_safe(pkt, n, &freeme, list) { + if (pkt->reply) + cnt++; + list_del(&pkt->list); + virtio_transport_free_pkt(pkt); + } + + if (cnt) { + struct vhost_virtqueue *tx_vq = &vsock->vqs[VSOCK_VQ_TX]; + int new_cnt; + + new_cnt = atomic_sub_return(cnt, &vsock->queued_replies); + if (new_cnt + cnt >= tx_vq->num && new_cnt < tx_vq->num) + vhost_poll_queue(&tx_vq->poll); + } + + return 0; +} + static struct virtio_vsock_pkt * vhost_vsock_alloc_pkt(struct vhost_virtqueue *vq, unsigned int out, unsigned int in) @@ -678,6 +718,7 @@ static struct virtio_transport vhost_transport = { .release = virtio_transport_release, .connect = virtio_transport_connect, .shutdown = virtio_transport_shutdown, + .cancel_pkt = vhost_transport_cancel_pkt, .dgram_enqueue = virtio_transport_dgram_enqueue, .dgram_dequeue = virtio_transport_dgram_dequeue, diff --git a/include/net/af_vsock.h b/include/net/af_vsock.h index e6675f79b925..f38fe1c00564 100644 --- a/include/net/af_vsock.h +++ b/include/net/af_vsock.h @@ -100,6 +100,9 @@ struct vsock_transport { void (*destruct)(struct vsock_sock *); void (*release)(struct vsock_sock *); + /* Cancel all pending packets sent on vsock. */ + int (*cancel_pkt)(struct vsock_sock *vsk); + /* Connections. */ int (*connect)(struct vsock_sock *); -- cgit v1.2.3 From 9c3fb44f493e7db4fb760cb0f4ab0a72526223ac Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Wed, 15 Mar 2017 09:32:17 +0800 Subject: UPSTREAM: vsock: cancel packets when failing to connect [ Upstream commit 380feae0def7e6a115124a3219c3ec9b654dca32 ] Otherwise we'll leave the packets queued until releasing vsock device. E.g., if guest is slow to start up, resulting ETIMEDOUT on connect, guest will get the connect requests from failed host sockets. Reviewed-by: Stefan Hajnoczi Reviewed-by: Jorgen Hansen Signed-off-by: Peng Tao Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 98d20e5902667f9b44a75116041a630823f81e46) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: I0685ec15925c662d4a51cdd24fc4f26a8c7ff723 --- net/vmw_vsock/af_vsock.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index d646359bbf6d..7e3c04eb01ee 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1104,10 +1104,19 @@ static const struct proto_ops vsock_dgram_ops = { .sendpage = sock_no_sendpage, }; +static int vsock_transport_cancel_pkt(struct vsock_sock *vsk) +{ + if (!transport->cancel_pkt) + return -EOPNOTSUPP; + + return transport->cancel_pkt(vsk); +} + static void vsock_connect_timeout(struct work_struct *work) { struct sock *sk; struct vsock_sock *vsk; + int cancel = 0; vsk = container_of(work, struct vsock_sock, connect_work.work); sk = sk_vsock(vsk); @@ -1118,8 +1127,11 @@ static void vsock_connect_timeout(struct work_struct *work) sk->sk_state = SS_UNCONNECTED; sk->sk_err = ETIMEDOUT; sk->sk_error_report(sk); + cancel = 1; } release_sock(sk); + if (cancel) + vsock_transport_cancel_pkt(vsk); sock_put(sk); } @@ -1224,11 +1236,13 @@ static int vsock_stream_connect(struct socket *sock, struct sockaddr *addr, err = sock_intr_errno(timeout); sk->sk_state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED; + vsock_transport_cancel_pkt(vsk); goto out_wait; } else if (timeout == 0) { err = -ETIMEDOUT; sk->sk_state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED; + vsock_transport_cancel_pkt(vsk); goto out_wait; } -- cgit v1.2.3 From a4cfce2ff22b0248c80e320e3b25a6e4c3e3618a Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Fri, 19 May 2017 11:21:59 -0700 Subject: UPSTREAM: vsock: use new wait API for vsock_stream_sendmsg() commit 499fde662f1957e3cb8d192a94a099ebe19c714b upstream. As reported by Michal, vsock_stream_sendmsg() could still sleep at vsock_stream_has_space() after prepare_to_wait(): vsock_stream_has_space vmci_transport_stream_has_space vmci_qpair_produce_free_space qp_lock qp_acquire_queue_mutex mutex_lock Just switch to the new wait API like we did for commit d9dc8b0f8b4e ("net: fix sleeping for sk_wait_event()"). Reported-by: Michal Kubecek Cc: Stefan Hajnoczi Cc: Jorgen Hansen Cc: "Michael S. Tsirkin" Cc: Claudio Imbrenda Signed-off-by: Cong Wang Reviewed-by: Stefan Hajnoczi Signed-off-by: David S. Miller Cc: "Jorgen S. Hansen" Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 6be6e48daabc18858a0a5a9d18fbd399714fc9e4) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: Ie0ac0685071c2034c9565e2554ff5e41f6cfd619 --- net/vmw_vsock/af_vsock.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index 7e3c04eb01ee..7566395e526d 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c @@ -1585,7 +1585,7 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg, while (total_written < len) { ssize_t written; - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); + add_wait_queue(sk_sleep(sk), &wait); while (vsock_stream_has_space(vsk) == 0 && sk->sk_err == 0 && !(sk->sk_shutdown & SEND_SHUTDOWN) && @@ -1594,13 +1594,13 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg, /* Don't wait for non-blocking sockets. */ if (timeout == 0) { err = -EAGAIN; - finish_wait(sk_sleep(sk), &wait); + remove_wait_queue(sk_sleep(sk), &wait); goto out_err; } err = transport->notify_send_pre_block(vsk, &send_data); if (err < 0) { - finish_wait(sk_sleep(sk), &wait); + remove_wait_queue(sk_sleep(sk), &wait); goto out_err; } @@ -1609,15 +1609,15 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg, lock_sock(sk); if (signal_pending(current)) { err = sock_intr_errno(timeout); - finish_wait(sk_sleep(sk), &wait); + remove_wait_queue(sk_sleep(sk), &wait); goto out_err; } else if (timeout == 0) { err = -EAGAIN; - finish_wait(sk_sleep(sk), &wait); + remove_wait_queue(sk_sleep(sk), &wait); goto out_err; } } - finish_wait(sk_sleep(sk), &wait); + remove_wait_queue(sk_sleep(sk), &wait); /* These checks occur both as part of and after the loop * conditional since we need to check before and after -- cgit v1.2.3 From 985ea57dc3a31a144de5d35b59e475fe0a793a6d Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Tue, 5 Sep 2017 09:22:05 +0800 Subject: UPSTREAM: vhost_net: correctly check tx avail during rx busy polling [ Upstream commit 8b949bef9172ca69d918e93509a4ecb03d0355e0 ] We check tx avail through vhost_enable_notify() in the past which is wrong since it only checks whether or not guest has filled more available buffer since last avail idx synchronization which was just done by vhost_vq_avail_empty() before. What we really want is checking pending buffers in the avail ring. Fix this by calling vhost_vq_avail_empty() instead. This issue could be noticed by doing netperf TCP_RR benchmark as client from guest (but not host). With this fix, TCP_RR from guest to localhost restores from 1375.91 trans per sec to 55235.28 trans per sec on my laptop (Intel(R) Core(TM) i7-5600U CPU @ 2.60GHz). Fixes: 030881372460 ("vhost_net: basic polling support") Signed-off-by: Jason Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit f5755c0e870056dd35c95a0b5c0a038cdb4382ee) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: Ia61d229fb5c82e64fd1c30aff06a9f938d20e467 --- drivers/vhost/net.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 77e94ecfd608..4b3cae02c0dc 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -523,8 +523,13 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) preempt_enable(); - if (vhost_enable_notify(&net->dev, vq)) + if (!vhost_vq_avail_empty(&net->dev, vq)) vhost_poll_queue(&vq->poll); + else if (unlikely(vhost_enable_notify(&net->dev, vq))) { + vhost_disable_notify(&net->dev, vq); + vhost_poll_queue(&vq->poll); + } + mutex_unlock(&vq->mutex); len = peek_head_len(sk); -- cgit v1.2.3 From ed82fd228695573d34fc3d556f6ce16f73b36131 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 9 Nov 2017 13:29:10 +0000 Subject: UPSTREAM: vhost/vsock: fix uninitialized vhost_vsock->guest_cid commit a72b69dc083a931422cc8a5e33841aff7d5312f2 upstream. The vhost_vsock->guest_cid field is uninitialized when /dev/vhost-vsock is opened until the VHOST_VSOCK_SET_GUEST_CID ioctl is called. kvmalloc(..., GFP_KERNEL | __GFP_RETRY_MAYFAIL) does not zero memory. All other vhost_vsock fields are initialized explicitly so just initialize this field too. Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin Cc: Daniel Verkamp Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 258d8549b55e2cd5d73d9ff3d18b39aeeab08e1f) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I230006942ceb015f6549449160205cbb501b8fa6 --- drivers/vhost/vsock.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 6bca57896915..e6ba768ab01c 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -516,6 +516,8 @@ static int vhost_vsock_dev_open(struct inode *inode, struct file *file) goto out; } + vsock->guest_cid = 0; /* no CID assigned yet */ + atomic_set(&vsock->queued_replies, 0); vqs[VSOCK_VQ_TX] = &vsock->vqs[VSOCK_VQ_TX]; -- cgit v1.2.3 From a0268535ed1bf4cd7ea1146ada12a387bc4693cc Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Tue, 23 Jan 2018 17:27:25 +0800 Subject: UPSTREAM: vhost: use mutex_lock_nested() in vhost_dev_lock_vqs() commit e9cb4239134c860e5f92c75bf5321bd377bb505b upstream. We used to call mutex_lock() in vhost_dev_lock_vqs() which tries to hold mutexes of all virtqueues. This may confuse lockdep to report a possible deadlock because of trying to hold locks belong to same class. Switch to use mutex_lock_nested() to avoid false positive. Fixes: 6b1e6cc7855b0 ("vhost: new device IOTLB API") Reported-by: syzbot+dbb7c1161485e61b0241@syzkaller.appspotmail.com Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit bd3ccdc6f922c6b7db4b7075d1b6596ddb986a98) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I20829e721706c10ef1696de0d78dd99110e40a6b --- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 80013975cfac..854eb40f019d 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -849,7 +849,7 @@ static void vhost_dev_lock_vqs(struct vhost_dev *d) { int i = 0; for (i = 0; i < d->nvqs; ++i) - mutex_lock(&d->vqs[i]->mutex); + mutex_lock_nested(&d->vqs[i]->mutex, i); } static void vhost_dev_unlock_vqs(struct vhost_dev *d) -- cgit v1.2.3 From 5cea8d1e2612e73cbec853318f242e7363f09d38 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 26 Mar 2018 16:10:23 +0800 Subject: UPSTREAM: vhost_net: add missing lock nesting notation [ Upstream commit aaa3149bbee9ba9b4e6f0bd6e3e7d191edeae942 ] We try to hold TX virtqueue mutex in vhost_net_rx_peek_head_len() after RX virtqueue mutex is held in handle_rx(). This requires an appropriate lock nesting notation to calm down deadlock detector. Fixes: 0308813724606 ("vhost_net: basic polling support") Reported-by: syzbot+7f073540b1384a614e09@syzkaller.appspotmail.com Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 1cb81756b7c3813f7d65d3c6bb1133cb53b69775) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: Ia72badca8f5f92095cfad91051fe47f76e6b03b7 --- drivers/vhost/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 4b3cae02c0dc..53cf130922f3 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -510,7 +510,7 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) if (!len && vq->busyloop_timeout) { /* Both tx vq and rx socket were polled here */ - mutex_lock(&vq->mutex); + mutex_lock_nested(&vq->mutex, 1); vhost_disable_notify(&net->dev, vq); preempt_disable(); @@ -643,7 +643,7 @@ static void handle_rx(struct vhost_net *net) struct iov_iter fixup; __virtio16 num_buffers; - mutex_lock(&vq->mutex); + mutex_lock_nested(&vq->mutex, 0); sock = vq->private_data; if (!sock) goto out; -- cgit v1.2.3 From 9a4bbdf47809d225c54647945e81bb79a26839e5 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 29 Mar 2018 16:00:04 +0800 Subject: UPSTREAM: vhost: validate log when IOTLB is enabled [ Upstream commit d65026c6c62e7d9616c8ceb5a53b68bcdc050525 ] Vq log_base is the userspace address of bitmap which has nothing to do with IOTLB. So it needs to be validated unconditionally otherwise we may try use 0 as log_base which may lead to pin pages that will lead unexpected result (e.g trigger BUG_ON() in set_bit_to_user()). Fixes: 6b1e6cc7855b0 ("vhost: new device IOTLB API") Reported-by: syzbot+6304bf97ef436580fede@syzkaller.appspotmail.com Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 992dbb1d5a653c49a7f2159f75d9cda0d8248f1f) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I64ef687ec8f55800ce300d0a0eac5473853bf6fd --- drivers/vhost/vhost.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 854eb40f019d..6f4c7d2d82b4 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1176,14 +1176,12 @@ static int vq_log_access_ok(struct vhost_virtqueue *vq, /* Caller should have vq mutex and device mutex */ int vhost_vq_access_ok(struct vhost_virtqueue *vq) { - if (vq->iotlb) { - /* When device IOTLB was used, the access validation - * will be validated during prefetching. - */ - return 1; - } - return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used) && - vq_log_access_ok(vq, vq->log_base); + int ret = vq_log_access_ok(vq, vq->log_base); + + if (ret || vq->iotlb) + return ret; + + return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used); } EXPORT_SYMBOL_GPL(vhost_vq_access_ok); -- cgit v1.2.3 From b8efb9dab82bcb5d99de667f0aff23fb2d341c35 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 11 Apr 2018 10:35:40 +0800 Subject: UPSTREAM: vhost: fix vhost_vq_access_ok() log check [ Upstream commit d14d2b78090c7de0557362b26a4ca591aa6a9faa ] Commit d65026c6c62e7d9616c8ceb5a53b68bcdc050525 ("vhost: validate log when IOTLB is enabled") introduced a regression. The logic was originally: if (vq->iotlb) return 1; return A && B; After the patch the short-circuit logic for A was inverted: if (A || vq->iotlb) return A; return B; This patch fixes the regression by rewriting the checks in the obvious way, no longer returning A when vq->iotlb is non-NULL (which is hard to understand). Reported-by: syzbot+65a84dde0214b0387ccd@syzkaller.appspotmail.com Cc: Jason Wang Signed-off-by: Stefan Hajnoczi Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 72de9891b5f46f1f98e7e6243c47076a4b4daa3c) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I63938aaa9f1cf44e4eb1a18693f8c7963eff927e --- drivers/vhost/vhost.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 6f4c7d2d82b4..12a01bc51cd5 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1176,10 +1176,12 @@ static int vq_log_access_ok(struct vhost_virtqueue *vq, /* Caller should have vq mutex and device mutex */ int vhost_vq_access_ok(struct vhost_virtqueue *vq) { - int ret = vq_log_access_ok(vq, vq->log_base); + if (!vq_log_access_ok(vq, vq->log_base)) + return 0; - if (ret || vq->iotlb) - return ret; + /* Access validation occurs at prefetch time with IOTLB */ + if (vq->iotlb) + return 1; return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used); } -- cgit v1.2.3 From 7c3c250679335a3091edf6c62faf37efe3fc4919 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sat, 12 May 2018 00:33:10 +0300 Subject: UPSTREAM: vhost: fix info leak due to uninitialized memory commit 670ae9caaca467ea1bfd325cb2a5c98ba87f94ad upstream. struct vhost_msg within struct vhost_msg_node is copied to userspace. Unfortunately it turns out on 64 bit systems vhost_msg has padding after type which gcc doesn't initialize, leaking 4 uninitialized bytes to userspace. This padding also unfortunately means 32 bit users of this interface are broken on a 64 bit kernel which will need to be fixed separately. Fixes: CVE-2018-1118 Cc: stable@vger.kernel.org Reported-by: Kevin Easton Signed-off-by: Michael S. Tsirkin Reported-by: syzbot+87cfa083e727a224754b@syzkaller.appspotmail.com Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 9681c3bdb098f6c87a0422b6b63912c1b90ad197) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: Ie5a29c3946792ae0f20e04015ba28c89fd90becb --- drivers/vhost/vhost.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 12a01bc51cd5..fb94b311f498 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -2296,6 +2296,9 @@ struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type) struct vhost_msg_node *node = kmalloc(sizeof *node, GFP_KERNEL); if (!node) return NULL; + + /* Make sure all padding within the structure is initialized. */ + memset(&node->msg, 0, sizeof node->msg); node->vq = vq; node->msg.type = type; return node; -- cgit v1.2.3 From 6047fda803094705151431a00ec20f58c4818eed Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Tue, 22 May 2018 19:58:57 +0800 Subject: UPSTREAM: vhost: synchronize IOTLB message with dev cleanup [ Upstream commit 1b15ad683ab42a203f98b67045b40720e99d0e9a ] DaeRyong Jeong reports a race between vhost_dev_cleanup() and vhost_process_iotlb_msg(): Thread interleaving: CPU0 (vhost_process_iotlb_msg) CPU1 (vhost_dev_cleanup) (In the case of both VHOST_IOTLB_UPDATE and VHOST_IOTLB_INVALIDATE) ===== ===== vhost_umem_clean(dev->iotlb); if (!dev->iotlb) { ret = -EFAULT; break; } dev->iotlb = NULL; The reason is we don't synchronize between them, fixing by protecting vhost_process_iotlb_msg() with dev mutex. Reported-by: DaeRyong Jeong Fixes: 6b1e6cc7855b0 ("vhost: new device IOTLB API") Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit f833209e15bd6cf066e731463308f0058736a74b) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I5f372cf9e2d0cf0002ebe01d692e33c3ff52f5d2 --- drivers/vhost/vhost.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index fb94b311f498..acdb9ac34242 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -939,6 +939,7 @@ int vhost_process_iotlb_msg(struct vhost_dev *dev, { int ret = 0; + mutex_lock(&dev->mutex); vhost_dev_lock_vqs(dev); switch (msg->type) { case VHOST_IOTLB_UPDATE: @@ -968,6 +969,8 @@ int vhost_process_iotlb_msg(struct vhost_dev *dev, } vhost_dev_unlock_vqs(dev); + mutex_unlock(&dev->mutex); + return ret; } ssize_t vhost_chr_write_iter(struct vhost_dev *dev, -- cgit v1.2.3 From 651e1bbeb855b1c4f461440b7a7292b78936e5cc Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 24 Aug 2018 16:53:13 +0800 Subject: UPSTREAM: vhost: correctly check the iova range when waking virtqueue [ Upstream commit 2d66f997f0545c8f7fc5cf0b49af1decb35170e7 ] We don't wakeup the virtqueue if the first byte of pending iova range is the last byte of the range we just got updated. This will lead a virtqueue to wait for IOTLB updating forever. Fixing by correct the check and wake up the virtqueue in this case. Fixes: 6b1e6cc7855b ("vhost: new device IOTLB API") Reported-by: Peter Xu Signed-off-by: Jason Wang Reviewed-by: Peter Xu Tested-by: Peter Xu Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman (cherry picked from commit a21a39a9c37b8f629633d22a29cab69bbce38261) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I2cd64a1d7e195a508a3385e3afe4ecf22632770f --- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index acdb9ac34242..53b1b3cfce84 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -906,7 +906,7 @@ static void vhost_iotlb_notify_vq(struct vhost_dev *d, list_for_each_entry_safe(node, n, &d->pending_list, node) { struct vhost_iotlb_msg *vq_msg = &node->msg.iotlb; if (msg->iova <= vq_msg->iova && - msg->iova + msg->size - 1 > vq_msg->iova && + msg->iova + msg->size - 1 >= vq_msg->iova && vq_msg->type == VHOST_IOTLB_MISS) { vhost_poll_queue(&node->vq->poll); list_del(&node->node); -- cgit v1.2.3 From 15195dd21b125795cd06bb2bf4a7af895b706b2a Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 5 Nov 2018 10:35:47 +0000 Subject: UPSTREAM: vhost/vsock: fix use-after-free in network stack callers [ Upstream commit 834e772c8db0c6a275d75315d90aba4ebbb1e249 ] If the network stack calls .send_pkt()/.cancel_pkt() during .release(), a struct vhost_vsock use-after-free is possible. This occurs because .release() does not wait for other CPUs to stop using struct vhost_vsock. Switch to an RCU-enabled hashtable (indexed by guest CID) so that .release() can wait for other CPUs by calling synchronize_rcu(). This also eliminates vhost_vsock_lock acquisition in the data path so it could have a positive effect on performance. This is CVE-2018-14625 "kernel: use-after-free Read in vhost_transport_send_pkt". Cc: stable@vger.kernel.org Reported-and-tested-by: syzbot+bd391451452fb0b93039@syzkaller.appspotmail.com Reported-by: syzbot+e3e074963495f92a89ed@syzkaller.appspotmail.com Reported-by: syzbot+d5a0a170c5069658b141@syzkaller.appspotmail.com Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin Acked-by: Jason Wang Signed-off-by: Sasha Levin (cherry picked from commit 569fc4ffb5de8f12fe01759f0b85098b7b9bba8e) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: I87f1e0fbe3fc01ccc18924085e33220373856e29 --- drivers/vhost/vsock.c | 57 +++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index e6ba768ab01c..744ee3a17768 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "vhost.h" @@ -27,14 +28,14 @@ enum { /* Used to track all the vhost_vsock instances on the system. */ static DEFINE_SPINLOCK(vhost_vsock_lock); -static LIST_HEAD(vhost_vsock_list); +static DEFINE_READ_MOSTLY_HASHTABLE(vhost_vsock_hash, 8); struct vhost_vsock { struct vhost_dev dev; struct vhost_virtqueue vqs[2]; - /* Link to global vhost_vsock_list, protected by vhost_vsock_lock */ - struct list_head list; + /* Link to global vhost_vsock_hash, writes use vhost_vsock_lock */ + struct hlist_node hash; struct vhost_work send_pkt_work; spinlock_t send_pkt_list_lock; @@ -50,11 +51,14 @@ static u32 vhost_transport_get_local_cid(void) return VHOST_VSOCK_DEFAULT_HOST_CID; } -static struct vhost_vsock *__vhost_vsock_get(u32 guest_cid) +/* Callers that dereference the return value must hold vhost_vsock_lock or the + * RCU read lock. + */ +static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) { struct vhost_vsock *vsock; - list_for_each_entry(vsock, &vhost_vsock_list, list) { + hash_for_each_possible_rcu(vhost_vsock_hash, vsock, hash, guest_cid) { u32 other_cid = vsock->guest_cid; /* Skip instances that have no CID yet */ @@ -69,17 +73,6 @@ static struct vhost_vsock *__vhost_vsock_get(u32 guest_cid) return NULL; } -static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) -{ - struct vhost_vsock *vsock; - - spin_lock_bh(&vhost_vsock_lock); - vsock = __vhost_vsock_get(guest_cid); - spin_unlock_bh(&vhost_vsock_lock); - - return vsock; -} - static void vhost_transport_do_send_pkt(struct vhost_vsock *vsock, struct vhost_virtqueue *vq) @@ -206,9 +199,12 @@ vhost_transport_send_pkt(struct virtio_vsock_pkt *pkt) struct vhost_virtqueue *vq; int len = pkt->len; + rcu_read_lock(); + /* Find the vhost_vsock according to guest context id */ vsock = vhost_vsock_get(le64_to_cpu(pkt->hdr.dst_cid)); if (!vsock) { + rcu_read_unlock(); virtio_transport_free_pkt(pkt); return -ENODEV; } @@ -223,6 +219,8 @@ vhost_transport_send_pkt(struct virtio_vsock_pkt *pkt) spin_unlock_bh(&vsock->send_pkt_list_lock); vhost_work_queue(&vsock->dev, &vsock->send_pkt_work); + + rcu_read_unlock(); return len; } @@ -232,12 +230,15 @@ vhost_transport_cancel_pkt(struct vsock_sock *vsk) struct vhost_vsock *vsock; struct virtio_vsock_pkt *pkt, *n; int cnt = 0; + int ret = -ENODEV; LIST_HEAD(freeme); + rcu_read_lock(); + /* Find the vhost_vsock according to guest context id */ vsock = vhost_vsock_get(vsk->remote_addr.svm_cid); if (!vsock) - return -ENODEV; + goto out; spin_lock_bh(&vsock->send_pkt_list_lock); list_for_each_entry_safe(pkt, n, &vsock->send_pkt_list, list) { @@ -263,7 +264,10 @@ vhost_transport_cancel_pkt(struct vsock_sock *vsk) vhost_poll_queue(&tx_vq->poll); } - return 0; + ret = 0; +out: + rcu_read_unlock(); + return ret; } static struct virtio_vsock_pkt * @@ -531,10 +535,6 @@ static int vhost_vsock_dev_open(struct inode *inode, struct file *file) spin_lock_init(&vsock->send_pkt_list_lock); INIT_LIST_HEAD(&vsock->send_pkt_list); vhost_work_init(&vsock->send_pkt_work, vhost_transport_send_pkt_work); - - spin_lock_bh(&vhost_vsock_lock); - list_add_tail(&vsock->list, &vhost_vsock_list); - spin_unlock_bh(&vhost_vsock_lock); return 0; out: @@ -575,9 +575,13 @@ static int vhost_vsock_dev_release(struct inode *inode, struct file *file) struct vhost_vsock *vsock = file->private_data; spin_lock_bh(&vhost_vsock_lock); - list_del(&vsock->list); + if (vsock->guest_cid) + hash_del_rcu(&vsock->hash); spin_unlock_bh(&vhost_vsock_lock); + /* Wait for other CPUs to finish using vsock */ + synchronize_rcu(); + /* Iterating over all connections for all CIDs to find orphans is * inefficient. Room for improvement here. */ vsock_for_each_connected_socket(vhost_vsock_reset_orphans); @@ -618,12 +622,17 @@ static int vhost_vsock_set_cid(struct vhost_vsock *vsock, u64 guest_cid) /* Refuse if CID is already in use */ spin_lock_bh(&vhost_vsock_lock); - other = __vhost_vsock_get(guest_cid); + other = vhost_vsock_get(guest_cid); if (other && other != vsock) { spin_unlock_bh(&vhost_vsock_lock); return -EADDRINUSE; } + + if (vsock->guest_cid) + hash_del_rcu(&vsock->hash); + vsock->guest_cid = guest_cid; + hash_add_rcu(vhost_vsock_hash, &vsock->hash, guest_cid); spin_unlock_bh(&vhost_vsock_lock); return 0; -- cgit v1.2.3 From c751f3742d15a7e888c9cf25a8bf016718c108bf Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 6 Dec 2018 19:14:34 +0000 Subject: UPSTREAM: vhost/vsock: fix reset orphans race with close timeout [ Upstream commit c38f57da428b033f2721b611d84b1f40bde674a8 ] If a local process has closed a connected socket and hasn't received a RST packet yet, then the socket remains in the table until a timeout expires. When a vhost_vsock instance is released with the timeout still pending, the socket is never freed because vhost_vsock has already set the SOCK_DONE flag. Check if the close timer is pending and let it close the socket. This prevents the race which can leak sockets. Reported-by: Maximilian Riemensberger Cc: Graham Whaley Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin Signed-off-by: Sasha Levin (cherry picked from commit 06ec6679fe12cacafce68ab7b509586482a2ae1b) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: I6b4564aebecc3938b789e56499a3f9b8bbbeb2a1 --- drivers/vhost/vsock.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 744ee3a17768..72e914de473e 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -561,13 +561,21 @@ static void vhost_vsock_reset_orphans(struct sock *sk) * executing. */ - if (!vhost_vsock_get(vsk->remote_addr.svm_cid)) { - sock_set_flag(sk, SOCK_DONE); - vsk->peer_shutdown = SHUTDOWN_MASK; - sk->sk_state = SS_UNCONNECTED; - sk->sk_err = ECONNRESET; - sk->sk_error_report(sk); - } + /* If the peer is still valid, no need to reset connection */ + if (vhost_vsock_get(vsk->remote_addr.svm_cid)) + return; + + /* If the close timeout is pending, let it expire. This avoids races + * with the timeout callback. + */ + if (vsk->close_work_scheduled) + return; + + sock_set_flag(sk, SOCK_DONE); + vsk->peer_shutdown = SHUTDOWN_MASK; + sk->sk_state = SS_UNCONNECTED; + sk->sk_err = ECONNRESET; + sk->sk_error_report(sk); } static int vhost_vsock_dev_release(struct inode *inode, struct file *file) -- cgit v1.2.3 From 7d61e8ff060424e0923738afd57ab7f8500d6923 Mon Sep 17 00:00:00 2001 From: Cody Schuffelen Date: Mon, 14 Jan 2019 18:37:28 -0800 Subject: ANDROID: cuttlefish_defconfig: Enable vsock options Bug: 121166534 Test: Ran cuttlefish with android-4.4 + vsock adb tunnel Signed-off-by: Cody Schuffelen Change-Id: I8168a710052c7daada306a915c56230c961accd4 --- arch/arm64/configs/cuttlefish_defconfig | 4 ++++ arch/x86/configs/x86_64_cuttlefish_defconfig | 3 +++ 2 files changed, 7 insertions(+) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index 2dacb5ca76df..7457781a6f4f 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -179,6 +179,8 @@ CONFIG_NET_CLS_U32=y CONFIG_NET_EMATCH=y CONFIG_NET_EMATCH_U32=y CONFIG_NET_CLS_ACT=y +CONFIG_VSOCKETS=y +CONFIG_VIRTIO_VSOCKETS=y CONFIG_CFG80211=y # CONFIG_CFG80211_DEFAULT_PS is not set CONFIG_MAC80211=y @@ -385,6 +387,8 @@ CONFIG_SDCARD_FS=y CONFIG_PSTORE=y CONFIG_PSTORE_CONSOLE=y CONFIG_PSTORE_RAM=y +CONFIG_VIRTUALIZATION=y +CONFIG_VHOST_VSOCK=y CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO=y # CONFIG_ENABLE_MUST_CHECK is not set diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 9efb463d0d52..75785ceede1a 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -190,6 +190,8 @@ CONFIG_NET_CLS_U32=y CONFIG_NET_EMATCH=y CONFIG_NET_EMATCH_U32=y CONFIG_NET_CLS_ACT=y +CONFIG_VSOCKETS=y +CONFIG_VIRTIO_VSOCKETS=y CONFIG_CFG80211=y CONFIG_MAC80211=y CONFIG_RFKILL=y @@ -458,3 +460,4 @@ CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y CONFIG_X509_CERTIFICATE_PARSER=y CONFIG_SYSTEM_TRUSTED_KEYRING=y CONFIG_SYSTEM_TRUSTED_KEYS="verity_dev_keys.x509" +CONFIG_VHOST_VSOCK=y -- cgit v1.2.3 From 509dc245b717a77134ccc450185cfcd329011d39 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Tue, 12 Feb 2019 13:23:11 -0800 Subject: ANDROID: Move from clang r346389b to r349610. Bug: 123635022 Test: make ARCH=arm64 cuttlefish_defconfig && make ARCH=arm64 Test: make ARCH=x86_64 x86_64_cuttlefish_defconfig && make ARCH=x86_64 Change-Id: Icc02ea92c13435fa5a6ecd33d8878629762fd2f7 Signed-off-by: Alistair Strachan --- build.config.cuttlefish.aarch64 | 2 +- build.config.cuttlefish.x86_64 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.config.cuttlefish.aarch64 b/build.config.cuttlefish.aarch64 index e36bae42443e..6bf6755ab3a8 100644 --- a/build.config.cuttlefish.aarch64 +++ b/build.config.cuttlefish.aarch64 @@ -6,7 +6,7 @@ DEFCONFIG=cuttlefish_defconfig EXTRA_CMDS='' KERNEL_DIR=common POST_DEFCONFIG_CMDS="check_defconfig" -CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r346389b/bin +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r349610/bin LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin FILES=" arch/arm64/boot/Image.gz diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64 index 0a77fa871e83..e3477c3b3cbe 100644 --- a/build.config.cuttlefish.x86_64 +++ b/build.config.cuttlefish.x86_64 @@ -6,7 +6,7 @@ DEFCONFIG=x86_64_cuttlefish_defconfig EXTRA_CMDS='' KERNEL_DIR=common POST_DEFCONFIG_CMDS="check_defconfig" -CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r346389b/bin +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r349610/bin LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin FILES=" arch/x86/boot/bzImage -- cgit v1.2.3 From 636b8ad986067b8d3282348ab92d6899603cae5c Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Tue, 5 Mar 2019 11:11:34 -0800 Subject: ANDROID: cuttlefish_defconfig: Add support for AC97 audio Enable driver support for the ac97 emulation provided by QEMU and crosvm. This is for the older 'ac97' soundhw, not 'hda'. Bug: 126955561 Test: local build and test of sound from cuttlefish Change-Id: I6c29e352e0be161e2a1dc35fde50b888b7dbf86e Signed-off-by: Alistair Strachan --- arch/arm64/configs/cuttlefish_defconfig | 6 ++++++ arch/x86/configs/x86_64_cuttlefish_defconfig | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index 7457781a6f4f..3fe49c860df8 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -278,6 +278,12 @@ CONFIG_DRM=y CONFIG_DRM_VIRTIO_GPU=y CONFIG_SOUND=y CONFIG_SND=y +CONFIG_SND_HRTIMER=y +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_DRIVERS is not set +CONFIG_SND_INTEL8X0=y +# CONFIG_SND_USB is not set CONFIG_HIDRAW=y CONFIG_UHID=y CONFIG_HID_A4TECH=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 75785ceede1a..e2e8103e98a0 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -306,6 +306,12 @@ CONFIG_DRM=y CONFIG_DRM_VIRTIO_GPU=y CONFIG_SOUND=y CONFIG_SND=y +CONFIG_SND_HRTIMER=y +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_DRIVERS is not set +CONFIG_SND_INTEL8X0=y +# CONFIG_SND_USB is not set CONFIG_HIDRAW=y CONFIG_UHID=y CONFIG_HID_A4TECH=y -- cgit v1.2.3 From ef952a4354dbf13afdfdd721df16e6f40f671dba Mon Sep 17 00:00:00 2001 From: Cody Schuffelen Date: Wed, 6 Feb 2019 15:54:15 -0800 Subject: UPSTREAM: virt_wifi: Remove REGULATORY_WIPHY_SELF_MANAGED REGULATORY_WIPHY_SELF_MANAGED as set here breaks NL80211_CMD_GET_REG, because it expects the wiphy to do regulatory management. Since virt_wifi does not do regulatory management, this triggers a WARN_ON in NL80211_CMD_GET_REG and fails the netlink command. Removing REGULATORY_WIPHY_SELF_MANAGED fixes the problem and the virtual wireless network continues to work. Signed-off-by: Cody Schuffelen Acked-by: Alistair Strachan Acked-by: Greg Hartman Signed-off-by: Johannes Berg (cherry picked from commit f440b125450dfc65ce0386eb231da2f663c45ca0) Bug: 119771992 Change-Id: Ida660b77a2f091e7aaabcecf8a60e66cc2f1f91d Signed-off-by: Alistair Strachan --- drivers/net/wireless/virt_wifi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/virt_wifi.c b/drivers/net/wireless/virt_wifi.c index 90ecb7e8834f..b9531fcfa5b4 100644 --- a/drivers/net/wireless/virt_wifi.c +++ b/drivers/net/wireless/virt_wifi.c @@ -363,7 +363,6 @@ static struct wiphy *virt_wifi_make_wiphy(void) wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5ghz; wiphy->bands[IEEE80211_BAND_60GHZ] = NULL; - wiphy->regulatory_flags = REGULATORY_WIPHY_SELF_MANAGED; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); priv = wiphy_priv(wiphy); -- cgit v1.2.3 From 476316462c87ea08dd43f2fb205b2d2a16bcf5aa Mon Sep 17 00:00:00 2001 From: Greg Hartman Date: Wed, 17 Apr 2019 12:58:54 -0700 Subject: Make arm64 serial port config compatible with crosvm BUG: 118442619 Test: Ran ~/bin/crosvm run --disable-sandbox ~/image, saw output Change-Id: If086af28b69eca5353a101228ae986653bc1465e Signed-off-by: Greg Hartman (cherry picked from commit 2860dfe869a94c8c1950effb55da116f83ebc740) --- arch/arm64/configs/cuttlefish_defconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index 3fe49c860df8..61201b843d07 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -54,8 +54,6 @@ CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y CONFIG_ARM64_SW_TTBR0_PAN=y CONFIG_RANDOMIZE_BASE=y -CONFIG_CMDLINE="console=ttyAMA0" -CONFIG_CMDLINE_EXTEND=y # CONFIG_EFI is not set # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y @@ -260,6 +258,7 @@ CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y CONFIG_VIRTIO_CONSOLE=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_VIRTIO=y @@ -357,6 +356,7 @@ CONFIG_MMC=y CONFIG_RTC_CLASS=y # CONFIG_RTC_HCTOSYS is not set # CONFIG_RTC_SYSTOHC is not set +CONFIG_RTC_DRV_PL030=y CONFIG_RTC_DRV_PL031=y CONFIG_VIRTIO_PCI=y # CONFIG_VIRTIO_PCI_LEGACY is not set -- cgit v1.2.3 From f2833ba2078987d677a7fbb9d5334b6327d28766 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Tue, 14 May 2019 16:07:58 -0700 Subject: ANDROID: Move from clang r349610 to r353983c. Bug: 120439617 Bug: 132097678 Test: make ARCH=arm64 cuttlefish_defconfig && make ARCH=arm64 Test: make ARCH=x86_64 x86_64_cuttlefish_defconfig && make ARCH=x86_64 Change-Id: If5542a39e36fb4de6dd4b4135a22e188f752dd84 Signed-off-by: Alistair Strachan --- build.config.cuttlefish.aarch64 | 2 +- build.config.cuttlefish.x86_64 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.config.cuttlefish.aarch64 b/build.config.cuttlefish.aarch64 index 6bf6755ab3a8..818b3dc1b3a3 100644 --- a/build.config.cuttlefish.aarch64 +++ b/build.config.cuttlefish.aarch64 @@ -6,7 +6,7 @@ DEFCONFIG=cuttlefish_defconfig EXTRA_CMDS='' KERNEL_DIR=common POST_DEFCONFIG_CMDS="check_defconfig" -CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r349610/bin +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r353983c/bin LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin FILES=" arch/arm64/boot/Image.gz diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64 index e3477c3b3cbe..84556472221d 100644 --- a/build.config.cuttlefish.x86_64 +++ b/build.config.cuttlefish.x86_64 @@ -6,7 +6,7 @@ DEFCONFIG=x86_64_cuttlefish_defconfig EXTRA_CMDS='' KERNEL_DIR=common POST_DEFCONFIG_CMDS="check_defconfig" -CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r349610/bin +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r353983c/bin LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin FILES=" arch/x86/boot/bzImage -- cgit v1.2.3 From 268795a8486e5e07834280ff365b8e0681cb0a1e Mon Sep 17 00:00:00 2001 From: Matthias Maennich Date: Mon, 4 Feb 2019 17:33:19 +0000 Subject: ANDROID: cuttlefish_defconfig: Enable CONFIG_RTC_HCTOSYS This configuration is required for the VTS test VtsKernelApiSysfsTest#testRtcHctosys to pass. Bug: 123860857 Test: run vts-kernel -m VtsKernelApiSysfsTest Signed-off-by: Matthias Maennich Change-Id: Icae17c74460bcd2aef4cf4e3ec5381de9ea0a66c --- arch/arm64/configs/cuttlefish_defconfig | 1 - arch/x86/configs/x86_64_cuttlefish_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index 61201b843d07..f639ead6ded0 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -354,7 +354,6 @@ CONFIG_USB_CONFIGFS_F_MIDI=y CONFIG_MMC=y # CONFIG_MMC_BLOCK is not set CONFIG_RTC_CLASS=y -# CONFIG_RTC_HCTOSYS is not set # CONFIG_RTC_SYSTOHC is not set CONFIG_RTC_DRV_PL030=y CONFIG_RTC_DRV_PL031=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index e2e8103e98a0..45f58d659d99 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -384,7 +384,6 @@ CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y CONFIG_USB_CONFIGFS_UEVENT=y CONFIG_USB_CONFIGFS_F_MIDI=y CONFIG_RTC_CLASS=y -# CONFIG_RTC_HCTOSYS is not set CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_BALLOON=y CONFIG_VIRTIO_INPUT=y -- cgit v1.2.3 From c95ffd281360097ad70d21a173bea1096a5f2126 Mon Sep 17 00:00:00 2001 From: Cody Schuffelen Date: Wed, 16 Jan 2019 16:45:29 -0800 Subject: ANDROID: Fix cuttlefish redundant vsock connection. I initially believed CONFIG_VHOST_VSOCK was necessary on the guest side, but astrachan@ correctly pointed out that this was for setting up vsock on a host system. With both CONFIG_VHOST_VSOCK and the other vsock options enabled, vsock fails on startup with the error: vmw_vsock_virtio_transport: probe of virtio9 failed with error -16 This is probably from the guest-side and host-side vsock fighting over ownership on the vsock device. Bug: 121166534 Test: Ran cuttlefish with the android-4.4 kernel. Change-Id: Ib23a5d756f02708984babc73e26fdbef8435bfb4 Signed-off-by: Cody Schuffelen --- arch/arm64/configs/cuttlefish_defconfig | 2 -- arch/x86/configs/x86_64_cuttlefish_defconfig | 1 - 2 files changed, 3 deletions(-) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index f639ead6ded0..bf279adcff3b 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -392,8 +392,6 @@ CONFIG_SDCARD_FS=y CONFIG_PSTORE=y CONFIG_PSTORE_CONSOLE=y CONFIG_PSTORE_RAM=y -CONFIG_VIRTUALIZATION=y -CONFIG_VHOST_VSOCK=y CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO=y # CONFIG_ENABLE_MUST_CHECK is not set diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 45f58d659d99..59f5dab1f250 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -465,4 +465,3 @@ CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y CONFIG_X509_CERTIFICATE_PARSER=y CONFIG_SYSTEM_TRUSTED_KEYRING=y CONFIG_SYSTEM_TRUSTED_KEYS="verity_dev_keys.x509" -CONFIG_VHOST_VSOCK=y -- cgit v1.2.3 From 8b4d936c2d91e573383bd6ce3ca509d678e71b65 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Fri, 15 Feb 2019 12:57:28 -0800 Subject: ANDROID: cuttlefish_defconfig: Enable DEBUG_SET_MODULE_RONX This feature is required by the KernelConfigTest#testConfigROData security CTS test. It was already a base option in kernel/configs and was enabled in the arm64 defconfig. It was simply missed for x86_64. As we do not currently use kernel modules on cuttlefish this option should have no other effect. Bug: 124521452 Test: booted cuttlefish with updated kernel (x86_64) Change-Id: Id6ab679b2412159d2f8c8e72b683bd2dee59e512 Signed-off-by: Alistair Strachan --- arch/x86/configs/x86_64_cuttlefish_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 59f5dab1f250..7240ef9e5b10 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -447,6 +447,7 @@ CONFIG_SCHEDSTATS=y CONFIG_TIMER_STATS=y CONFIG_RCU_CPU_STALL_TIMEOUT=60 CONFIG_ENABLE_DEFAULT_TRACERS=y +CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_IO_DELAY_NONE=y CONFIG_DEBUG_BOOT_PARAMS=y CONFIG_OPTIMIZE_INLINING=y -- cgit v1.2.3 From 3f434ad40c2a636c644e5c5a90164d99ff87fadd Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Fri, 19 Apr 2019 18:18:15 -0700 Subject: ANDROID: cuttlefish_defconfig: L2TP/PPTP to OLAC/OPNS Change-Id: Idafb69ff5b4ecfe73d2f5b7c46c4e9523ef37c08 Signed-off-by: Alistair Strachan --- arch/arm64/configs/cuttlefish_defconfig | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index bf279adcff3b..36c343ece5aa 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -78,7 +78,6 @@ CONFIG_INET=y CONFIG_IP_MULTICAST=y CONFIG_IP_ADVANCED_ROUTER=y CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_NET_IPGRE_DEMUX=y CONFIG_NET_IPVTI=y CONFIG_INET_ESP=y # CONFIG_INET_XFRM_MODE_BEET is not set @@ -170,7 +169,6 @@ CONFIG_IP6_NF_FILTER=y CONFIG_IP6_NF_TARGET_REJECT=y CONFIG_IP6_NF_MANGLE=y CONFIG_IP6_NF_RAW=y -CONFIG_L2TP=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_HTB=y CONFIG_NET_CLS_U32=y @@ -217,8 +215,8 @@ CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y CONFIG_PPP_MPPE=y -CONFIG_PPTP=y -CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y CONFIG_USB_USBNET=y # CONFIG_USB_NET_AX8817X is not set # CONFIG_USB_NET_AX88179_178A is not set -- cgit v1.2.3 From de0a0dd6f73babf7ae5a8eea16e8bc5708f600a2 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 2 Feb 2016 21:46:35 -0800 Subject: UPSTREAM: vring: Introduce vring_use_dma_api() This is a kludge, but no one has come up with a a better idea yet. We'll introduce DMA API support guarded by vring_use_dma_api(). Eventually we may be able to return true on more and more systems, and hopefully we can get rid of vring_use_dma_api() entirely some day. Signed-off-by: Andy Lutomirski Signed-off-by: Michael S. Tsirkin (cherry picked from commit d26c96c8102549f91eb0bea6196d54711ab52176) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: Icfe1fdb85df794d0238fef53123cd10d99d10aa4 --- drivers/virtio/virtio_ring.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index a01a41a41269..eba6deb94685 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -104,6 +104,30 @@ struct vring_virtqueue { #define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq) +/* + * The interaction between virtio and a possible IOMMU is a mess. + * + * On most systems with virtio, physical addresses match bus addresses, + * and it doesn't particularly matter whether we use the DMA API. + * + * On some systems, including Xen and any system with a physical device + * that speaks virtio behind a physical IOMMU, we must use the DMA API + * for virtio DMA to work at all. + * + * On other systems, including SPARC and PPC64, virtio-pci devices are + * enumerated as though they are behind an IOMMU, but the virtio host + * ignores the IOMMU, so we must either pretend that the IOMMU isn't + * there or somehow map everything as the identity. + * + * For the time being, we preserve historic behavior and bypass the DMA + * API. + */ + +static bool vring_use_dma_api(struct virtio_device *vdev) +{ + return false; +} + static struct vring_desc *alloc_indirect(struct virtqueue *_vq, unsigned int total_sg, gfp_t gfp) { -- cgit v1.2.3 From 4323356bacd3da6beb5199e45b1de52624487c77 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 2 Feb 2016 21:46:36 -0800 Subject: UPSTREAM: virtio_ring: Support DMA APIs virtio_ring currently sends the device (usually a hypervisor) physical addresses of its I/O buffers. This is okay when DMA addresses and physical addresses are the same thing, but this isn't always the case. For example, this never works on Xen guests, and it is likely to fail if a physical "virtio" device ever ends up behind an IOMMU or swiotlb. The immediate use case for me is to enable virtio on Xen guests. For that to work, we need vring to support DMA address translation as well as a corresponding change to virtio_pci or to another driver. Signed-off-by: Andy Lutomirski Signed-off-by: Michael S. Tsirkin (cherry picked from commit 780bc7903a32edb63be138487fd981694d993610) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: I0b21ea8a054df791fe114a10701a1120341806ce --- drivers/virtio/Kconfig | 2 +- drivers/virtio/virtio_ring.c | 200 ++++++++++++++++++++++++++++++++------- tools/virtio/linux/dma-mapping.h | 17 ++++ 3 files changed, 183 insertions(+), 36 deletions(-) create mode 100644 tools/virtio/linux/dma-mapping.h diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index cab9f3f63a38..77590320d44c 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -60,7 +60,7 @@ config VIRTIO_INPUT config VIRTIO_MMIO tristate "Platform bus driver for memory mapped virtio devices" - depends on HAS_IOMEM + depends on HAS_IOMEM && HAS_DMA select VIRTIO ---help--- This drivers provides support for memory mapped virtio diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index eba6deb94685..7e74a5386ef3 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef DEBUG /* For development, we want to crash whenever the ring is screwed. */ @@ -54,6 +55,11 @@ #define END_USE(vq) #endif +struct vring_desc_state { + void *data; /* Data for callback. */ + struct vring_desc *indir_desc; /* Indirect descriptor, if any. */ +}; + struct vring_virtqueue { struct virtqueue vq; @@ -98,8 +104,8 @@ struct vring_virtqueue { ktime_t last_add_time; #endif - /* Tokens for callbacks. */ - void *data[]; + /* Per-descriptor state. */ + struct vring_desc_state desc_state[]; }; #define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq) @@ -128,6 +134,79 @@ static bool vring_use_dma_api(struct virtio_device *vdev) return false; } +/* + * The DMA ops on various arches are rather gnarly right now, and + * making all of the arch DMA ops work on the vring device itself + * is a mess. For now, we use the parent device for DMA ops. + */ +struct device *vring_dma_dev(const struct vring_virtqueue *vq) +{ + return vq->vq.vdev->dev.parent; +} + +/* Map one sg entry. */ +static dma_addr_t vring_map_one_sg(const struct vring_virtqueue *vq, + struct scatterlist *sg, + enum dma_data_direction direction) +{ + if (!vring_use_dma_api(vq->vq.vdev)) + return (dma_addr_t)sg_phys(sg); + + /* + * We can't use dma_map_sg, because we don't use scatterlists in + * the way it expects (we don't guarantee that the scatterlist + * will exist for the lifetime of the mapping). + */ + return dma_map_page(vring_dma_dev(vq), + sg_page(sg), sg->offset, sg->length, + direction); +} + +static dma_addr_t vring_map_single(const struct vring_virtqueue *vq, + void *cpu_addr, size_t size, + enum dma_data_direction direction) +{ + if (!vring_use_dma_api(vq->vq.vdev)) + return (dma_addr_t)virt_to_phys(cpu_addr); + + return dma_map_single(vring_dma_dev(vq), + cpu_addr, size, direction); +} + +static void vring_unmap_one(const struct vring_virtqueue *vq, + struct vring_desc *desc) +{ + u16 flags; + + if (!vring_use_dma_api(vq->vq.vdev)) + return; + + flags = virtio16_to_cpu(vq->vq.vdev, desc->flags); + + if (flags & VRING_DESC_F_INDIRECT) { + dma_unmap_single(vring_dma_dev(vq), + virtio64_to_cpu(vq->vq.vdev, desc->addr), + virtio32_to_cpu(vq->vq.vdev, desc->len), + (flags & VRING_DESC_F_WRITE) ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); + } else { + dma_unmap_page(vring_dma_dev(vq), + virtio64_to_cpu(vq->vq.vdev, desc->addr), + virtio32_to_cpu(vq->vq.vdev, desc->len), + (flags & VRING_DESC_F_WRITE) ? + DMA_FROM_DEVICE : DMA_TO_DEVICE); + } +} + +static int vring_mapping_error(const struct vring_virtqueue *vq, + dma_addr_t addr) +{ + if (!vring_use_dma_api(vq->vq.vdev)) + return 0; + + return dma_mapping_error(vring_dma_dev(vq), addr); +} + static struct vring_desc *alloc_indirect(struct virtqueue *_vq, unsigned int total_sg, gfp_t gfp) { @@ -161,7 +240,7 @@ static inline int virtqueue_add(struct virtqueue *_vq, struct vring_virtqueue *vq = to_vvq(_vq); struct scatterlist *sg; struct vring_desc *desc; - unsigned int i, n, avail, descs_used, uninitialized_var(prev); + unsigned int i, n, avail, descs_used, uninitialized_var(prev), err_idx; int head; bool indirect; @@ -201,21 +280,15 @@ static inline int virtqueue_add(struct virtqueue *_vq, if (desc) { /* Use a single buffer which doesn't continue */ - vq->vring.desc[head].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_INDIRECT); - vq->vring.desc[head].addr = cpu_to_virtio64(_vq->vdev, virt_to_phys(desc)); - /* avoid kmemleak false positive (hidden by virt_to_phys) */ - kmemleak_ignore(desc); - vq->vring.desc[head].len = cpu_to_virtio32(_vq->vdev, total_sg * sizeof(struct vring_desc)); - + indirect = true; /* Set up rest to use this indirect table. */ i = 0; descs_used = 1; - indirect = true; } else { + indirect = false; desc = vq->vring.desc; i = head; descs_used = total_sg; - indirect = false; } if (vq->vq.num_free < descs_used) { @@ -232,13 +305,14 @@ static inline int virtqueue_add(struct virtqueue *_vq, return -ENOSPC; } - /* We're about to use some buffers from the free list. */ - vq->vq.num_free -= descs_used; - for (n = 0; n < out_sgs; n++) { for (sg = sgs[n]; sg; sg = sg_next(sg)) { + dma_addr_t addr = vring_map_one_sg(vq, sg, DMA_TO_DEVICE); + if (vring_mapping_error(vq, addr)) + goto unmap_release; + desc[i].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_NEXT); - desc[i].addr = cpu_to_virtio64(_vq->vdev, sg_phys(sg)); + desc[i].addr = cpu_to_virtio64(_vq->vdev, addr); desc[i].len = cpu_to_virtio32(_vq->vdev, sg->length); prev = i; i = virtio16_to_cpu(_vq->vdev, desc[i].next); @@ -246,8 +320,12 @@ static inline int virtqueue_add(struct virtqueue *_vq, } for (; n < (out_sgs + in_sgs); n++) { for (sg = sgs[n]; sg; sg = sg_next(sg)) { + dma_addr_t addr = vring_map_one_sg(vq, sg, DMA_FROM_DEVICE); + if (vring_mapping_error(vq, addr)) + goto unmap_release; + desc[i].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_NEXT | VRING_DESC_F_WRITE); - desc[i].addr = cpu_to_virtio64(_vq->vdev, sg_phys(sg)); + desc[i].addr = cpu_to_virtio64(_vq->vdev, addr); desc[i].len = cpu_to_virtio32(_vq->vdev, sg->length); prev = i; i = virtio16_to_cpu(_vq->vdev, desc[i].next); @@ -256,14 +334,33 @@ static inline int virtqueue_add(struct virtqueue *_vq, /* Last one doesn't continue. */ desc[prev].flags &= cpu_to_virtio16(_vq->vdev, ~VRING_DESC_F_NEXT); + if (indirect) { + /* Now that the indirect table is filled in, map it. */ + dma_addr_t addr = vring_map_single( + vq, desc, total_sg * sizeof(struct vring_desc), + DMA_TO_DEVICE); + if (vring_mapping_error(vq, addr)) + goto unmap_release; + + vq->vring.desc[head].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_INDIRECT); + vq->vring.desc[head].addr = cpu_to_virtio64(_vq->vdev, addr); + + vq->vring.desc[head].len = cpu_to_virtio32(_vq->vdev, total_sg * sizeof(struct vring_desc)); + } + + /* We're using some buffers from the free list. */ + vq->vq.num_free -= descs_used; + /* Update free pointer */ if (indirect) vq->free_head = virtio16_to_cpu(_vq->vdev, vq->vring.desc[head].next); else vq->free_head = i; - /* Set token. */ - vq->data[head] = data; + /* Store token and indirect buffer state. */ + vq->desc_state[head].data = data; + if (indirect) + vq->desc_state[head].indir_desc = desc; /* Put entry in available array (but don't update avail->idx until they * do sync). */ @@ -286,6 +383,24 @@ static inline int virtqueue_add(struct virtqueue *_vq, virtqueue_kick(_vq); return 0; + +unmap_release: + err_idx = i; + i = head; + + for (n = 0; n < total_sg; n++) { + if (i == err_idx) + break; + vring_unmap_one(vq, &desc[i]); + i = vq->vring.desc[i].next; + } + + vq->vq.num_free += total_sg; + + if (indirect) + kfree(desc); + + return -EIO; } /** @@ -456,27 +571,43 @@ EXPORT_SYMBOL_GPL(virtqueue_kick); static void detach_buf(struct vring_virtqueue *vq, unsigned int head) { - unsigned int i; + unsigned int i, j; + u16 nextflag = cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_NEXT); /* Clear data ptr. */ - vq->data[head] = NULL; + vq->desc_state[head].data = NULL; - /* Put back on free list: find end */ + /* Put back on free list: unmap first-level descriptors and find end */ i = head; - /* Free the indirect table */ - if (vq->vring.desc[i].flags & cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_INDIRECT)) - kfree(phys_to_virt(virtio64_to_cpu(vq->vq.vdev, vq->vring.desc[i].addr))); - - while (vq->vring.desc[i].flags & cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_NEXT)) { + while (vq->vring.desc[i].flags & nextflag) { + vring_unmap_one(vq, &vq->vring.desc[i]); i = virtio16_to_cpu(vq->vq.vdev, vq->vring.desc[i].next); vq->vq.num_free++; } + vring_unmap_one(vq, &vq->vring.desc[i]); vq->vring.desc[i].next = cpu_to_virtio16(vq->vq.vdev, vq->free_head); vq->free_head = head; + /* Plus final descriptor */ vq->vq.num_free++; + + /* Free the indirect table, if any, now that it's unmapped. */ + if (vq->desc_state[head].indir_desc) { + struct vring_desc *indir_desc = vq->desc_state[head].indir_desc; + u32 len = virtio32_to_cpu(vq->vq.vdev, vq->vring.desc[head].len); + + BUG_ON(!(vq->vring.desc[head].flags & + cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_INDIRECT))); + BUG_ON(len == 0 || len % sizeof(struct vring_desc)); + + for (j = 0; j < len / sizeof(struct vring_desc); j++) + vring_unmap_one(vq, &indir_desc[j]); + + kfree(vq->desc_state[head].indir_desc); + vq->desc_state[head].indir_desc = NULL; + } } static inline bool more_used(const struct vring_virtqueue *vq) @@ -531,13 +662,13 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) BAD_RING(vq, "id %u out of range\n", i); return NULL; } - if (unlikely(!vq->data[i])) { + if (unlikely(!vq->desc_state[i].data)) { BAD_RING(vq, "id %u is not a head!\n", i); return NULL; } /* detach_buf clears data, so grab it now. */ - ret = vq->data[i]; + ret = vq->desc_state[i].data; detach_buf(vq, i); vq->last_used_idx++; /* If we expect an interrupt for the next entry, tell host @@ -711,10 +842,10 @@ void *virtqueue_detach_unused_buf(struct virtqueue *_vq) START_USE(vq); for (i = 0; i < vq->vring.num; i++) { - if (!vq->data[i]) + if (!vq->desc_state[i].data) continue; /* detach_buf clears data, so grab it now. */ - buf = vq->data[i]; + buf = vq->desc_state[i].data; detach_buf(vq, i); vq->avail_idx_shadow--; vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, vq->avail_idx_shadow); @@ -768,7 +899,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int index, return NULL; } - vq = kmalloc(sizeof(*vq) + sizeof(void *)*num, GFP_KERNEL); + vq = kmalloc(sizeof(*vq) + num * sizeof(struct vring_desc_state), + GFP_KERNEL); if (!vq) return NULL; @@ -803,11 +935,9 @@ struct virtqueue *vring_new_virtqueue(unsigned int index, /* Put everything in free lists. */ vq->free_head = 0; - for (i = 0; i < num-1; i++) { + for (i = 0; i < num-1; i++) vq->vring.desc[i].next = cpu_to_virtio16(vdev, i + 1); - vq->data[i] = NULL; - } - vq->data[i] = NULL; + memset(vq->desc_state, 0, num * sizeof(struct vring_desc_state)); return &vq->vq; } diff --git a/tools/virtio/linux/dma-mapping.h b/tools/virtio/linux/dma-mapping.h new file mode 100644 index 000000000000..4f93af89ae16 --- /dev/null +++ b/tools/virtio/linux/dma-mapping.h @@ -0,0 +1,17 @@ +#ifndef _LINUX_DMA_MAPPING_H +#define _LINUX_DMA_MAPPING_H + +#ifdef CONFIG_HAS_DMA +# error Virtio userspace code does not support CONFIG_HAS_DMA +#endif + +#define PCI_DMA_BUS_IS_PHYS 1 + +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +#endif -- cgit v1.2.3 From 77facbcf65e77022828924081418fa3e453bac96 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 2 Feb 2016 21:46:40 -0800 Subject: UPSTREAM: vring: Use the DMA API on Xen Signed-off-by: Andy Lutomirski Signed-off-by: Michael S. Tsirkin Reviewed-by: David Vrabel Reviewed-by: Wei Liu (cherry picked from commit 78fe39872378b0bef00a91181f1947acb8a08500) Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: Ibf85aad139f319354cd2ee8833ca9434c15640d8 --- drivers/virtio/virtio_ring.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 7e74a5386ef3..9a31cb74b4cd 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef DEBUG /* For development, we want to crash whenever the ring is screwed. */ @@ -131,6 +132,17 @@ struct vring_virtqueue { static bool vring_use_dma_api(struct virtio_device *vdev) { + /* + * In theory, it's possible to have a buggy QEMU-supposed + * emulated Q35 IOMMU and Xen enabled at the same time. On + * such a configuration, virtio has never worked and will + * not work without an even larger kludge. Instead, enable + * the DMA API if we're a Xen guest, which at least allows + * all of the sensible Xen configurations to work correctly. + */ + if (xen_domain()) + return true; + return false; } -- cgit v1.2.3 From 9e5e2625a2b9284e2d47a59bfb0ae2763a1b0cab Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 18 Apr 2016 12:58:14 +0300 Subject: UPSTREAM: virtio: new feature to detect IOMMU device quirk The interaction between virtio and IOMMUs is messy. On most systems with virtio, physical addresses match bus addresses, and it doesn't particularly matter which one we use to program the device. On some systems, including Xen and any system with a physical device that speaks virtio behind a physical IOMMU, we must program the IOMMU for virtio DMA to work at all. On other systems, including SPARC and PPC64, virtio-pci devices are enumerated as though they are behind an IOMMU, but the virtio host ignores the IOMMU, so we must either pretend that the IOMMU isn't there or somehow map everything as the identity. Add a feature bit to detect that quirk: VIRTIO_F_IOMMU_PLATFORM. Any device with this feature bit set to 0 needs a quirk and has to be passed physical addresses (as opposed to bus addresses) even though the device is behind an IOMMU. Note: it has to be a per-device quirk because for example, there could be a mix of passed-through and virtual virtio devices. As another example, some devices could be implemented by an out of process hypervisor backend (in case of qemu vhost, or vhost-user) and so support for an IOMMU needs to be coded up separately. It would be cleanest to handle this in IOMMU core code, but that needs per-device DMA ops. While we are waiting for that to be implemented, use a work-around in virtio core. Note: a "noiommu" feature is a quirk - add a wrapper to make that clear. Signed-off-by: Michael S. Tsirkin (cherry picked from commit 1a937693993ff10d7e80cca6ddd55f3000aa6376) [astrachan: should fix CONFIG_IOMMU builds] Bug: 121166534 Test: Ran cuttlefish with android-4.4 + VSOCKETS, VMWARE_VMCI_VSOCKETS Signed-off-by: Alistair Strachan Change-Id: If09b9b34a2410de7453d2c38812550615e098b10 --- drivers/virtio/virtio_ring.c | 15 ++++++++++++++- include/linux/virtio_config.h | 13 +++++++++++++ include/uapi/linux/virtio_config.h | 10 +++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 9a31cb74b4cd..761f28ffd40e 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -112,7 +112,10 @@ struct vring_virtqueue { #define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq) /* - * The interaction between virtio and a possible IOMMU is a mess. + * Modern virtio devices have feature bits to specify whether they need a + * quirk and bypass the IOMMU. If not there, just use the DMA API. + * + * If there, the interaction between virtio and DMA API is messy. * * On most systems with virtio, physical addresses match bus addresses, * and it doesn't particularly matter whether we use the DMA API. @@ -128,10 +131,18 @@ struct vring_virtqueue { * * For the time being, we preserve historic behavior and bypass the DMA * API. + * + * TODO: install a per-device DMA ops structure that does the right thing + * taking into account all the above quirks, and use the DMA API + * unconditionally on data path. */ static bool vring_use_dma_api(struct virtio_device *vdev) { + if (!virtio_has_iommu_quirk(vdev)) + return true; + + /* Otherwise, we are left to guess. */ /* * In theory, it's possible to have a buggy QEMU-supposed * emulated Q35 IOMMU and Xen enabled at the same time. On @@ -975,6 +986,8 @@ void vring_transport_features(struct virtio_device *vdev) break; case VIRTIO_F_VERSION_1: break; + case VIRTIO_F_IOMMU_PLATFORM: + break; default: /* We don't understand this bit. */ __virtio_clear_bit(vdev, i); diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h index 6e6cb0c9d7cb..26c155bb639b 100644 --- a/include/linux/virtio_config.h +++ b/include/linux/virtio_config.h @@ -149,6 +149,19 @@ static inline bool virtio_has_feature(const struct virtio_device *vdev, return __virtio_test_bit(vdev, fbit); } +/** + * virtio_has_iommu_quirk - determine whether this device has the iommu quirk + * @vdev: the device + */ +static inline bool virtio_has_iommu_quirk(const struct virtio_device *vdev) +{ + /* + * Note the reverse polarity of the quirk feature (compared to most + * other features), this is for compatibility with legacy systems. + */ + return !virtio_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); +} + static inline struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev, vq_callback_t *c, const char *n) diff --git a/include/uapi/linux/virtio_config.h b/include/uapi/linux/virtio_config.h index c18264df9504..cf49c7e2cfdb 100644 --- a/include/uapi/linux/virtio_config.h +++ b/include/uapi/linux/virtio_config.h @@ -47,7 +47,7 @@ * transport being used (eg. virtio_ring), the rest are per-device feature * bits. */ #define VIRTIO_TRANSPORT_F_START 28 -#define VIRTIO_TRANSPORT_F_END 33 +#define VIRTIO_TRANSPORT_F_END 34 #ifndef VIRTIO_CONFIG_NO_LEGACY /* Do we get callbacks when the ring is completely used, even if we've @@ -61,4 +61,12 @@ /* v1.0 compliant. */ #define VIRTIO_F_VERSION_1 32 +/* + * If clear - device has the IOMMU bypass quirk feature. + * If set - use platform tools to detect the IOMMU. + * + * Note the reverse polarity (compared to most other features), + * this is for compatibility with legacy systems. + */ +#define VIRTIO_F_IOMMU_PLATFORM 33 #endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */ -- cgit v1.2.3 From e9147a5f9fe8cd479c61943256042be3ff8c2e25 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Wed, 15 May 2019 17:59:43 -0700 Subject: ANDROID: cuttlefish_defconfig: Drop dead CRYPTO options Change-Id: Idad33a0f7507c3c713cbacda3c5016cba51ceadc Signed-off-by: Alistair Strachan --- arch/arm64/configs/cuttlefish_defconfig | 1 - arch/x86/configs/x86_64_cuttlefish_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index 36c343ece5aa..87c1d8a49dc7 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -412,6 +412,5 @@ CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_LZ4=y -CONFIG_CRYPTO_ZSTD=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_XZ_DEC=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 7240ef9e5b10..749eaf1f99fc 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -459,7 +459,6 @@ CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set -CONFIG_CRYPTO_ECHAINIV=y CONFIG_CRYPTO_SHA512=y CONFIG_ASYMMETRIC_KEY_TYPE=y CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y -- cgit v1.2.3 From 4660d4cbcbdc6f89c7af2658fab23a028f32bc0c Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Wed, 8 May 2019 09:11:11 -0700 Subject: ANDROID: cuttlefish_defconfig: Enable CONFIG_CPUSETS and CONFIG_CGROUP_SCHEDTUNE cpuset and schedtune cgroup controllers are required by Android framework. Bug: 124080437 Test: libcutils_test Change-Id: I30101d336a8c142f15c13dac1d8ce3c774d15be0 Signed-off-by: Suren Baghdasaryan --- arch/x86/configs/x86_64_cuttlefish_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 749eaf1f99fc..ac079bf2a412 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -13,10 +13,13 @@ CONFIG_IKCONFIG_PROC=y CONFIG_CGROUPS=y CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y CONFIG_CGROUP_SCHED=y CONFIG_RT_GROUP_SCHED=y CONFIG_NAMESPACES=y +CONFIG_SCHED_TUNE=y CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZ4 is not set CONFIG_KALLSYMS_ALL=y -- cgit v1.2.3 From 45246ee0499706ca8b16fa03219676ff2958e198 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Wed, 15 May 2019 17:51:09 -0700 Subject: ANDROID: cuttlefish_defconfig: Disable DEVTMPFS This option was enabled for other experiments, and Android doesn't need or use devtmpfs. However, even just having this feature enabled will cause selinux denials. Fix the denials by disabling this feature. Bug: 130468851 Change-Id: I3bf35b2e74f8701d792b85dbdc3f2143d171a8c1 Signed-off-by: Alistair Strachan --- arch/arm64/configs/cuttlefish_defconfig | 1 - arch/x86/configs/x86_64_cuttlefish_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index 87c1d8a49dc7..276cd1feb3d2 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -183,7 +183,6 @@ CONFIG_MAC80211=y # CONFIG_MAC80211_RC_MINSTREL is not set CONFIG_RFKILL=y # CONFIG_UEVENT_HELPER is not set -CONFIG_DEVTMPFS=y # CONFIG_ALLOW_DEV_COREDUMP is not set CONFIG_DEBUG_DEVRES=y CONFIG_OF_UNITTEST=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index ac079bf2a412..39747e99782d 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -199,7 +199,6 @@ CONFIG_CFG80211=y CONFIG_MAC80211=y CONFIG_RFKILL=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_DEVTMPFS=y CONFIG_DEBUG_DEVRES=y CONFIG_OF=y CONFIG_OF_UNITTEST=y -- cgit v1.2.3 From 027ce46ee91ff4ec273534f8988ecf98a9c558d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 4 May 2019 03:42:15 -0700 Subject: ANDROID: cuttlefish 4.4: enable CONFIG_CRYPTO_AES_NI_INTEL=y MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generated via: echo 'CONFIG_CRYPTO_AES_NI_INTEL=y' >> arch/x86/configs/x86_64_cuttlefish_defconfig echo 'CONFIG_CRYPTO_AES_NI_INTEL=y' >> arch/arm64/configs/cuttlefish_defconfig make ARCH=x86_64 x86_64_cuttlefish_defconfig make ARCH=x86_64 savedefconfig cat defconfig > arch/x86/configs/x86_64_cuttlefish_defconfig make ARCH=arm64 cuttlefish_defconfig make ARCH=arm64 savedefconfig cat defconfig > arch/arm64/configs/cuttlefish_defconfig rm defconfig Signed-off-by: Maciej Żenczykowski Change-Id: I78113acbbe3874ae9bf2f47c2573a4fa40f9b978 --- arch/x86/configs/x86_64_cuttlefish_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 39747e99782d..fcc8817ed38b 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -462,6 +462,7 @@ CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_AES_NI_INTEL=y CONFIG_ASYMMETRIC_KEY_TYPE=y CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y CONFIG_X509_CERTIFICATE_PARSER=y -- cgit v1.2.3 From 8236fb88a8c1ff2dfd9ac538ac54f8fbba2ade63 Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Wed, 5 Jun 2019 09:37:46 -0700 Subject: BACKPORT: binder: fix race between munmap() and direct reclaim commit 5cec2d2e5839f9c0fec319c523a911e0a7fd299f upstream. An munmap() on a binder device causes binder_vma_close() to be called which clears the alloc->vma pointer. If direct reclaim causes binder_alloc_free_page() to be called, there is a race where alloc->vma is read into a local vma pointer and then used later after the mm->mmap_sem is acquired. This can result in calling zap_page_range() with an invalid vma which manifests as a use-after-free in zap_page_range(). The fix is to check alloc->vma after acquiring the mmap_sem (which we were acquiring anyway) and skip zap_page_range() if it has changed to NULL. Bug: 120025196 Change-Id: I2f3284d294326ec7736303374769640a1e028783 Cc: Ben Hutchings Signed-off-by: Todd Kjos Reviewed-by: Joel Fernandes (Google) Cc: stable # 4.14 Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder_alloc.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index baecb4bf9d9b..c8614f3c70c4 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -924,15 +924,14 @@ enum lru_status binder_alloc_free_page(struct list_head *item, index = page - alloc->pages; page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE; + + mm = alloc->vma_vm_mm; + /* Same as mmget_not_zero() in later kernel versions */ + if (!atomic_inc_not_zero(&alloc->vma_vm_mm->mm_users)) + goto err_mmget; + if (!down_write_trylock(&mm->mmap_sem)) + goto err_down_write_mmap_sem_failed; vma = alloc->vma; - if (vma) { - /* Same as mmget_not_zero() in later kernel versions */ - if (!atomic_inc_not_zero(&alloc->vma_vm_mm->mm_users)) - goto err_mmget; - mm = alloc->vma_vm_mm; - if (!down_write_trylock(&mm->mmap_sem)) - goto err_down_write_mmap_sem_failed; - } list_lru_isolate(lru, item); spin_unlock(lock); @@ -946,10 +945,9 @@ enum lru_status binder_alloc_free_page(struct list_head *item, PAGE_SIZE, NULL); trace_binder_unmap_user_end(alloc, index); - - up_write(&mm->mmap_sem); - mmput(mm); } + up_write(&mm->mmap_sem); + mmput(mm); trace_binder_unmap_kernel_start(alloc, index); -- cgit v1.2.3 From 7b41aee921e20b15fb9f12d5042386ed2416f786 Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Wed, 24 Apr 2019 12:31:18 -0700 Subject: UPSTREAM: binder: check for overflow when alloc for security context commit 0b0509508beff65c1d50541861bc0d4973487dc5 upstream. When allocating space in the target buffer for the security context, make sure the extra_buffers_size doesn't overflow. This can only happen if the given size is invalid, but an overflow can turn it into a valid size. Fail the transaction if an overflow is detected. Bug: 130571081 Change-Id: Ibaec652d2073491cc426a4a24004a848348316bf Signed-off-by: Todd Kjos Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index ae222e5ad2e2..bd43360458fd 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3130,6 +3130,7 @@ static void binder_transaction(struct binder_proc *proc, if (target_node && target_node->txn_security_ctx) { u32 secid; + size_t added_size; security_task_getsecid(proc->tsk, &secid); ret = security_secid_to_secctx(secid, &secctx, &secctx_sz); @@ -3139,7 +3140,15 @@ static void binder_transaction(struct binder_proc *proc, return_error_line = __LINE__; goto err_get_secctx_failed; } - extra_buffers_size += ALIGN(secctx_sz, sizeof(u64)); + added_size = ALIGN(secctx_sz, sizeof(u64)); + extra_buffers_size += added_size; + if (extra_buffers_size < added_size) { + /* integer overflow of extra_buffers_size */ + return_error = BR_FAILED_REPLY; + return_error_param = EINVAL; + return_error_line = __LINE__; + goto err_bad_extra_size; + } } trace_binder_transaction(reply, t, target_node); @@ -3441,6 +3450,7 @@ err_copy_data_failed: t->buffer->transaction = NULL; binder_alloc_free_buf(&target_proc->alloc, t->buffer); err_binder_alloc_buf_failed: +err_bad_extra_size: if (secctx) security_release_secctx(secctx, secctx_sz); err_get_secctx_failed: -- cgit v1.2.3 From db3af59b11dac73fa67cdc4f3052ef51c6fd06e7 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 9 Jul 2019 13:09:23 +0200 Subject: BACKPORT: binder: Set end of SG buffer area properly. In case the target node requests a security context, the extra_buffers_size is increased with the size of the security context. But, that size is not available for use by regular scatter-gather buffers; make sure the ending of that buffer is marked correctly. Bug: 136210786 Acked-by: Todd Kjos Fixes: ec74136ded79 ("binder: create node flag to request sender's security context") Signed-off-by: Martijn Coenen Cc: stable@vger.kernel.org # 5.1+ Link: https://lore.kernel.org/r/20190709110923.220736-1-maco@android.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit a56587065094fd96eb4c2b5ad65571daad32156d) --- drivers/android/binder.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index bd43360458fd..a3c0f5f2b230 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3225,7 +3225,8 @@ static void binder_transaction(struct binder_proc *proc, } off_end = (void *)off_start + tr->offsets_size; sg_bufp = (u8 *)(PTR_ALIGN(off_end, sizeof(void *))); - sg_buf_end = sg_bufp + extra_buffers_size; + sg_buf_end = sg_bufp + extra_buffers_size - + ALIGN(secctx_sz, sizeof(u64)); off_min = 0; for (; offp < off_end; offp++) { struct binder_object_header *hdr; -- cgit v1.2.3 From ea2db829e4acec8a228bfc8a8453af266f0cd0ff Mon Sep 17 00:00:00 2001 From: Tri Vo Date: Thu, 25 Jul 2019 16:57:16 -0700 Subject: ANDROID: xfrm: remove in_compat_syscall() checks This hack is needed to run 32-bit userspace on 64-bit kernel. Bug: 138147164 Test: kernel_net_tests Signed-off-by: Tri Vo Change-Id: I083d32b45ca985cfadfe3ce57d253b63202befde --- net/xfrm/xfrm_state.c | 5 ----- net/xfrm/xfrm_user.c | 5 ----- 2 files changed, 10 deletions(-) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 13f261feb75c..6475d18149c0 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1848,11 +1848,6 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen struct xfrm_mgr *km; struct xfrm_policy *pol = NULL; -#ifdef CONFIG_COMPAT - if (is_compat_task()) - return -EOPNOTSUPP; -#endif - if (!optval && !optlen) { xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL); xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 4804f29fd011..13d86ef96e56 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -2524,11 +2524,6 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) const struct xfrm_link *link; int type, err; -#ifdef CONFIG_COMPAT - if (is_compat_task()) - return -EOPNOTSUPP; -#endif - type = nlh->nlmsg_type; if (type > XFRM_MSG_MAX) return -EINVAL; -- cgit v1.2.3 From e1c299507e43cbd6ca19526148f29cf8b606a769 Mon Sep 17 00:00:00 2001 From: Tri Vo Date: Tue, 23 Jul 2019 13:20:59 -0700 Subject: ANDROID: enable CONFIG_RTC_DRV_TEST on cuttlefish CMOS RTC device does not work on cuttlefish due to crosvm not implementing ACPI b/127373130. Add a dummy software RTC driver. Fixes following tests on cuttlefish: VtsKernelApiSysfs#testRtcHctosys VtsKernelLinuxKselftest#rtc_rtctest Bug: 127373130 Test: above tests Signed-off-by: Tri Vo Change-Id: I34b69d7808f465add263c5a940d23aa0737dc60f --- arch/x86/configs/x86_64_cuttlefish_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index fcc8817ed38b..d55b4f587c0c 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -386,6 +386,7 @@ CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y CONFIG_USB_CONFIGFS_UEVENT=y CONFIG_USB_CONFIGFS_F_MIDI=y CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_TEST=y CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_BALLOON=y CONFIG_VIRTIO_INPUT=y -- cgit v1.2.3 From 8d806d6ff1842f09a1d2bcb64a266c21e2b3ec6d Mon Sep 17 00:00:00 2001 From: Robin Peng Date: Tue, 30 Jul 2019 10:19:54 +0800 Subject: ANDROID: overlayfs: Fix a regression in commit b24be4acd Fixes a regression in commit b24be4acd17a8963a29b2a92e1d80b9ddf759c95 ("ovl: modify ovl_permission() to do checks on two inodes") by replacing a call to revert_creds with internal ovl_revert_creds. Signed-off-by: Robin Peng Acked-by: Mark Salyzyn Bug: 137827669 Bug: 137827828 Change-Id: I7b542e23554d30347944626dd2d6c48e081e59d9 Signed-off-by: Greg Kroah-Hartman --- fs/overlayfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 9aff8178aa8c..85507909823d 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -155,7 +155,7 @@ int ovl_permission(struct inode *inode, int mask) old_cred = ovl_override_creds(inode->i_sb); err = __inode_permission(realinode, mask); - revert_creds(old_cred); + ovl_revert_creds(old_cred); out_dput: dput(alias); -- cgit v1.2.3 From 78a688fa830a4e9ff49de221ccc64bc26e54c531 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 4 Aug 2019 10:22:50 +0200 Subject: ANDROID: Revert "f2fs: avoid out-of-range memory access" This reverts commit 77bd558b2a02356a43b6e38de5168c6bb2afe9e8 which is commit 56f3ce675103e3fb9e631cfb4131fc768bc23e9a upstream. This is being done because segment.c is a bit "different" in this branch, and we should keep the f2fs fixes away from here for now. Otherwise the build breaks. Change-Id: I014e3381acb1112825f305d47bdf88848ee6fb7f Cc: Ocean Chen Cc: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/segment.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index a022e2f9faf1..1c7b75a760da 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -3073,11 +3073,6 @@ static void read_compacted_summaries(struct f2fs_sb_info *sbi) seg_i = CURSEG_I(sbi, i); segno = le32_to_cpu(ckpt->cur_data_segno[i]); blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]); - if (blk_off > ENTRIES_IN_SUM) { - f2fs_bug_on(sbi, 1); - f2fs_put_page(page, 1); - return -EFAULT; - } seg_i->next_segno = segno; reset_curseg(sbi, i, 0); seg_i->alloc_type = ckpt->alloc_type[i]; -- cgit v1.2.3 From 0e1b964ab45ea74a54c988228c777d3b701c265f Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Mon, 10 Jun 2019 09:14:25 -0700 Subject: binder: binder: fix possible UAF when freeing buffer There is a race between the binder driver cleaning up a completed transaction via binder_free_transaction() and a user calling binder_ioctl(BC_FREE_BUFFER) to release a buffer. It doesn't matter which is first but they need to be protected against running concurrently which can result in a UAF. Bug: 133758011 Change-Id: Ie1426ff3d00218d050d61ff77b333ddf8818b7c9 Signed-off-by: Todd Kjos --- drivers/android/binder.c | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index a3c0f5f2b230..39f588bf7f5f 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -528,7 +528,8 @@ struct binder_priority { * @requested_threads_started: number binder threads started * (protected by @inner_lock) * @tmp_ref: temporary reference to indicate proc is in use - * (protected by @inner_lock) + * (atomic since @proc->inner_lock cannot + * always be acquired) * @default_priority: default scheduler priority * (invariant after initialized) * @debugfs_entry: debugfs node @@ -562,7 +563,7 @@ struct binder_proc { int max_threads; int requested_threads; int requested_threads_started; - int tmp_ref; + atomic_t tmp_ref; struct binder_priority default_priority; struct dentry *debugfs_entry; struct binder_alloc alloc; @@ -2053,9 +2054,9 @@ static void binder_thread_dec_tmpref(struct binder_thread *thread) static void binder_proc_dec_tmpref(struct binder_proc *proc) { binder_inner_proc_lock(proc); - proc->tmp_ref--; + atomic_dec(&proc->tmp_ref); if (proc->is_dead && RB_EMPTY_ROOT(&proc->threads) && - !proc->tmp_ref) { + !atomic_read(&proc->tmp_ref)) { binder_inner_proc_unlock(proc); binder_free_proc(proc); return; @@ -2117,8 +2118,26 @@ static struct binder_thread *binder_get_txn_from_and_acq_inner( static void binder_free_transaction(struct binder_transaction *t) { - if (t->buffer) - t->buffer->transaction = NULL; + struct binder_proc *target_proc; + + spin_lock(&t->lock); + target_proc = t->to_proc; + if (target_proc) { + atomic_inc(&target_proc->tmp_ref); + spin_unlock(&t->lock); + + binder_inner_proc_lock(target_proc); + if (t->buffer) + t->buffer->transaction = NULL; + binder_inner_proc_unlock(target_proc); + binder_proc_dec_tmpref(target_proc); + } else { + /* + * If the transaction has no target_proc, then + * t->buffer->transaction * has already been cleared. + */ + spin_unlock(&t->lock); + } kfree(t); binder_stats_deleted(BINDER_STAT_TRANSACTION); } @@ -2871,7 +2890,7 @@ static struct binder_node *binder_get_node_refs_for_txn( target_node = node; binder_inc_node_nilocked(node, 1, 0, NULL); binder_inc_node_tmpref_ilocked(node); - node->proc->tmp_ref++; + atomic_inc(&node->proc->tmp_ref); *procp = node->proc; } else *error = BR_DEAD_REPLY; @@ -2967,7 +2986,7 @@ static void binder_transaction(struct binder_proc *proc, goto err_dead_binder; } target_proc = target_thread->proc; - target_proc->tmp_ref++; + atomic_inc(&target_proc->tmp_ref); binder_inner_proc_unlock(target_thread->proc); } else { if (tr->target.handle) { @@ -3700,10 +3719,12 @@ static int binder_thread_write(struct binder_proc *proc, buffer->debug_id, buffer->transaction ? "active" : "finished"); + binder_inner_proc_lock(proc); if (buffer->transaction) { buffer->transaction->buffer = NULL; buffer->transaction = NULL; } + binder_inner_proc_unlock(proc); if (buffer->async_transaction && buffer->target_node) { struct binder_node *buf_node; struct binder_work *w; @@ -4565,7 +4586,7 @@ static int binder_thread_release(struct binder_proc *proc, * The corresponding dec is when we actually * free the thread in binder_free_thread() */ - proc->tmp_ref++; + atomic_inc(&proc->tmp_ref); /* * take a ref on this thread to ensure it * survives while we are releasing it @@ -5005,6 +5026,7 @@ static int binder_open(struct inode *nodp, struct file *filp) return -ENOMEM; spin_lock_init(&proc->inner_lock); spin_lock_init(&proc->outer_lock); + atomic_set(&proc->tmp_ref, 0); get_task_struct(current->group_leader); proc->tsk = current->group_leader; mutex_init(&proc->files_lock); @@ -5184,7 +5206,7 @@ static void binder_deferred_release(struct binder_proc *proc) * Make sure proc stays alive after we * remove all the threads */ - proc->tmp_ref++; + atomic_inc(&proc->tmp_ref); proc->is_dead = true; threads = 0; -- cgit v1.2.3 From 2b874e3aede4d36722de5bf4a2a9737a36756301 Mon Sep 17 00:00:00 2001 From: Tom Gall Date: Mon, 5 Aug 2019 14:19:53 -0500 Subject: Fix overlayfs build break Change call from ovl_revert_creds to revert_creds in fs/overlayfs/inode.c, which is consistent with other usage. This fixes a build break. Signed-off-by: Tom Gall Change-Id: I052ed3510a19aa85a1857fb0978ff2966243cb0b --- fs/overlayfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 85507909823d..9aff8178aa8c 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -155,7 +155,7 @@ int ovl_permission(struct inode *inode, int mask) old_cred = ovl_override_creds(inode->i_sb); err = __inode_permission(realinode, mask); - ovl_revert_creds(old_cred); + revert_creds(old_cred); out_dput: dput(alias); -- cgit v1.2.3 From 6cfb5a870f75eee5bf5b3401f00e9b9cfaf7f27b Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Mon, 12 Aug 2019 10:11:52 -0700 Subject: ANDROID: fix binder change in merge of 4.4.183 The 4.4.183 merge was missing the change to the binder driver associated with the linux-4.4.y commit 8f6345a11caa ("coredump: fix race condition between mmget_not_zero()/get_task_mm() and core dumping"). It was left out because the android-4.4 binder driver has been significantly refactored compared to linux-4.4.y. This patch applies the missing change from that patch to the binder driver. Change-Id: I803e558cb629fedff04b14e23ac9f83e98628ede Fixes: 94fd42809f7d ("Merge 4.4.183 into android-4.4") Signed-off-by: Todd Kjos Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder_alloc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index c8614f3c70c4..6bea2840e70a 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -219,6 +219,11 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate, if (mm) { down_read(&mm->mmap_sem); + if (!mmget_still_valid(mm)) { + if (allocate == 0) + goto free_range; + goto err_no_vma; + } vma = alloc->vma; } -- cgit v1.2.3 From bcb576e1a7f16853cc965de5516c5afbbfeec8a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 18 Jul 2019 23:30:03 -0700 Subject: UPSTREAM: net-ipv6-ndisc: add support for RFC7710 RA Captive Portal Identifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is trivial since we already have support for the entirely identical (from the kernel's point of view) RDNSS and DNSSL that also contain opaque data that needs to be passed down to userspace. As specified in RFC7710, Captive Portal option contains a URL. 8-bit identifier of the option type as assigned by the IANA is 37. This option should also be treated as userland. Hence, treat ND option 37 as userland (Captive Portal support) See: https://tools.ietf.org/html/rfc7710 https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml Fixes: e35f30c131a56 Signed-off-by: Maciej Żenczykowski Cc: Lorenzo Colitti Cc: Remin Nguyen Van Cc: Alexey I. Froloff Signed-off-by: David S. Miller Bug: 137914568 Change-Id: I73c12c45660e6371c1e193f799c0da7d97bd5435 (cherry picked from commit 66b5f1c439843bcbab01cc7f3854ae2742f3d1e3) --- include/net/ndisc.h | 1 + net/ipv6/ndisc.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 2d8edaad29cb..da7ffc04ce0c 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -35,6 +35,7 @@ enum { ND_OPT_ROUTE_INFO = 24, /* RFC4191 */ ND_OPT_RDNSS = 25, /* RFC5006 */ ND_OPT_DNSSL = 31, /* RFC6106 */ + ND_OPT_CAPTIVE_PORTAL = 37, /* RFC7710 */ __ND_OPT_MAX }; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index e03bb5a6b8d4..e16a05ca4879 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -188,7 +188,8 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, static inline int ndisc_is_useropt(struct nd_opt_hdr *opt) { return opt->nd_opt_type == ND_OPT_RDNSS || - opt->nd_opt_type == ND_OPT_DNSSL; + opt->nd_opt_type == ND_OPT_DNSSL || + opt->nd_opt_type == ND_OPT_CAPTIVE_PORTAL; } static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, -- cgit v1.2.3 From dd842551d5f0a0f9d239d5a8cef2b167b553dcad Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Thu, 13 Jun 2019 11:54:36 +0100 Subject: ANDROID: Avoid taking multiple locks in handle_lmk_event Conflicting lock events have been reported resulting from rcu_read_lock, mmap_sem (in get_cmdline) and lmk_event_lock. This CL avoids the possibility of these conditions by moving handle_lmk_event outside rcu_read_lock and invoking get_cmdline before lmk_event_lock is taken. Bug: 133479338, 133829075 Signed-off-by: Jim Blackler Change-Id: Ib3c32587472bd972e3ac108798e2af3f4a5c329a --- drivers/staging/android/lowmemorykiller.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 8b19b5e4bd69..d5f5bd4a2d5c 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -102,6 +102,7 @@ void handle_lmk_event(struct task_struct *selected, short min_score_adj) struct lmk_event *event; int res; long rss_in_pages = -1; + char taskname[MAX_TASKNAME]; struct mm_struct *mm = get_task_mm(selected); if (mm) { @@ -109,6 +110,17 @@ void handle_lmk_event(struct task_struct *selected, short min_score_adj) mmput(mm); } + res = get_cmdline(selected, taskname, MAX_TASKNAME - 1); + + /* No valid process name means this is definitely not associated with a + * userspace activity. + */ + + if (res <= 0 || res >= MAX_TASKNAME) + return; + + taskname[res] = '\0'; + spin_lock(&lmk_event_lock); head = event_buffer.head; @@ -123,18 +135,8 @@ void handle_lmk_event(struct task_struct *selected, short min_score_adj) events = (struct lmk_event *) event_buffer.buf; event = &events[head]; - res = get_cmdline(selected, event->taskname, MAX_TASKNAME - 1); - - /* No valid process name means this is definitely not associated with a - * userspace activity. - */ - - if (res <= 0 || res >= MAX_TASKNAME) { - spin_unlock(&lmk_event_lock); - return; - } + memcpy(event->taskname, taskname, res + 1); - event->taskname[res] = '\0'; event->pid = selected->pid; event->uid = from_kuid_munged(current_user_ns(), task_uid(selected)); if (selected->group_leader) @@ -344,13 +346,15 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) free); lowmem_deathpending_timeout = jiffies + HZ; rem += selected_tasksize; - - handle_lmk_event(selected, min_score_adj); } lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n", sc->nr_to_scan, sc->gfp_mask, rem); rcu_read_unlock(); + + if (selected) + handle_lmk_event(selected, min_score_adj); + return rem; } -- cgit v1.2.3 From e005abce5829d9060148325bc482a908f8ad8cbd Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Mon, 19 Aug 2019 12:30:37 -0700 Subject: ANDROID: fix kernelci build-break in lowmemorykiller was not included by lowmemorykiller.c resulting in a kernelci build-break due to no definition for 'poll_table'. Fixes: 941128efa146c ("ANDROID: Communicates LMK events to userland where they can be logged") Signed-off-by: Todd Kjos Change-Id: I5fb2d1d8f6e5afbdd00fbf017df37ec2e8b9ff9e --- drivers/staging/android/lowmemorykiller.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index d5f5bd4a2d5c..1dac38735030 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -45,6 +45,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include "trace/lowmemorykiller.h" -- cgit v1.2.3 From fdfc07c1377c447f3b3814ef4c335cf1c838d686 Mon Sep 17 00:00:00 2001 From: Dan Aloni Date: Thu, 15 Aug 2019 15:28:18 +0300 Subject: ANDROID: arm64: fix leftover RWX when using CONFIG_UNMAP_KERNEL_AT_EL0 With CONFIG_UNMAP_KERNEL_AT_EL0 enabled, before this change, there was an RWX mapping at a fixed `fixmap` address (as discovered using CONFIG_ARM64_PTDUMP). 0xffff7ffffe7fc000-0xffff7ffffe7fd000 4K RW x SHD AF UXN MEM/NORMAL Having PAGE_KERNEL_ROX by default for this fixmap makes sense for a security POV, for reducing the ability to load and run shellcode. Originally, the commit that introduced CONFIG_UNMAP_KERNEL_AT_EL0, had the following: pgprot_t prot = rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC; However rodata_enabled is not available in arch/arm64 on this early version of the kernel. Change-Id: I21f26df498fb591fc28e32f4dfad671a9ed3d8d3 Fixes: 39685f556c0c ("FROMLIST: arm64: mm: Map entry trampoline into trampoline and kernel page tables") Signed-off-by: Dan Aloni --- arch/arm64/mm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 1175bac2f86f..6914d0137b93 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -499,7 +499,7 @@ static int __init map_entry_trampoline(void) { extern char __entry_tramp_text_start[]; - pgprot_t prot = PAGE_KERNEL_EXEC; + pgprot_t prot = PAGE_KERNEL_ROX; phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start); /* The trampoline is always mapped and can therefore be global */ -- cgit v1.2.3 From 5ad560c06b742cd09dca4ca97c0e47649ee4bf44 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Thu, 29 Aug 2019 10:02:15 -0700 Subject: ANDROID: fiq_debugger: remove This represents a rollup of a series of reverts, simplified are modifications to remove fiq_glue and fiq_debugger references in: arch/arm/common/Kconfig arch/arm/common/Makefile drivers/staging/android/Kconfig drivers/staging/android/Makefile And deletion of: arch/arm/common/fiq_glue.S arch/arm/common/fiq_glue_setup.c drivers/staging/android/fiq_debugger/ Signed-off-by: Mark Salyzyn Bug: 32402555 Bug: 36101220 Change-Id: I3f74b1ff5e4971d619bcb37a911fed68fbb538d5 --- arch/arm/common/Kconfig | 4 - arch/arm/common/Makefile | 1 - arch/arm/common/fiq_glue.S | 118 -- arch/arm/common/fiq_glue_setup.c | 147 --- drivers/staging/android/Kconfig | 2 - drivers/staging/android/Makefile | 1 - drivers/staging/android/fiq_debugger/Kconfig | 58 - drivers/staging/android/fiq_debugger/Makefile | 4 - .../staging/android/fiq_debugger/fiq_debugger.c | 1248 -------------------- .../staging/android/fiq_debugger/fiq_debugger.h | 64 - .../android/fiq_debugger/fiq_debugger_arm.c | 240 ---- .../android/fiq_debugger/fiq_debugger_arm64.c | 202 ---- .../android/fiq_debugger/fiq_debugger_priv.h | 37 - .../android/fiq_debugger/fiq_debugger_ringbuf.h | 94 -- .../staging/android/fiq_debugger/fiq_watchdog.c | 56 - .../staging/android/fiq_debugger/fiq_watchdog.h | 20 - 16 files changed, 2296 deletions(-) delete mode 100644 arch/arm/common/fiq_glue.S delete mode 100644 arch/arm/common/fiq_glue_setup.c delete mode 100644 drivers/staging/android/fiq_debugger/Kconfig delete mode 100644 drivers/staging/android/fiq_debugger/Makefile delete mode 100644 drivers/staging/android/fiq_debugger/fiq_debugger.c delete mode 100644 drivers/staging/android/fiq_debugger/fiq_debugger.h delete mode 100644 drivers/staging/android/fiq_debugger/fiq_debugger_arm.c delete mode 100644 drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c delete mode 100644 drivers/staging/android/fiq_debugger/fiq_debugger_priv.h delete mode 100644 drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h delete mode 100644 drivers/staging/android/fiq_debugger/fiq_watchdog.c delete mode 100644 drivers/staging/android/fiq_debugger/fiq_watchdog.h diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index ce01364a96e3..9353184d730d 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -17,7 +17,3 @@ config SHARP_PARAM config SHARP_SCOOP bool - -config FIQ_GLUE - bool - select FIQ diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index 04aca896b338..27f23b15b1ea 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -4,7 +4,6 @@ obj-y += firmware.o -obj-$(CONFIG_FIQ_GLUE) += fiq_glue.o fiq_glue_setup.o obj-$(CONFIG_ICST) += icst.o obj-$(CONFIG_SA1111) += sa1111.o obj-$(CONFIG_DMABOUNCE) += dmabounce.o diff --git a/arch/arm/common/fiq_glue.S b/arch/arm/common/fiq_glue.S deleted file mode 100644 index 24b42cec4813..000000000000 --- a/arch/arm/common/fiq_glue.S +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include - - .text - - .global fiq_glue_end - - /* fiq stack: r0-r15,cpsr,spsr of interrupted mode */ - -ENTRY(fiq_glue) - /* store pc, cpsr from previous mode, reserve space for spsr */ - mrs r12, spsr - sub lr, lr, #4 - subs r10, #1 - bne nested_fiq - - str r12, [sp, #-8]! - str lr, [sp, #-4]! - - /* store r8-r14 from previous mode */ - sub sp, sp, #(7 * 4) - stmia sp, {r8-r14}^ - nop - - /* store r0-r7 from previous mode */ - stmfd sp!, {r0-r7} - - /* setup func(data,regs) arguments */ - mov r0, r9 - mov r1, sp - mov r3, r8 - - mov r7, sp - - /* Get sp and lr from non-user modes */ - and r4, r12, #MODE_MASK - cmp r4, #USR_MODE - beq fiq_from_usr_mode - - mov r7, sp - orr r4, r4, #(PSR_I_BIT | PSR_F_BIT) - msr cpsr_c, r4 - str sp, [r7, #(4 * 13)] - str lr, [r7, #(4 * 14)] - mrs r5, spsr - str r5, [r7, #(4 * 17)] - - cmp r4, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT) - /* use fiq stack if we reenter this mode */ - subne sp, r7, #(4 * 3) - -fiq_from_usr_mode: - msr cpsr_c, #(SVC_MODE | PSR_I_BIT | PSR_F_BIT) - mov r2, sp - sub sp, r7, #12 - stmfd sp!, {r2, ip, lr} - /* call func(data,regs) */ - blx r3 - ldmfd sp, {r2, ip, lr} - mov sp, r2 - - /* restore/discard saved state */ - cmp r4, #USR_MODE - beq fiq_from_usr_mode_exit - - msr cpsr_c, r4 - ldr sp, [r7, #(4 * 13)] - ldr lr, [r7, #(4 * 14)] - msr spsr_cxsf, r5 - -fiq_from_usr_mode_exit: - msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT) - - ldmfd sp!, {r0-r7} - ldr lr, [sp, #(4 * 7)] - ldr r12, [sp, #(4 * 8)] - add sp, sp, #(10 * 4) -exit_fiq: - msr spsr_cxsf, r12 - add r10, #1 - cmp r11, #0 - moveqs pc, lr - bx r11 /* jump to custom fiq return function */ - -nested_fiq: - orr r12, r12, #(PSR_F_BIT) - b exit_fiq - -fiq_glue_end: - -ENTRY(fiq_glue_setup) /* func, data, sp, smc call number */ - stmfd sp!, {r4} - mrs r4, cpsr - msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT) - movs r8, r0 - mov r9, r1 - mov sp, r2 - mov r11, r3 - moveq r10, #0 - movne r10, #1 - msr cpsr_c, r4 - ldmfd sp!, {r4} - bx lr - diff --git a/arch/arm/common/fiq_glue_setup.c b/arch/arm/common/fiq_glue_setup.c deleted file mode 100644 index 8cb1b611c6d5..000000000000 --- a/arch/arm/common/fiq_glue_setup.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2010 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include - -extern unsigned char fiq_glue, fiq_glue_end; -extern void fiq_glue_setup(void *func, void *data, void *sp, - fiq_return_handler_t fiq_return_handler); - -static struct fiq_handler fiq_debbuger_fiq_handler = { - .name = "fiq_glue", -}; -DEFINE_PER_CPU(void *, fiq_stack); -static struct fiq_glue_handler *current_handler; -static fiq_return_handler_t fiq_return_handler; -static DEFINE_MUTEX(fiq_glue_lock); - -static void fiq_glue_setup_helper(void *info) -{ - struct fiq_glue_handler *handler = info; - fiq_glue_setup(handler->fiq, handler, - __get_cpu_var(fiq_stack) + THREAD_START_SP, - fiq_return_handler); -} - -int fiq_glue_register_handler(struct fiq_glue_handler *handler) -{ - int ret; - int cpu; - - if (!handler || !handler->fiq) - return -EINVAL; - - mutex_lock(&fiq_glue_lock); - if (fiq_stack) { - ret = -EBUSY; - goto err_busy; - } - - for_each_possible_cpu(cpu) { - void *stack; - stack = (void *)__get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER); - if (WARN_ON(!stack)) { - ret = -ENOMEM; - goto err_alloc_fiq_stack; - } - per_cpu(fiq_stack, cpu) = stack; - } - - ret = claim_fiq(&fiq_debbuger_fiq_handler); - if (WARN_ON(ret)) - goto err_claim_fiq; - - current_handler = handler; - on_each_cpu(fiq_glue_setup_helper, handler, true); - set_fiq_handler(&fiq_glue, &fiq_glue_end - &fiq_glue); - - mutex_unlock(&fiq_glue_lock); - return 0; - -err_claim_fiq: -err_alloc_fiq_stack: - for_each_possible_cpu(cpu) { - __free_pages(per_cpu(fiq_stack, cpu), THREAD_SIZE_ORDER); - per_cpu(fiq_stack, cpu) = NULL; - } -err_busy: - mutex_unlock(&fiq_glue_lock); - return ret; -} - -static void fiq_glue_update_return_handler(void (*fiq_return)(void)) -{ - fiq_return_handler = fiq_return; - if (current_handler) - on_each_cpu(fiq_glue_setup_helper, current_handler, true); -} - -int fiq_glue_set_return_handler(void (*fiq_return)(void)) -{ - int ret; - - mutex_lock(&fiq_glue_lock); - if (fiq_return_handler) { - ret = -EBUSY; - goto err_busy; - } - fiq_glue_update_return_handler(fiq_return); - ret = 0; -err_busy: - mutex_unlock(&fiq_glue_lock); - - return ret; -} -EXPORT_SYMBOL(fiq_glue_set_return_handler); - -int fiq_glue_clear_return_handler(void (*fiq_return)(void)) -{ - int ret; - - mutex_lock(&fiq_glue_lock); - if (WARN_ON(fiq_return_handler != fiq_return)) { - ret = -EINVAL; - goto err_inval; - } - fiq_glue_update_return_handler(NULL); - ret = 0; -err_inval: - mutex_unlock(&fiq_glue_lock); - - return ret; -} -EXPORT_SYMBOL(fiq_glue_clear_return_handler); - -/** - * fiq_glue_resume - Restore fiqs after suspend or low power idle states - * - * This must be called before calling local_fiq_enable after returning from a - * power state where the fiq mode registers were lost. If a driver provided - * a resume hook when it registered the handler it will be called. - */ - -void fiq_glue_resume(void) -{ - if (!current_handler) - return; - fiq_glue_setup(current_handler->fiq, current_handler, - __get_cpu_var(fiq_stack) + THREAD_START_SP, - fiq_return_handler); - if (current_handler->resume) - current_handler->resume(current_handler); -} - diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 82eb4dcf40c6..565f02b27424 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -86,8 +86,6 @@ config ANDROID_VSOC source "drivers/staging/android/ion/Kconfig" -source "drivers/staging/android/fiq_debugger/Kconfig" - endif # if ANDROID endmenu diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 087886668641..f77ddac38be6 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -1,7 +1,6 @@ ccflags-y += -I$(src) # needed for trace events obj-y += ion/ -obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger/ obj-$(CONFIG_ASHMEM) += ashmem.o obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o diff --git a/drivers/staging/android/fiq_debugger/Kconfig b/drivers/staging/android/fiq_debugger/Kconfig deleted file mode 100644 index 60fc224d4efc..000000000000 --- a/drivers/staging/android/fiq_debugger/Kconfig +++ /dev/null @@ -1,58 +0,0 @@ -config FIQ_DEBUGGER - bool "FIQ Mode Serial Debugger" - default n - depends on ARM || ARM64 - help - The FIQ serial debugger can accept commands even when the - kernel is unresponsive due to being stuck with interrupts - disabled. - -config FIQ_DEBUGGER_NO_SLEEP - bool "Keep serial debugger active" - depends on FIQ_DEBUGGER - default n - help - Enables the serial debugger at boot. Passing - fiq_debugger.no_sleep on the kernel commandline will - override this config option. - -config FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON - bool "Don't disable wakeup IRQ when debugger is active" - depends on FIQ_DEBUGGER - default n - help - Don't disable the wakeup irq when enabling the uart clock. This will - cause extra interrupts, but it makes the serial debugger usable with - on some MSM radio builds that ignore the uart clock request in power - collapse. - -config FIQ_DEBUGGER_CONSOLE - bool "Console on FIQ Serial Debugger port" - depends on FIQ_DEBUGGER - default n - help - Enables a console so that printk messages are displayed on - the debugger serial port as the occur. - -config FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE - bool "Put the FIQ debugger into console mode by default" - depends on FIQ_DEBUGGER_CONSOLE - default n - help - If enabled, this puts the fiq debugger into console mode by default. - Otherwise, the fiq debugger will start out in debug mode. - -config FIQ_DEBUGGER_UART_OVERLAY - bool "Install uart DT overlay" - depends on FIQ_DEBUGGER - select OF_OVERLAY - default n - help - If enabled, fiq debugger is calling fiq_debugger_uart_overlay() - that will apply overlay uart_overlay@0 to disable proper uart. - -config FIQ_WATCHDOG - bool - select FIQ_DEBUGGER - select PSTORE_RAM - default n diff --git a/drivers/staging/android/fiq_debugger/Makefile b/drivers/staging/android/fiq_debugger/Makefile deleted file mode 100644 index a7ca4871cad3..000000000000 --- a/drivers/staging/android/fiq_debugger/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -obj-y += fiq_debugger.o -obj-$(CONFIG_ARM) += fiq_debugger_arm.o -obj-$(CONFIG_ARM64) += fiq_debugger_arm64.o -obj-$(CONFIG_FIQ_WATCHDOG) += fiq_watchdog.o diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.c b/drivers/staging/android/fiq_debugger/fiq_debugger.c deleted file mode 100644 index ef9fa483ac00..000000000000 --- a/drivers/staging/android/fiq_debugger/fiq_debugger.c +++ /dev/null @@ -1,1248 +0,0 @@ -/* - * drivers/staging/android/fiq_debugger.c - * - * Serial Debugger Interface accessed through an FIQ interrupt. - * - * Copyright (C) 2008 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_FIQ_GLUE -#include -#endif - -#ifdef CONFIG_FIQ_DEBUGGER_UART_OVERLAY -#include -#endif - -#include - -#include "fiq_debugger.h" -#include "fiq_debugger_priv.h" -#include "fiq_debugger_ringbuf.h" - -#define DEBUG_MAX 64 -#define MAX_UNHANDLED_FIQ_COUNT 1000000 - -#define MAX_FIQ_DEBUGGER_PORTS 4 - -struct fiq_debugger_state { -#ifdef CONFIG_FIQ_GLUE - struct fiq_glue_handler handler; -#endif - struct fiq_debugger_output output; - - int fiq; - int uart_irq; - int signal_irq; - int wakeup_irq; - bool wakeup_irq_no_set_wake; - struct clk *clk; - struct fiq_debugger_pdata *pdata; - struct platform_device *pdev; - - char debug_cmd[DEBUG_MAX]; - int debug_busy; - int debug_abort; - - char debug_buf[DEBUG_MAX]; - int debug_count; - - bool no_sleep; - bool debug_enable; - bool ignore_next_wakeup_irq; - struct timer_list sleep_timer; - spinlock_t sleep_timer_lock; - bool uart_enabled; - struct wake_lock debugger_wake_lock; - bool console_enable; - int current_cpu; - atomic_t unhandled_fiq_count; - bool in_fiq; - - struct work_struct work; - spinlock_t work_lock; - char work_cmd[DEBUG_MAX]; - -#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE - spinlock_t console_lock; - struct console console; - struct tty_port tty_port; - struct fiq_debugger_ringbuf *tty_rbuf; - bool syslog_dumping; -#endif - - unsigned int last_irqs[NR_IRQS]; - unsigned int last_local_timer_irqs[NR_CPUS]; -}; - -#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE -struct tty_driver *fiq_tty_driver; -#endif - -#ifdef CONFIG_FIQ_DEBUGGER_NO_SLEEP -static bool initial_no_sleep = true; -#else -static bool initial_no_sleep; -#endif - -#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE -static bool initial_debug_enable = true; -static bool initial_console_enable = true; -#else -static bool initial_debug_enable; -static bool initial_console_enable; -#endif - -static bool fiq_kgdb_enable; -static bool fiq_debugger_disable; - -module_param_named(no_sleep, initial_no_sleep, bool, 0644); -module_param_named(debug_enable, initial_debug_enable, bool, 0644); -module_param_named(console_enable, initial_console_enable, bool, 0644); -module_param_named(kgdb_enable, fiq_kgdb_enable, bool, 0644); -module_param_named(disable, fiq_debugger_disable, bool, 0644); - -#ifdef CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON -static inline -void fiq_debugger_enable_wakeup_irq(struct fiq_debugger_state *state) {} -static inline -void fiq_debugger_disable_wakeup_irq(struct fiq_debugger_state *state) {} -#else -static inline -void fiq_debugger_enable_wakeup_irq(struct fiq_debugger_state *state) -{ - if (state->wakeup_irq < 0) - return; - enable_irq(state->wakeup_irq); - if (!state->wakeup_irq_no_set_wake) - enable_irq_wake(state->wakeup_irq); -} -static inline -void fiq_debugger_disable_wakeup_irq(struct fiq_debugger_state *state) -{ - if (state->wakeup_irq < 0) - return; - disable_irq_nosync(state->wakeup_irq); - if (!state->wakeup_irq_no_set_wake) - disable_irq_wake(state->wakeup_irq); -} -#endif - -static inline bool fiq_debugger_have_fiq(struct fiq_debugger_state *state) -{ - return (state->fiq >= 0); -} - -#ifdef CONFIG_FIQ_GLUE -static void fiq_debugger_force_irq(struct fiq_debugger_state *state) -{ - unsigned int irq = state->signal_irq; - - if (WARN_ON(!fiq_debugger_have_fiq(state))) - return; - if (state->pdata->force_irq) { - state->pdata->force_irq(state->pdev, irq); - } else { - struct irq_chip *chip = irq_get_chip(irq); - if (chip && chip->irq_retrigger) - chip->irq_retrigger(irq_get_irq_data(irq)); - } -} -#endif - -static void fiq_debugger_uart_enable(struct fiq_debugger_state *state) -{ - if (state->clk) - clk_enable(state->clk); - if (state->pdata->uart_enable) - state->pdata->uart_enable(state->pdev); -} - -static void fiq_debugger_uart_disable(struct fiq_debugger_state *state) -{ - if (state->pdata->uart_disable) - state->pdata->uart_disable(state->pdev); - if (state->clk) - clk_disable(state->clk); -} - -static void fiq_debugger_uart_flush(struct fiq_debugger_state *state) -{ - if (state->pdata->uart_flush) - state->pdata->uart_flush(state->pdev); -} - -static void fiq_debugger_putc(struct fiq_debugger_state *state, char c) -{ - state->pdata->uart_putc(state->pdev, c); -} - -static void fiq_debugger_puts(struct fiq_debugger_state *state, char *s) -{ - unsigned c; - while ((c = *s++)) { - if (c == '\n') - fiq_debugger_putc(state, '\r'); - fiq_debugger_putc(state, c); - } -} - -static void fiq_debugger_prompt(struct fiq_debugger_state *state) -{ - fiq_debugger_puts(state, "debug> "); -} - -static void fiq_debugger_dump_kernel_log(struct fiq_debugger_state *state) -{ - char buf[512]; - size_t len; - struct kmsg_dumper dumper = { .active = true }; - - - kmsg_dump_rewind_nolock(&dumper); - while (kmsg_dump_get_line_nolock(&dumper, true, buf, - sizeof(buf) - 1, &len)) { - buf[len] = 0; - fiq_debugger_puts(state, buf); - } -} - -static void fiq_debugger_printf(struct fiq_debugger_output *output, - const char *fmt, ...) -{ - struct fiq_debugger_state *state; - char buf[256]; - va_list ap; - - state = container_of(output, struct fiq_debugger_state, output); - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - fiq_debugger_puts(state, buf); -} - -/* Safe outside fiq context */ -static int fiq_debugger_printf_nfiq(void *cookie, const char *fmt, ...) -{ - struct fiq_debugger_state *state = cookie; - char buf[256]; - va_list ap; - unsigned long irq_flags; - - va_start(ap, fmt); - vsnprintf(buf, 128, fmt, ap); - va_end(ap); - - local_irq_save(irq_flags); - fiq_debugger_puts(state, buf); - fiq_debugger_uart_flush(state); - local_irq_restore(irq_flags); - return state->debug_abort; -} - -static void fiq_debugger_dump_irqs(struct fiq_debugger_state *state) -{ - int n; - struct irq_desc *desc; - - fiq_debugger_printf(&state->output, - "irqnr total since-last status name\n"); - for_each_irq_desc(n, desc) { - struct irqaction *act = desc->action; - if (!act && !kstat_irqs(n)) - continue; - fiq_debugger_printf(&state->output, "%5d: %10u %11u %8x %s\n", n, - kstat_irqs(n), - kstat_irqs(n) - state->last_irqs[n], - desc->status_use_accessors, - (act && act->name) ? act->name : "???"); - state->last_irqs[n] = kstat_irqs(n); - } -} - -static void fiq_debugger_do_ps(struct fiq_debugger_state *state) -{ - struct task_struct *g; - struct task_struct *p; - unsigned task_state; - static const char stat_nam[] = "RSDTtZX"; - - fiq_debugger_printf(&state->output, "pid ppid prio task pc\n"); - read_lock(&tasklist_lock); - do_each_thread(g, p) { - task_state = p->state ? __ffs(p->state) + 1 : 0; - fiq_debugger_printf(&state->output, - "%5d %5d %4d ", p->pid, p->parent->pid, p->prio); - fiq_debugger_printf(&state->output, "%-13.13s %c", p->comm, - task_state >= sizeof(stat_nam) ? '?' : stat_nam[task_state]); - if (task_state == TASK_RUNNING) - fiq_debugger_printf(&state->output, " running\n"); - else - fiq_debugger_printf(&state->output, " %08lx\n", - thread_saved_pc(p)); - } while_each_thread(g, p); - read_unlock(&tasklist_lock); -} - -#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE -static void fiq_debugger_begin_syslog_dump(struct fiq_debugger_state *state) -{ - state->syslog_dumping = true; -} - -static void fiq_debugger_end_syslog_dump(struct fiq_debugger_state *state) -{ - state->syslog_dumping = false; -} -#else -extern int do_syslog(int type, char __user *bug, int count); -static void fiq_debugger_begin_syslog_dump(struct fiq_debugger_state *state) -{ - do_syslog(5 /* clear */, NULL, 0); -} - -static void fiq_debugger_end_syslog_dump(struct fiq_debugger_state *state) -{ - fiq_debugger_dump_kernel_log(state); -} -#endif - -static void fiq_debugger_do_sysrq(struct fiq_debugger_state *state, char rq) -{ - if ((rq == 'g' || rq == 'G') && !fiq_kgdb_enable) { - fiq_debugger_printf(&state->output, "sysrq-g blocked\n"); - return; - } - fiq_debugger_begin_syslog_dump(state); - handle_sysrq(rq); - fiq_debugger_end_syslog_dump(state); -} - -#ifdef CONFIG_KGDB -static void fiq_debugger_do_kgdb(struct fiq_debugger_state *state) -{ - if (!fiq_kgdb_enable) { - fiq_debugger_printf(&state->output, "kgdb through fiq debugger not enabled\n"); - return; - } - - fiq_debugger_printf(&state->output, "enabling console and triggering kgdb\n"); - state->console_enable = true; - handle_sysrq('g'); -} -#endif - -static void fiq_debugger_schedule_work(struct fiq_debugger_state *state, - char *cmd) -{ - unsigned long flags; - - spin_lock_irqsave(&state->work_lock, flags); - if (state->work_cmd[0] != '\0') { - fiq_debugger_printf(&state->output, "work command processor busy\n"); - spin_unlock_irqrestore(&state->work_lock, flags); - return; - } - - strlcpy(state->work_cmd, cmd, sizeof(state->work_cmd)); - spin_unlock_irqrestore(&state->work_lock, flags); - - schedule_work(&state->work); -} - -static void fiq_debugger_work(struct work_struct *work) -{ - struct fiq_debugger_state *state; - char work_cmd[DEBUG_MAX]; - char *cmd; - unsigned long flags; - - state = container_of(work, struct fiq_debugger_state, work); - - spin_lock_irqsave(&state->work_lock, flags); - - strlcpy(work_cmd, state->work_cmd, sizeof(work_cmd)); - state->work_cmd[0] = '\0'; - - spin_unlock_irqrestore(&state->work_lock, flags); - - cmd = work_cmd; - if (!strncmp(cmd, "reboot", 6)) { - cmd += 6; - while (*cmd == ' ') - cmd++; - if (*cmd != '\0') - kernel_restart(cmd); - else - kernel_restart(NULL); - } else { - fiq_debugger_printf(&state->output, "unknown work command '%s'\n", - work_cmd); - } -} - -/* This function CANNOT be called in FIQ context */ -static void fiq_debugger_irq_exec(struct fiq_debugger_state *state, char *cmd) -{ - if (!strcmp(cmd, "ps")) - fiq_debugger_do_ps(state); - if (!strcmp(cmd, "sysrq")) - fiq_debugger_do_sysrq(state, 'h'); - if (!strncmp(cmd, "sysrq ", 6)) - fiq_debugger_do_sysrq(state, cmd[6]); -#ifdef CONFIG_KGDB - if (!strcmp(cmd, "kgdb")) - fiq_debugger_do_kgdb(state); -#endif - if (!strncmp(cmd, "reboot", 6)) - fiq_debugger_schedule_work(state, cmd); -} - -static void fiq_debugger_help(struct fiq_debugger_state *state) -{ - fiq_debugger_printf(&state->output, - "FIQ Debugger commands:\n" - " pc PC status\n" - " regs Register dump\n" - " allregs Extended Register dump\n" - " bt Stack trace\n" - " reboot [] Reboot with command \n" - " reset [] Hard reset with command \n" - " irqs Interupt status\n" - " kmsg Kernel log\n" - " version Kernel version\n"); - fiq_debugger_printf(&state->output, - " sleep Allow sleep while in FIQ\n" - " nosleep Disable sleep while in FIQ\n" - " console Switch terminal to console\n" - " cpu Current CPU\n" - " cpu Switch to CPU\n"); - fiq_debugger_printf(&state->output, - " ps Process list\n" - " sysrq sysrq options\n" - " sysrq Execute sysrq with \n"); -#ifdef CONFIG_KGDB - fiq_debugger_printf(&state->output, - " kgdb Enter kernel debugger\n"); -#endif -} - -static void fiq_debugger_take_affinity(void *info) -{ - struct fiq_debugger_state *state = info; - struct cpumask cpumask; - - cpumask_clear(&cpumask); - cpumask_set_cpu(get_cpu(), &cpumask); - - irq_set_affinity(state->uart_irq, &cpumask); -} - -static void fiq_debugger_switch_cpu(struct fiq_debugger_state *state, int cpu) -{ - if (!fiq_debugger_have_fiq(state)) - smp_call_function_single(cpu, fiq_debugger_take_affinity, state, - false); - state->current_cpu = cpu; -} - -static bool fiq_debugger_fiq_exec(struct fiq_debugger_state *state, - const char *cmd, const struct pt_regs *regs, - void *svc_sp) -{ - bool signal_helper = false; - - if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) { - fiq_debugger_help(state); - } else if (!strcmp(cmd, "pc")) { - fiq_debugger_dump_pc(&state->output, regs); - } else if (!strcmp(cmd, "regs")) { - fiq_debugger_dump_regs(&state->output, regs); - } else if (!strcmp(cmd, "allregs")) { - fiq_debugger_dump_allregs(&state->output, regs); - } else if (!strcmp(cmd, "bt")) { - fiq_debugger_dump_stacktrace(&state->output, regs, 100, svc_sp); - } else if (!strncmp(cmd, "reset", 5)) { - cmd += 5; - while (*cmd == ' ') - cmd++; - if (*cmd) { - char tmp_cmd[32]; - strlcpy(tmp_cmd, cmd, sizeof(tmp_cmd)); - machine_restart(tmp_cmd); - } else { - machine_restart(NULL); - } - } else if (!strcmp(cmd, "irqs")) { - fiq_debugger_dump_irqs(state); - } else if (!strcmp(cmd, "kmsg")) { - fiq_debugger_dump_kernel_log(state); - } else if (!strcmp(cmd, "version")) { - fiq_debugger_printf(&state->output, "%s\n", linux_banner); - } else if (!strcmp(cmd, "sleep")) { - state->no_sleep = false; - fiq_debugger_printf(&state->output, "enabling sleep\n"); - } else if (!strcmp(cmd, "nosleep")) { - state->no_sleep = true; - fiq_debugger_printf(&state->output, "disabling sleep\n"); - } else if (!strcmp(cmd, "console")) { - fiq_debugger_printf(&state->output, "console mode\n"); - fiq_debugger_uart_flush(state); - state->console_enable = true; - } else if (!strcmp(cmd, "cpu")) { - fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu); - } else if (!strncmp(cmd, "cpu ", 4)) { - unsigned long cpu = 0; - if (kstrtoul(cmd + 4, 10, &cpu) == 0) - fiq_debugger_switch_cpu(state, cpu); - else - fiq_debugger_printf(&state->output, "invalid cpu\n"); - fiq_debugger_printf(&state->output, "cpu %d\n", state->current_cpu); - } else { - if (state->debug_busy) { - fiq_debugger_printf(&state->output, - "command processor busy. trying to abort.\n"); - state->debug_abort = -1; - } else { - strcpy(state->debug_cmd, cmd); - state->debug_busy = 1; - } - - return true; - } - if (!state->console_enable) - fiq_debugger_prompt(state); - - return signal_helper; -} - -static void fiq_debugger_sleep_timer_expired(unsigned long data) -{ - struct fiq_debugger_state *state = (struct fiq_debugger_state *)data; - unsigned long flags; - - spin_lock_irqsave(&state->sleep_timer_lock, flags); - if (state->uart_enabled && !state->no_sleep) { - if (state->debug_enable && !state->console_enable) { - state->debug_enable = false; - fiq_debugger_printf_nfiq(state, - "suspending fiq debugger\n"); - } - state->ignore_next_wakeup_irq = true; - fiq_debugger_uart_disable(state); - state->uart_enabled = false; - fiq_debugger_enable_wakeup_irq(state); - } - wake_unlock(&state->debugger_wake_lock); - spin_unlock_irqrestore(&state->sleep_timer_lock, flags); -} - -static void fiq_debugger_handle_wakeup(struct fiq_debugger_state *state) -{ - unsigned long flags; - - spin_lock_irqsave(&state->sleep_timer_lock, flags); - if (state->wakeup_irq >= 0 && state->ignore_next_wakeup_irq) { - state->ignore_next_wakeup_irq = false; - } else if (!state->uart_enabled) { - wake_lock(&state->debugger_wake_lock); - fiq_debugger_uart_enable(state); - state->uart_enabled = true; - fiq_debugger_disable_wakeup_irq(state); - mod_timer(&state->sleep_timer, jiffies + HZ / 2); - } - spin_unlock_irqrestore(&state->sleep_timer_lock, flags); -} - -static irqreturn_t fiq_debugger_wakeup_irq_handler(int irq, void *dev) -{ - struct fiq_debugger_state *state = dev; - - if (!state->no_sleep) - fiq_debugger_puts(state, "WAKEUP\n"); - fiq_debugger_handle_wakeup(state); - - return IRQ_HANDLED; -} - -static -void fiq_debugger_handle_console_irq_context(struct fiq_debugger_state *state) -{ -#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) - if (state->tty_port.ops) { - int i; - int count = fiq_debugger_ringbuf_level(state->tty_rbuf); - for (i = 0; i < count; i++) { - int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0); - tty_insert_flip_char(&state->tty_port, c, TTY_NORMAL); - if (!fiq_debugger_ringbuf_consume(state->tty_rbuf, 1)) - pr_warn("fiq tty failed to consume byte\n"); - } - tty_flip_buffer_push(&state->tty_port); - } -#endif -} - -static void fiq_debugger_handle_irq_context(struct fiq_debugger_state *state) -{ - if (!state->no_sleep) { - unsigned long flags; - - spin_lock_irqsave(&state->sleep_timer_lock, flags); - wake_lock(&state->debugger_wake_lock); - mod_timer(&state->sleep_timer, jiffies + HZ * 5); - spin_unlock_irqrestore(&state->sleep_timer_lock, flags); - } - fiq_debugger_handle_console_irq_context(state); - if (state->debug_busy) { - fiq_debugger_irq_exec(state, state->debug_cmd); - if (!state->console_enable) - fiq_debugger_prompt(state); - state->debug_busy = 0; - } -} - -static int fiq_debugger_getc(struct fiq_debugger_state *state) -{ - return state->pdata->uart_getc(state->pdev); -} - -static bool fiq_debugger_handle_uart_interrupt(struct fiq_debugger_state *state, - int this_cpu, const struct pt_regs *regs, void *svc_sp) -{ - int c; - static int last_c; - int count = 0; - bool signal_helper = false; - - if (this_cpu != state->current_cpu) { - if (state->in_fiq) - return false; - - if (atomic_inc_return(&state->unhandled_fiq_count) != - MAX_UNHANDLED_FIQ_COUNT) - return false; - - fiq_debugger_printf(&state->output, - "fiq_debugger: cpu %d not responding, " - "reverting to cpu %d\n", state->current_cpu, - this_cpu); - - atomic_set(&state->unhandled_fiq_count, 0); - fiq_debugger_switch_cpu(state, this_cpu); - return false; - } - - state->in_fiq = true; - - while ((c = fiq_debugger_getc(state)) != FIQ_DEBUGGER_NO_CHAR) { - count++; - if (!state->debug_enable) { - if ((c == 13) || (c == 10)) { - state->debug_enable = true; - state->debug_count = 0; - fiq_debugger_prompt(state); - } - } else if (c == FIQ_DEBUGGER_BREAK) { - state->console_enable = false; - fiq_debugger_puts(state, "fiq debugger mode\n"); - state->debug_count = 0; - fiq_debugger_prompt(state); -#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE - } else if (state->console_enable && state->tty_rbuf) { - fiq_debugger_ringbuf_push(state->tty_rbuf, c); - signal_helper = true; -#endif - } else if ((c >= ' ') && (c < 127)) { - if (state->debug_count < (DEBUG_MAX - 1)) { - state->debug_buf[state->debug_count++] = c; - fiq_debugger_putc(state, c); - } - } else if ((c == 8) || (c == 127)) { - if (state->debug_count > 0) { - state->debug_count--; - fiq_debugger_putc(state, 8); - fiq_debugger_putc(state, ' '); - fiq_debugger_putc(state, 8); - } - } else if ((c == 13) || (c == 10)) { - if (c == '\r' || (c == '\n' && last_c != '\r')) { - fiq_debugger_putc(state, '\r'); - fiq_debugger_putc(state, '\n'); - } - if (state->debug_count) { - state->debug_buf[state->debug_count] = 0; - state->debug_count = 0; - signal_helper |= - fiq_debugger_fiq_exec(state, - state->debug_buf, - regs, svc_sp); - } else { - fiq_debugger_prompt(state); - } - } - last_c = c; - } - if (!state->console_enable) - fiq_debugger_uart_flush(state); - if (state->pdata->fiq_ack) - state->pdata->fiq_ack(state->pdev, state->fiq); - - /* poke sleep timer if necessary */ - if (state->debug_enable && !state->no_sleep) - signal_helper = true; - - atomic_set(&state->unhandled_fiq_count, 0); - state->in_fiq = false; - - return signal_helper; -} - -#ifdef CONFIG_FIQ_GLUE -static void fiq_debugger_fiq(struct fiq_glue_handler *h, - const struct pt_regs *regs, void *svc_sp) -{ - struct fiq_debugger_state *state = - container_of(h, struct fiq_debugger_state, handler); - unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu; - bool need_irq; - - need_irq = fiq_debugger_handle_uart_interrupt(state, this_cpu, regs, - svc_sp); - if (need_irq) - fiq_debugger_force_irq(state); -} -#endif - -/* - * When not using FIQs, we only use this single interrupt as an entry point. - * This just effectively takes over the UART interrupt and does all the work - * in this context. - */ -static irqreturn_t fiq_debugger_uart_irq(int irq, void *dev) -{ - struct fiq_debugger_state *state = dev; - bool not_done; - - fiq_debugger_handle_wakeup(state); - - /* handle the debugger irq in regular context */ - not_done = fiq_debugger_handle_uart_interrupt(state, smp_processor_id(), - get_irq_regs(), - current_thread_info()); - if (not_done) - fiq_debugger_handle_irq_context(state); - - return IRQ_HANDLED; -} - -/* - * If FIQs are used, not everything can happen in fiq context. - * FIQ handler does what it can and then signals this interrupt to finish the - * job in irq context. - */ -static irqreturn_t fiq_debugger_signal_irq(int irq, void *dev) -{ - struct fiq_debugger_state *state = dev; - - if (state->pdata->force_irq_ack) - state->pdata->force_irq_ack(state->pdev, state->signal_irq); - - fiq_debugger_handle_irq_context(state); - - return IRQ_HANDLED; -} - -#ifdef CONFIG_FIQ_GLUE -static void fiq_debugger_resume(struct fiq_glue_handler *h) -{ - struct fiq_debugger_state *state = - container_of(h, struct fiq_debugger_state, handler); - if (state->pdata->uart_resume) - state->pdata->uart_resume(state->pdev); -} -#endif - -#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) -struct tty_driver *fiq_debugger_console_device(struct console *co, int *index) -{ - *index = co->index; - return fiq_tty_driver; -} - -static void fiq_debugger_console_write(struct console *co, - const char *s, unsigned int count) -{ - struct fiq_debugger_state *state; - unsigned long flags; - - state = container_of(co, struct fiq_debugger_state, console); - - if (!state->console_enable && !state->syslog_dumping) - return; - - fiq_debugger_uart_enable(state); - spin_lock_irqsave(&state->console_lock, flags); - while (count--) { - if (*s == '\n') - fiq_debugger_putc(state, '\r'); - fiq_debugger_putc(state, *s++); - } - fiq_debugger_uart_flush(state); - spin_unlock_irqrestore(&state->console_lock, flags); - fiq_debugger_uart_disable(state); -} - -static struct console fiq_debugger_console = { - .name = "ttyFIQ", - .device = fiq_debugger_console_device, - .write = fiq_debugger_console_write, - .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_ENABLED, -}; - -int fiq_tty_open(struct tty_struct *tty, struct file *filp) -{ - int line = tty->index; - struct fiq_debugger_state **states = tty->driver->driver_state; - struct fiq_debugger_state *state = states[line]; - - return tty_port_open(&state->tty_port, tty, filp); -} - -void fiq_tty_close(struct tty_struct *tty, struct file *filp) -{ - tty_port_close(tty->port, tty, filp); -} - -int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) -{ - int i; - int line = tty->index; - struct fiq_debugger_state **states = tty->driver->driver_state; - struct fiq_debugger_state *state = states[line]; - - if (!state->console_enable) - return count; - - fiq_debugger_uart_enable(state); - spin_lock_irq(&state->console_lock); - for (i = 0; i < count; i++) - fiq_debugger_putc(state, *buf++); - spin_unlock_irq(&state->console_lock); - fiq_debugger_uart_disable(state); - - return count; -} - -int fiq_tty_write_room(struct tty_struct *tty) -{ - return 16; -} - -#ifdef CONFIG_CONSOLE_POLL -static int fiq_tty_poll_init(struct tty_driver *driver, int line, char *options) -{ - return 0; -} - -static int fiq_tty_poll_get_char(struct tty_driver *driver, int line) -{ - struct fiq_debugger_state **states = driver->driver_state; - struct fiq_debugger_state *state = states[line]; - int c = NO_POLL_CHAR; - - fiq_debugger_uart_enable(state); - if (fiq_debugger_have_fiq(state)) { - int count = fiq_debugger_ringbuf_level(state->tty_rbuf); - if (count > 0) { - c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0); - fiq_debugger_ringbuf_consume(state->tty_rbuf, 1); - } - } else { - c = fiq_debugger_getc(state); - if (c == FIQ_DEBUGGER_NO_CHAR) - c = NO_POLL_CHAR; - } - fiq_debugger_uart_disable(state); - - return c; -} - -static void fiq_tty_poll_put_char(struct tty_driver *driver, int line, char ch) -{ - struct fiq_debugger_state **states = driver->driver_state; - struct fiq_debugger_state *state = states[line]; - fiq_debugger_uart_enable(state); - fiq_debugger_putc(state, ch); - fiq_debugger_uart_disable(state); -} -#endif - -static const struct tty_port_operations fiq_tty_port_ops; - -static const struct tty_operations fiq_tty_driver_ops = { - .write = fiq_tty_write, - .write_room = fiq_tty_write_room, - .open = fiq_tty_open, - .close = fiq_tty_close, -#ifdef CONFIG_CONSOLE_POLL - .poll_init = fiq_tty_poll_init, - .poll_get_char = fiq_tty_poll_get_char, - .poll_put_char = fiq_tty_poll_put_char, -#endif -}; - -static int fiq_debugger_tty_init(void) -{ - int ret; - struct fiq_debugger_state **states = NULL; - - states = kzalloc(sizeof(*states) * MAX_FIQ_DEBUGGER_PORTS, GFP_KERNEL); - if (!states) { - pr_err("Failed to allocate fiq debugger state structres\n"); - return -ENOMEM; - } - - fiq_tty_driver = alloc_tty_driver(MAX_FIQ_DEBUGGER_PORTS); - if (!fiq_tty_driver) { - pr_err("Failed to allocate fiq debugger tty\n"); - ret = -ENOMEM; - goto err_free_state; - } - - fiq_tty_driver->owner = THIS_MODULE; - fiq_tty_driver->driver_name = "fiq-debugger"; - fiq_tty_driver->name = "ttyFIQ"; - fiq_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - fiq_tty_driver->subtype = SERIAL_TYPE_NORMAL; - fiq_tty_driver->init_termios = tty_std_termios; - fiq_tty_driver->flags = TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV; - fiq_tty_driver->driver_state = states; - - fiq_tty_driver->init_termios.c_cflag = - B115200 | CS8 | CREAD | HUPCL | CLOCAL; - fiq_tty_driver->init_termios.c_ispeed = 115200; - fiq_tty_driver->init_termios.c_ospeed = 115200; - - tty_set_operations(fiq_tty_driver, &fiq_tty_driver_ops); - - ret = tty_register_driver(fiq_tty_driver); - if (ret) { - pr_err("Failed to register fiq tty: %d\n", ret); - goto err_free_tty; - } - - pr_info("Registered FIQ tty driver\n"); - return 0; - -err_free_tty: - put_tty_driver(fiq_tty_driver); - fiq_tty_driver = NULL; -err_free_state: - kfree(states); - return ret; -} - -static int fiq_debugger_tty_init_one(struct fiq_debugger_state *state) -{ - int ret; - struct device *tty_dev; - struct fiq_debugger_state **states = fiq_tty_driver->driver_state; - - states[state->pdev->id] = state; - - state->tty_rbuf = fiq_debugger_ringbuf_alloc(1024); - if (!state->tty_rbuf) { - pr_err("Failed to allocate fiq debugger ringbuf\n"); - ret = -ENOMEM; - goto err; - } - - tty_port_init(&state->tty_port); - state->tty_port.ops = &fiq_tty_port_ops; - - tty_dev = tty_port_register_device(&state->tty_port, fiq_tty_driver, - state->pdev->id, &state->pdev->dev); - if (IS_ERR(tty_dev)) { - pr_err("Failed to register fiq debugger tty device\n"); - ret = PTR_ERR(tty_dev); - goto err; - } - - device_set_wakeup_capable(tty_dev, 1); - - pr_info("Registered fiq debugger ttyFIQ%d\n", state->pdev->id); - - return 0; - -err: - fiq_debugger_ringbuf_free(state->tty_rbuf); - state->tty_rbuf = NULL; - return ret; -} -#endif - -static int fiq_debugger_dev_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct fiq_debugger_state *state = platform_get_drvdata(pdev); - - if (state->pdata->uart_dev_suspend) - return state->pdata->uart_dev_suspend(pdev); - return 0; -} - -static int fiq_debugger_dev_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct fiq_debugger_state *state = platform_get_drvdata(pdev); - - if (state->pdata->uart_dev_resume) - return state->pdata->uart_dev_resume(pdev); - return 0; -} - -static int fiq_debugger_probe(struct platform_device *pdev) -{ - int ret; - struct fiq_debugger_pdata *pdata = dev_get_platdata(&pdev->dev); - struct fiq_debugger_state *state; - int fiq; - int uart_irq; - - if (pdev->id >= MAX_FIQ_DEBUGGER_PORTS) - return -EINVAL; - - if (!pdata->uart_getc || !pdata->uart_putc) - return -EINVAL; - if ((pdata->uart_enable && !pdata->uart_disable) || - (!pdata->uart_enable && pdata->uart_disable)) - return -EINVAL; - - fiq = platform_get_irq_byname(pdev, "fiq"); - uart_irq = platform_get_irq_byname(pdev, "uart_irq"); - - /* uart_irq mode and fiq mode are mutually exclusive, but one of them - * is required */ - if ((uart_irq < 0 && fiq < 0) || (uart_irq >= 0 && fiq >= 0)) - return -EINVAL; - if (fiq >= 0 && !pdata->fiq_enable) - return -EINVAL; - - state = kzalloc(sizeof(*state), GFP_KERNEL); - state->output.printf = fiq_debugger_printf; - setup_timer(&state->sleep_timer, fiq_debugger_sleep_timer_expired, - (unsigned long)state); - state->pdata = pdata; - state->pdev = pdev; - state->no_sleep = initial_no_sleep; - state->debug_enable = initial_debug_enable; - state->console_enable = initial_console_enable; - - state->fiq = fiq; - state->uart_irq = uart_irq; - state->signal_irq = platform_get_irq_byname(pdev, "signal"); - state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup"); - - INIT_WORK(&state->work, fiq_debugger_work); - spin_lock_init(&state->work_lock); - - platform_set_drvdata(pdev, state); - - spin_lock_init(&state->sleep_timer_lock); - - if (state->wakeup_irq < 0 && fiq_debugger_have_fiq(state)) - state->no_sleep = true; - state->ignore_next_wakeup_irq = !state->no_sleep; - - wake_lock_init(&state->debugger_wake_lock, - WAKE_LOCK_SUSPEND, "serial-debug"); - - state->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(state->clk)) - state->clk = NULL; - - /* do not call pdata->uart_enable here since uart_init may still - * need to do some initialization before uart_enable can work. - * So, only try to manage the clock during init. - */ - if (state->clk) - clk_enable(state->clk); - - if (pdata->uart_init) { - ret = pdata->uart_init(pdev); - if (ret) - goto err_uart_init; - } - - fiq_debugger_printf_nfiq(state, - "\n", - state->no_sleep ? "" : "twice "); - -#ifdef CONFIG_FIQ_GLUE - if (fiq_debugger_have_fiq(state)) { - state->handler.fiq = fiq_debugger_fiq; - state->handler.resume = fiq_debugger_resume; - ret = fiq_glue_register_handler(&state->handler); - if (ret) { - pr_err("%s: could not install fiq handler\n", __func__); - goto err_register_irq; - } - - pdata->fiq_enable(pdev, state->fiq, 1); - } else -#endif - { - ret = request_irq(state->uart_irq, fiq_debugger_uart_irq, - IRQF_NO_SUSPEND, "debug", state); - if (ret) { - pr_err("%s: could not install irq handler\n", __func__); - goto err_register_irq; - } - - /* for irq-only mode, we want this irq to wake us up, if it - * can. - */ - enable_irq_wake(state->uart_irq); - } - - if (state->clk) - clk_disable(state->clk); - - if (state->signal_irq >= 0) { - ret = request_irq(state->signal_irq, fiq_debugger_signal_irq, - IRQF_TRIGGER_RISING, "debug-signal", state); - if (ret) - pr_err("serial_debugger: could not install signal_irq"); - } - - if (state->wakeup_irq >= 0) { - ret = request_irq(state->wakeup_irq, - fiq_debugger_wakeup_irq_handler, - IRQF_TRIGGER_FALLING, - "debug-wakeup", state); - if (ret) { - pr_err("serial_debugger: " - "could not install wakeup irq\n"); - state->wakeup_irq = -1; - } else { - ret = enable_irq_wake(state->wakeup_irq); - if (ret) { - pr_err("serial_debugger: " - "could not enable wakeup\n"); - state->wakeup_irq_no_set_wake = true; - } - } - } - if (state->no_sleep) - fiq_debugger_handle_wakeup(state); - -#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) - spin_lock_init(&state->console_lock); - state->console = fiq_debugger_console; - state->console.index = pdev->id; - if (!console_set_on_cmdline) - add_preferred_console(state->console.name, - state->console.index, NULL); - register_console(&state->console); - fiq_debugger_tty_init_one(state); -#endif - return 0; - -err_register_irq: - if (pdata->uart_free) - pdata->uart_free(pdev); -err_uart_init: - if (state->clk) - clk_disable(state->clk); - if (state->clk) - clk_put(state->clk); - wake_lock_destroy(&state->debugger_wake_lock); - platform_set_drvdata(pdev, NULL); - kfree(state); - return ret; -} - -static const struct dev_pm_ops fiq_debugger_dev_pm_ops = { - .suspend = fiq_debugger_dev_suspend, - .resume = fiq_debugger_dev_resume, -}; - -static struct platform_driver fiq_debugger_driver = { - .probe = fiq_debugger_probe, - .driver = { - .name = "fiq_debugger", - .pm = &fiq_debugger_dev_pm_ops, - }, -}; - -#if defined(CONFIG_FIQ_DEBUGGER_UART_OVERLAY) -int fiq_debugger_uart_overlay(void) -{ - struct device_node *onp = of_find_node_by_path("/uart_overlay@0"); - int ret; - - if (!onp) { - pr_err("serial_debugger: uart overlay not found\n"); - return -ENODEV; - } - - ret = of_overlay_create(onp); - if (ret < 0) { - pr_err("serial_debugger: fail to create overlay: %d\n", ret); - of_node_put(onp); - return ret; - } - - pr_info("serial_debugger: uart overlay applied\n"); - return 0; -} -#endif - -static int __init fiq_debugger_init(void) -{ - if (fiq_debugger_disable) { - pr_err("serial_debugger: disabled\n"); - return -ENODEV; - } -#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE) - fiq_debugger_tty_init(); -#endif -#if defined(CONFIG_FIQ_DEBUGGER_UART_OVERLAY) - fiq_debugger_uart_overlay(); -#endif - return platform_driver_register(&fiq_debugger_driver); -} - -postcore_initcall(fiq_debugger_init); diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger.h b/drivers/staging/android/fiq_debugger/fiq_debugger.h deleted file mode 100644 index c9ec4f8db086..000000000000 --- a/drivers/staging/android/fiq_debugger/fiq_debugger.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * drivers/staging/android/fiq_debugger/fiq_debugger.h - * - * Copyright (C) 2010 Google, Inc. - * Author: Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _ARCH_ARM_MACH_TEGRA_FIQ_DEBUGGER_H_ -#define _ARCH_ARM_MACH_TEGRA_FIQ_DEBUGGER_H_ - -#include - -#define FIQ_DEBUGGER_NO_CHAR NO_POLL_CHAR -#define FIQ_DEBUGGER_BREAK 0x00ff0100 - -#define FIQ_DEBUGGER_FIQ_IRQ_NAME "fiq" -#define FIQ_DEBUGGER_SIGNAL_IRQ_NAME "signal" -#define FIQ_DEBUGGER_WAKEUP_IRQ_NAME "wakeup" - -/** - * struct fiq_debugger_pdata - fiq debugger platform data - * @uart_resume: used to restore uart state right before enabling - * the fiq. - * @uart_enable: Do the work necessary to communicate with the uart - * hw (enable clocks, etc.). This must be ref-counted. - * @uart_disable: Do the work necessary to disable the uart hw - * (disable clocks, etc.). This must be ref-counted. - * @uart_dev_suspend: called during PM suspend, generally not needed - * for real fiq mode debugger. - * @uart_dev_resume: called during PM resume, generally not needed - * for real fiq mode debugger. - */ -struct fiq_debugger_pdata { - int (*uart_init)(struct platform_device *pdev); - void (*uart_free)(struct platform_device *pdev); - int (*uart_resume)(struct platform_device *pdev); - int (*uart_getc)(struct platform_device *pdev); - void (*uart_putc)(struct platform_device *pdev, unsigned int c); - void (*uart_flush)(struct platform_device *pdev); - void (*uart_enable)(struct platform_device *pdev); - void (*uart_disable)(struct platform_device *pdev); - - int (*uart_dev_suspend)(struct platform_device *pdev); - int (*uart_dev_resume)(struct platform_device *pdev); - - void (*fiq_enable)(struct platform_device *pdev, unsigned int fiq, - bool enable); - void (*fiq_ack)(struct platform_device *pdev, unsigned int fiq); - - void (*force_irq)(struct platform_device *pdev, unsigned int irq); - void (*force_irq_ack)(struct platform_device *pdev, unsigned int irq); -}; - -#endif diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c deleted file mode 100644 index 8b3e0137be1a..000000000000 --- a/drivers/staging/android/fiq_debugger/fiq_debugger_arm.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2014 Google, Inc. - * Author: Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include - -#include - -#include "fiq_debugger_priv.h" - -static char *mode_name(unsigned cpsr) -{ - switch (cpsr & MODE_MASK) { - case USR_MODE: return "USR"; - case FIQ_MODE: return "FIQ"; - case IRQ_MODE: return "IRQ"; - case SVC_MODE: return "SVC"; - case ABT_MODE: return "ABT"; - case UND_MODE: return "UND"; - case SYSTEM_MODE: return "SYS"; - default: return "???"; - } -} - -void fiq_debugger_dump_pc(struct fiq_debugger_output *output, - const struct pt_regs *regs) -{ - output->printf(output, " pc %08x cpsr %08x mode %s\n", - regs->ARM_pc, regs->ARM_cpsr, mode_name(regs->ARM_cpsr)); -} - -void fiq_debugger_dump_regs(struct fiq_debugger_output *output, - const struct pt_regs *regs) -{ - output->printf(output, - " r0 %08x r1 %08x r2 %08x r3 %08x\n", - regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3); - output->printf(output, - " r4 %08x r5 %08x r6 %08x r7 %08x\n", - regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7); - output->printf(output, - " r8 %08x r9 %08x r10 %08x r11 %08x mode %s\n", - regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp, - mode_name(regs->ARM_cpsr)); - output->printf(output, - " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", - regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc, - regs->ARM_cpsr); -} - -struct mode_regs { - unsigned long sp_svc; - unsigned long lr_svc; - unsigned long spsr_svc; - - unsigned long sp_abt; - unsigned long lr_abt; - unsigned long spsr_abt; - - unsigned long sp_und; - unsigned long lr_und; - unsigned long spsr_und; - - unsigned long sp_irq; - unsigned long lr_irq; - unsigned long spsr_irq; - - unsigned long r8_fiq; - unsigned long r9_fiq; - unsigned long r10_fiq; - unsigned long r11_fiq; - unsigned long r12_fiq; - unsigned long sp_fiq; - unsigned long lr_fiq; - unsigned long spsr_fiq; -}; - -static void __naked get_mode_regs(struct mode_regs *regs) -{ - asm volatile ( - "mrs r1, cpsr\n" - "msr cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r13 - r14}\n" - "mrs r2, spsr\n" - "msr cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n" - "stmia r0!, {r2, r8 - r14}\n" - "mrs r2, spsr\n" - "stmia r0!, {r2}\n" - "msr cpsr_c, r1\n" - "bx lr\n"); -} - - -void fiq_debugger_dump_allregs(struct fiq_debugger_output *output, - const struct pt_regs *regs) -{ - struct mode_regs mode_regs; - unsigned long mode = regs->ARM_cpsr & MODE_MASK; - - fiq_debugger_dump_regs(output, regs); - get_mode_regs(&mode_regs); - - output->printf(output, - "%csvc: sp %08x lr %08x spsr %08x\n", - mode == SVC_MODE ? '*' : ' ', - mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc); - output->printf(output, - "%cabt: sp %08x lr %08x spsr %08x\n", - mode == ABT_MODE ? '*' : ' ', - mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt); - output->printf(output, - "%cund: sp %08x lr %08x spsr %08x\n", - mode == UND_MODE ? '*' : ' ', - mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und); - output->printf(output, - "%cirq: sp %08x lr %08x spsr %08x\n", - mode == IRQ_MODE ? '*' : ' ', - mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq); - output->printf(output, - "%cfiq: r8 %08x r9 %08x r10 %08x r11 %08x r12 %08x\n", - mode == FIQ_MODE ? '*' : ' ', - mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq, - mode_regs.r11_fiq, mode_regs.r12_fiq); - output->printf(output, - " fiq: sp %08x lr %08x spsr %08x\n", - mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq); -} - -struct stacktrace_state { - struct fiq_debugger_output *output; - unsigned int depth; -}; - -static int report_trace(struct stackframe *frame, void *d) -{ - struct stacktrace_state *sts = d; - - if (sts->depth) { - sts->output->printf(sts->output, - " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", - frame->pc, frame->pc, frame->lr, frame->lr, - frame->sp, frame->fp); - sts->depth--; - return 0; - } - sts->output->printf(sts->output, " ...\n"); - - return sts->depth == 0; -} - -struct frame_tail { - struct frame_tail *fp; - unsigned long sp; - unsigned long lr; -} __attribute__((packed)); - -static struct frame_tail *user_backtrace(struct fiq_debugger_output *output, - struct frame_tail *tail) -{ - struct frame_tail buftail[2]; - - /* Also check accessibility of one struct frame_tail beyond */ - if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) { - output->printf(output, " invalid frame pointer %p\n", - tail); - return NULL; - } - if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) { - output->printf(output, - " failed to copy frame pointer %p\n", tail); - return NULL; - } - - output->printf(output, " %p\n", buftail[0].lr); - - /* frame pointers should strictly progress back up the stack - * (towards higher addresses) */ - if (tail >= buftail[0].fp) - return NULL; - - return buftail[0].fp-1; -} - -void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output, - const struct pt_regs *regs, unsigned int depth, void *ssp) -{ - struct frame_tail *tail; - struct thread_info *real_thread_info = THREAD_INFO(ssp); - struct stacktrace_state sts; - - sts.depth = depth; - sts.output = output; - *current_thread_info() = *real_thread_info; - - if (!current) - output->printf(output, "current NULL\n"); - else - output->printf(output, "pid: %d comm: %s\n", - current->pid, current->comm); - fiq_debugger_dump_regs(output, regs); - - if (!user_mode(regs)) { - struct stackframe frame; - frame.fp = regs->ARM_fp; - frame.sp = regs->ARM_sp; - frame.lr = regs->ARM_lr; - frame.pc = regs->ARM_pc; - output->printf(output, - " pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n", - regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr, - regs->ARM_sp, regs->ARM_fp); - walk_stackframe(&frame, report_trace, &sts); - return; - } - - tail = ((struct frame_tail *) regs->ARM_fp) - 1; - while (depth-- && tail && !((unsigned long) tail & 3)) - tail = user_backtrace(output, tail); -} diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c b/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c deleted file mode 100644 index 97246bcbcd62..000000000000 --- a/drivers/staging/android/fiq_debugger/fiq_debugger_arm64.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2014 Google, Inc. - * Author: Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include - -#include "fiq_debugger_priv.h" - -static char *mode_name(const struct pt_regs *regs) -{ - if (compat_user_mode(regs)) { - return "USR"; - } else { - switch (processor_mode(regs)) { - case PSR_MODE_EL0t: return "EL0t"; - case PSR_MODE_EL1t: return "EL1t"; - case PSR_MODE_EL1h: return "EL1h"; - case PSR_MODE_EL2t: return "EL2t"; - case PSR_MODE_EL2h: return "EL2h"; - default: return "???"; - } - } -} - -void fiq_debugger_dump_pc(struct fiq_debugger_output *output, - const struct pt_regs *regs) -{ - output->printf(output, " pc %016lx cpsr %08lx mode %s\n", - regs->pc, regs->pstate, mode_name(regs)); -} - -void fiq_debugger_dump_regs_aarch32(struct fiq_debugger_output *output, - const struct pt_regs *regs) -{ - output->printf(output, " r0 %08x r1 %08x r2 %08x r3 %08x\n", - regs->compat_usr(0), regs->compat_usr(1), - regs->compat_usr(2), regs->compat_usr(3)); - output->printf(output, " r4 %08x r5 %08x r6 %08x r7 %08x\n", - regs->compat_usr(4), regs->compat_usr(5), - regs->compat_usr(6), regs->compat_usr(7)); - output->printf(output, " r8 %08x r9 %08x r10 %08x r11 %08x\n", - regs->compat_usr(8), regs->compat_usr(9), - regs->compat_usr(10), regs->compat_usr(11)); - output->printf(output, " ip %08x sp %08x lr %08x pc %08x\n", - regs->compat_usr(12), regs->compat_sp, - regs->compat_lr, regs->pc); - output->printf(output, " cpsr %08x (%s)\n", - regs->pstate, mode_name(regs)); -} - -void fiq_debugger_dump_regs_aarch64(struct fiq_debugger_output *output, - const struct pt_regs *regs) -{ - - output->printf(output, " x0 %016lx x1 %016lx\n", - regs->regs[0], regs->regs[1]); - output->printf(output, " x2 %016lx x3 %016lx\n", - regs->regs[2], regs->regs[3]); - output->printf(output, " x4 %016lx x5 %016lx\n", - regs->regs[4], regs->regs[5]); - output->printf(output, " x6 %016lx x7 %016lx\n", - regs->regs[6], regs->regs[7]); - output->printf(output, " x8 %016lx x9 %016lx\n", - regs->regs[8], regs->regs[9]); - output->printf(output, " x10 %016lx x11 %016lx\n", - regs->regs[10], regs->regs[11]); - output->printf(output, " x12 %016lx x13 %016lx\n", - regs->regs[12], regs->regs[13]); - output->printf(output, " x14 %016lx x15 %016lx\n", - regs->regs[14], regs->regs[15]); - output->printf(output, " x16 %016lx x17 %016lx\n", - regs->regs[16], regs->regs[17]); - output->printf(output, " x18 %016lx x19 %016lx\n", - regs->regs[18], regs->regs[19]); - output->printf(output, " x20 %016lx x21 %016lx\n", - regs->regs[20], regs->regs[21]); - output->printf(output, " x22 %016lx x23 %016lx\n", - regs->regs[22], regs->regs[23]); - output->printf(output, " x24 %016lx x25 %016lx\n", - regs->regs[24], regs->regs[25]); - output->printf(output, " x26 %016lx x27 %016lx\n", - regs->regs[26], regs->regs[27]); - output->printf(output, " x28 %016lx x29 %016lx\n", - regs->regs[28], regs->regs[29]); - output->printf(output, " x30 %016lx sp %016lx\n", - regs->regs[30], regs->sp); - output->printf(output, " pc %016lx cpsr %08x (%s)\n", - regs->pc, regs->pstate, mode_name(regs)); -} - -void fiq_debugger_dump_regs(struct fiq_debugger_output *output, - const struct pt_regs *regs) -{ - if (compat_user_mode(regs)) - fiq_debugger_dump_regs_aarch32(output, regs); - else - fiq_debugger_dump_regs_aarch64(output, regs); -} - -#define READ_SPECIAL_REG(x) ({ \ - u64 val; \ - asm volatile ("mrs %0, " # x : "=r"(val)); \ - val; \ -}) - -void fiq_debugger_dump_allregs(struct fiq_debugger_output *output, - const struct pt_regs *regs) -{ - u32 pstate = READ_SPECIAL_REG(CurrentEl); - bool in_el2 = (pstate & PSR_MODE_MASK) >= PSR_MODE_EL2t; - - fiq_debugger_dump_regs(output, regs); - - output->printf(output, " sp_el0 %016lx\n", - READ_SPECIAL_REG(sp_el0)); - - if (in_el2) - output->printf(output, " sp_el1 %016lx\n", - READ_SPECIAL_REG(sp_el1)); - - output->printf(output, " elr_el1 %016lx\n", - READ_SPECIAL_REG(elr_el1)); - - output->printf(output, " spsr_el1 %08lx\n", - READ_SPECIAL_REG(spsr_el1)); - - if (in_el2) { - output->printf(output, " spsr_irq %08lx\n", - READ_SPECIAL_REG(spsr_irq)); - output->printf(output, " spsr_abt %08lx\n", - READ_SPECIAL_REG(spsr_abt)); - output->printf(output, " spsr_und %08lx\n", - READ_SPECIAL_REG(spsr_und)); - output->printf(output, " spsr_fiq %08lx\n", - READ_SPECIAL_REG(spsr_fiq)); - output->printf(output, " spsr_el2 %08lx\n", - READ_SPECIAL_REG(elr_el2)); - output->printf(output, " spsr_el2 %08lx\n", - READ_SPECIAL_REG(spsr_el2)); - } -} - -struct stacktrace_state { - struct fiq_debugger_output *output; - unsigned int depth; -}; - -static int report_trace(struct stackframe *frame, void *d) -{ - struct stacktrace_state *sts = d; - - if (sts->depth) { - sts->output->printf(sts->output, "%pF:\n", frame->pc); - sts->output->printf(sts->output, - " pc %016lx sp %016lx fp %016lx\n", - frame->pc, frame->sp, frame->fp); - sts->depth--; - return 0; - } - sts->output->printf(sts->output, " ...\n"); - - return sts->depth == 0; -} - -void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output, - const struct pt_regs *regs, unsigned int depth, void *ssp) -{ - struct thread_info *real_thread_info = THREAD_INFO(ssp); - struct stacktrace_state sts; - - sts.depth = depth; - sts.output = output; - *current_thread_info() = *real_thread_info; - - if (!current) - output->printf(output, "current NULL\n"); - else - output->printf(output, "pid: %d comm: %s\n", - current->pid, current->comm); - fiq_debugger_dump_regs(output, regs); - - if (!user_mode(regs)) { - struct stackframe frame; - frame.fp = regs->regs[29]; - frame.sp = regs->sp; - frame.pc = regs->pc; - output->printf(output, "\n"); - walk_stackframe(current, &frame, report_trace, &sts); - } -} diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h b/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h deleted file mode 100644 index d5d051f727a8..000000000000 --- a/drivers/staging/android/fiq_debugger/fiq_debugger_priv.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2014 Google, Inc. - * Author: Colin Cross - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _FIQ_DEBUGGER_PRIV_H_ -#define _FIQ_DEBUGGER_PRIV_H_ - -#define THREAD_INFO(sp) ((struct thread_info *) \ - ((unsigned long)(sp) & ~(THREAD_SIZE - 1))) - -struct fiq_debugger_output { - void (*printf)(struct fiq_debugger_output *output, const char *fmt, ...); -}; - -struct pt_regs; - -void fiq_debugger_dump_pc(struct fiq_debugger_output *output, - const struct pt_regs *regs); -void fiq_debugger_dump_regs(struct fiq_debugger_output *output, - const struct pt_regs *regs); -void fiq_debugger_dump_allregs(struct fiq_debugger_output *output, - const struct pt_regs *regs); -void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output, - const struct pt_regs *regs, unsigned int depth, void *ssp); - -#endif diff --git a/drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h b/drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h deleted file mode 100644 index 10c3c5d09098..000000000000 --- a/drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * drivers/staging/android/fiq_debugger/fiq_debugger_ringbuf.h - * - * simple lockless ringbuffer - * - * Copyright (C) 2010 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include - -struct fiq_debugger_ringbuf { - int len; - int head; - int tail; - u8 buf[]; -}; - - -static inline struct fiq_debugger_ringbuf *fiq_debugger_ringbuf_alloc(int len) -{ - struct fiq_debugger_ringbuf *rbuf; - - rbuf = kzalloc(sizeof(*rbuf) + len, GFP_KERNEL); - if (rbuf == NULL) - return NULL; - - rbuf->len = len; - rbuf->head = 0; - rbuf->tail = 0; - smp_mb(); - - return rbuf; -} - -static inline void fiq_debugger_ringbuf_free(struct fiq_debugger_ringbuf *rbuf) -{ - kfree(rbuf); -} - -static inline int fiq_debugger_ringbuf_level(struct fiq_debugger_ringbuf *rbuf) -{ - int level = rbuf->head - rbuf->tail; - - if (level < 0) - level = rbuf->len + level; - - return level; -} - -static inline int fiq_debugger_ringbuf_room(struct fiq_debugger_ringbuf *rbuf) -{ - return rbuf->len - fiq_debugger_ringbuf_level(rbuf) - 1; -} - -static inline u8 -fiq_debugger_ringbuf_peek(struct fiq_debugger_ringbuf *rbuf, int i) -{ - return rbuf->buf[(rbuf->tail + i) % rbuf->len]; -} - -static inline int -fiq_debugger_ringbuf_consume(struct fiq_debugger_ringbuf *rbuf, int count) -{ - count = min(count, fiq_debugger_ringbuf_level(rbuf)); - - rbuf->tail = (rbuf->tail + count) % rbuf->len; - smp_mb(); - - return count; -} - -static inline int -fiq_debugger_ringbuf_push(struct fiq_debugger_ringbuf *rbuf, u8 datum) -{ - if (fiq_debugger_ringbuf_room(rbuf) == 0) - return 0; - - rbuf->buf[rbuf->head] = datum; - smp_mb(); - rbuf->head = (rbuf->head + 1) % rbuf->len; - smp_mb(); - - return 1; -} diff --git a/drivers/staging/android/fiq_debugger/fiq_watchdog.c b/drivers/staging/android/fiq_debugger/fiq_watchdog.c deleted file mode 100644 index 194b54138417..000000000000 --- a/drivers/staging/android/fiq_debugger/fiq_watchdog.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2014 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include - -#include "fiq_watchdog.h" -#include "fiq_debugger_priv.h" - -static DEFINE_RAW_SPINLOCK(fiq_watchdog_lock); - -static void fiq_watchdog_printf(struct fiq_debugger_output *output, - const char *fmt, ...) -{ - char buf[256]; - va_list ap; - int len; - - va_start(ap, fmt); - len = vscnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - ramoops_console_write_buf(buf, len); -} - -struct fiq_debugger_output fiq_watchdog_output = { - .printf = fiq_watchdog_printf, -}; - -void fiq_watchdog_triggered(const struct pt_regs *regs, void *svc_sp) -{ - char msg[24]; - int len; - - raw_spin_lock(&fiq_watchdog_lock); - - len = scnprintf(msg, sizeof(msg), "watchdog fiq cpu %d\n", - THREAD_INFO(svc_sp)->cpu); - ramoops_console_write_buf(msg, len); - - fiq_debugger_dump_stacktrace(&fiq_watchdog_output, regs, 100, svc_sp); - - raw_spin_unlock(&fiq_watchdog_lock); -} diff --git a/drivers/staging/android/fiq_debugger/fiq_watchdog.h b/drivers/staging/android/fiq_debugger/fiq_watchdog.h deleted file mode 100644 index c6b507f8d976..000000000000 --- a/drivers/staging/android/fiq_debugger/fiq_watchdog.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2014 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _FIQ_WATCHDOG_H_ -#define _FIQ_WATCHDOG_H_ - -void fiq_watchdog_triggered(const struct pt_regs *regs, void *svc_sp); - -#endif -- cgit v1.2.3 From eb275f4f0dc5902ee81bcdc79a6789e5795b30b3 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Thu, 29 Aug 2019 11:31:00 +0100 Subject: ANDROID: sched: Disallow WALT with CFS bandwidth control The WALT time accounting breaks when CFS tasks are throttled by the CPU bandwidth control mechanism of the CPU cgroups controller. This can result in a negative cumulative_runnable_avg, which can then lead to a kernel panic, and the device crashing. Although the right fix would be add support for throttled CFS tasks to WALT, the common kernel is now in stable maintenance mode and will not get new features which could cause issues for partners downstream. To work around the issue, make the CFS_BANDWIDTH Kconfig option depend on SCHED_WALT=n, hence preventing these two things from being enabled simultaneously. This should not be an issue for most partners (nobody had noticed the breakage for years), and those who do need the better fix can apply it in their device kernel. Bug: 139071966 Bug: 120440300 Change-Id: Ieb3c367ae7893ac93fb5b38c1580dc59151aacce Signed-off-by: Quentin Perret --- init/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/init/Kconfig b/init/Kconfig index b72e83288f66..369e7c6b1656 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1132,6 +1132,7 @@ config FAIR_GROUP_SCHED config CFS_BANDWIDTH bool "CPU bandwidth provisioning for FAIR_GROUP_SCHED" depends on FAIR_GROUP_SCHED + depends on !SCHED_WALT default n help This option allows users to define CPU bandwidth rates (limits) for -- cgit v1.2.3 From 93380a03f4476095baed16a8fb1689620d0a6476 Mon Sep 17 00:00:00 2001 From: Alistair Delva Date: Mon, 9 Sep 2019 10:16:12 -0700 Subject: Fix fallout from changes to bootparam_utils.h In the decompressor code, which is -fstandalone, changes to bootparam_utils.h mean that memcpy() is called, but there is no __memcpy() implementation at the time it is included. Ensure that this header is included *after* string.h. Fixes: arch/x86/boot/compressed/misc.o: In function `decompress_kernel': misc.c:(.text+0x330e): undefined reference to `__memcpy' Change-Id: I7fb6d45ad15f1657f630f2e236b12f7e218e0a37 Signed-off-by: Alistair Delva --- arch/x86/boot/compressed/misc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index 4abb284a5b9c..8fcbe6c4d7d9 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h @@ -19,6 +19,7 @@ #include #include #include +#include "../string.h" #include #define BOOT_BOOT_H -- cgit v1.2.3 From 9bc62df4166481501e3fb9406aec9f647ee39dc8 Mon Sep 17 00:00:00 2001 From: Amandeep Singh Date: Fri, 13 Sep 2019 12:52:05 +0530 Subject: msm: Update config name of function-1 driver Update config name to enable and disable SDIO function-1 driver support and its dependencies. Change-Id: I91de5e75c115f755ddc84bd80e5942162120f6cf Signed-off-by: Amandeep Singh --- drivers/char/Kconfig | 4 ++-- drivers/char/Makefile | 2 +- drivers/char/diag/Kconfig | 2 +- drivers/char/diag/Makefile | 2 +- drivers/char/diag/diagfwd_bridge.c | 2 +- drivers/char/diag/diagfwd_sdio.h | 4 ++-- drivers/soc/qcom/Kconfig | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index efdff5d16c5d..c603312bae17 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -633,8 +633,8 @@ config MSM_RDBG for a debugger running on a host PC to communicate with a remote stub running on peripheral subsystems such as the ADSP, MODEM etc. -config QCOM_SDIO_CLIENT - bool "QCOM_SDIO_CLIENT support" +config QTI_SDIO_CLIENT + bool "QTI_SDIO_CLIENT support" depends on SDIO_QCN default y help diff --git a/drivers/char/Makefile b/drivers/char/Makefile index dc00ba448d20..731f8fdd2ec6 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -67,4 +67,4 @@ ifdef CONFIG_COMPAT obj-$(CONFIG_MSM_ADSPRPC) += adsprpc_compat.o endif obj-$(CONFIG_MSM_RDBG) += rdbg.o -obj-$(CONFIG_QCOM_SDIO_CLIENT) += qti_sdio_client.o +obj-$(CONFIG_QTI_SDIO_CLIENT) += qti_sdio_client.o diff --git a/drivers/char/diag/Kconfig b/drivers/char/diag/Kconfig index 1bcacb8d83dd..f8a072025e9e 100644 --- a/drivers/char/diag/Kconfig +++ b/drivers/char/diag/Kconfig @@ -25,7 +25,7 @@ endmenu menu "HSIC/SMUX support for DIAG" config DIAGFWD_BRIDGE_CODE - depends on USB_QCOM_DIAG_BRIDGE || MSM_MHI || QCOM_SDIO_CLIENT + depends on USB_QCOM_DIAG_BRIDGE || MSM_MHI || QTI_SDIO_CLIENT default y bool "Enable QSC/9K DIAG traffic over SMUX/HSIC" help diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile index 40c5387998b3..b090f228535c 100644 --- a/drivers/char/diag/Makefile +++ b/drivers/char/diag/Makefile @@ -3,6 +3,6 @@ obj-$(CONFIG_DIAGFWD_BRIDGE_CODE) += diagfwd_bridge.o obj-$(CONFIG_USB_QCOM_DIAG_BRIDGE) += diagfwd_hsic.o obj-$(CONFIG_MSM_MHI) += diagfwd_mhi.o -obj-$(CONFIG_QCOM_SDIO_CLIENT) += diagfwd_sdio.o +obj-$(CONFIG_QTI_SDIO_CLIENT) += diagfwd_sdio.o diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagfwd_glink.o diagfwd_peripheral.o diagfwd_smd.o diagfwd_socket.o diag_mux.o diag_memorydevice.o diag_usb.o diagmem.o diagfwd_cntl.o diag_dci.o diag_masks.o diag_debugfs.o diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c index bfe85d9fd19d..298813917dec 100644 --- a/drivers/char/diag/diagfwd_bridge.c +++ b/drivers/char/diag/diagfwd_bridge.c @@ -43,7 +43,7 @@ static int diag_mhi_init(void) } #endif -#ifndef CONFIG_QCOM_SDIO_CLIENT +#ifndef CONFIG_QTI_SDIO_CLIENT static int diag_sdio_init(void) { return -EINVAL; diff --git a/drivers/char/diag/diagfwd_sdio.h b/drivers/char/diag/diagfwd_sdio.h index 1fa258e901c0..42c300d47c68 100644 --- a/drivers/char/diag/diagfwd_sdio.h +++ b/drivers/char/diag/diagfwd_sdio.h @@ -13,7 +13,7 @@ #ifndef DIAGFWD_SDIO_H #define DIAGFWD_SDIO_H -#ifdef CONFIG_QCOM_SDIO_CLIENT +#ifdef CONFIG_QTI_SDIO_CLIENT #ifdef CONFIG_DIAG_OVER_USB #include @@ -52,4 +52,4 @@ int diag_sdio_init(void); void diag_sdio_exit(void); #endif -#endif /*CONFIG_QCOM_SDIO_CLIENT*/ +#endif /*CONFIG_QTI_SDIO_CLIENT*/ diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 70fd4035a627..81db4fe93dbc 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -327,7 +327,7 @@ config MSM_IPC_ROUTER_GLINK_XPRT message exchange. config MSM_IPC_ROUTER_SDIO_XPRT - depends on QCOM_SDIO_CLIENT + depends on QTI_SDIO_CLIENT depends on IPC_ROUTER bool "MSM SDIO XPRT Layer" help -- cgit v1.2.3 From 72c5343cdbc5ec257e45d5387ed7220065c2ecff Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Fri, 13 Sep 2019 08:25:31 -0700 Subject: ANDROID: regression introduced override_creds=off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes a regression introduced by the series of commits: commit 272fcd1ca7ceb252b1c3a2961110c7c1722707cf ("ANDROID: overlayfs: override_creds=off option bypass creator_cred"), commit aab9adb4b81bcce107dd1783f6ac41dc1abe9f15 ("Merge 4.4.179 into android-4.4") that took in an incomplete, backport of commit 54a07fff4b217607e862b2e1e3fcec32919ad583 ("ovl: fix uid/gid when creating over whiteout") (or upstream commit d0e13f5bbe4be7c8f27736fc40503dcec04b7de0 ("ovl: fix uid/gid when creating over whiteout")) where a crash is observed in ovl_create_or_link() when a simple re-direction command in vendor directory. /vendor/bin/ > /vendor/bin/test_log.txt 2>&1& After further debugging we see that if the output is redirected to a file which doesn’t exist we see this stack: [ 377.382745] ovl_create_or_link+0xac/0x710 [ 377.382745] ovl_create_object+0xb8/0x110 [ 377.382745] ovl_create+0x34/0x40 [ 377.382745] path_openat+0xd44/0x15a8 [ 377.382745] do_filp_open+0x80/0x128 [ 377.382745] do_sys_open+0x140/0x250 [ 377.382745] __arm64_sys_openat+0x2c/0x38 ovl_override_creds returns NULL because the override_cred flag is set to false. This causes ovl_revert_creds also to fail. There is another call to check override_cred in override_cred call which overrides the creds permanently as there no revert_creds associated. So whenever next commit_cred is called we see the crash as the credentials are permanently overridden. Signed-off-by: Mark Salyzyn Tested-by: Rishabh/Jeevan Bug: 140816499 Bug: 109821005 Bug: 112955896 Bug: 127298877 Bug: 137541192 Change-Id: Icd0d9be82fc57af5ead1eeab99f79adf3adf62ef --- fs/overlayfs/dir.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index eedacae889b9..b4498b95234c 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -407,7 +407,7 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev, if (!ovl_dentry_is_opaque(dentry)) { err = ovl_create_upper(dentry, inode, &stat, link, hardlink); } else { - const struct cred *old_cred; + const struct cred *old_cred, *hold_cred = NULL; struct cred *override_cred; old_cred = ovl_override_creds(dentry->d_sb); @@ -415,15 +415,22 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev, err = -ENOMEM; override_cred = prepare_creds(); if (override_cred) { - override_cred->fsuid = old_cred->fsuid; - override_cred->fsgid = old_cred->fsgid; - put_cred(override_creds(override_cred)); + const struct cred *our_cred; + + our_cred = old_cred; + if (!our_cred) + our_cred = current_cred(); + override_cred->fsuid = our_cred->fsuid; + override_cred->fsgid = our_cred->fsgid; + hold_cred = override_creds(override_cred); put_cred(override_cred); err = ovl_create_over_whiteout(dentry, inode, &stat, link, hardlink); } - revert_creds(old_cred); + ovl_revert_creds(old_cred ?: hold_cred); + if (old_cred && hold_cred) + put_cred(hold_cred); } if (!err) -- cgit v1.2.3 From aa6ba1d906be3b47f5854ee3c4a7d3c8dd4f1e5e Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Mon, 16 Sep 2019 14:19:27 +0000 Subject: Revert "ANDROID: regression introduced override_creds=off" This reverts commit 72c5343cdbc5ec257e45d5387ed7220065c2ecff. Reason for revert: android-4.4 is for 'q' security updates, it is not dead. Signed-off-by: Mark Salyzyn Bug: 140816499 Change-Id: Ia99c0b420db306631e669428bb71eb8a2493ddc1 --- fs/overlayfs/dir.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index b4498b95234c..eedacae889b9 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -407,7 +407,7 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev, if (!ovl_dentry_is_opaque(dentry)) { err = ovl_create_upper(dentry, inode, &stat, link, hardlink); } else { - const struct cred *old_cred, *hold_cred = NULL; + const struct cred *old_cred; struct cred *override_cred; old_cred = ovl_override_creds(dentry->d_sb); @@ -415,22 +415,15 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev, err = -ENOMEM; override_cred = prepare_creds(); if (override_cred) { - const struct cred *our_cred; - - our_cred = old_cred; - if (!our_cred) - our_cred = current_cred(); - override_cred->fsuid = our_cred->fsuid; - override_cred->fsgid = our_cred->fsgid; - hold_cred = override_creds(override_cred); + override_cred->fsuid = old_cred->fsuid; + override_cred->fsgid = old_cred->fsgid; + put_cred(override_creds(override_cred)); put_cred(override_cred); err = ovl_create_over_whiteout(dentry, inode, &stat, link, hardlink); } - ovl_revert_creds(old_cred ?: hold_cred); - if (old_cred && hold_cred) - put_cred(hold_cred); + revert_creds(old_cred); } if (!err) -- cgit v1.2.3 From fab8f054af1ba6f5026e3807d4fefb009436698e Mon Sep 17 00:00:00 2001 From: c_mtharu Date: Tue, 17 Sep 2019 12:52:12 +0530 Subject: msm: adsprpc: Fix integer overflow in refcount of map Integer overflow in refcount of map is leading to use after free. Error out if refcount reaches INT_MAX. Change-Id: I21e88361a8e70ef8c5c9593f1fc0ddd2b351a55a Acked-by: Himateja Reddy Signed-off-by: Tharun Kumar Merugu --- drivers/char/adsprpc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 0e7befd4a146..fd351b921d7d 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -479,6 +479,10 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, uintptr_t va, if (va >= map->va && va + len <= map->va + map->len && map->fd == fd) { + if (map->refs + 1 == INT_MAX) { + spin_unlock(&me->hlock); + return -ETOOMANYREFS; + } map->refs++; match = map; break; @@ -491,6 +495,10 @@ static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, uintptr_t va, if (va >= map->va && va + len <= map->va + map->len && map->fd == fd) { + if (map->refs + 1 == INT_MAX) { + spin_unlock(&fl->hlock); + return -ETOOMANYREFS; + } map->refs++; match = map; break; -- cgit v1.2.3 From 1dffd1ffc410112bf2741d32693d45e27e944ae4 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Wed, 3 Jul 2019 17:33:51 +0100 Subject: ANDROID: Fixes to locking around handle_lmk_event get_task_struct used to reserve 'selected' outside rcu_read_lock block. Remove the need for get_task_mm, removing the possibility of lock issues there. Bug: 133479338 Signed-off-by: Jim Blackler Change-Id: I1399e2f669242c04e0e397bc09c987358aa97a0a --- drivers/staging/android/lowmemorykiller.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 1dac38735030..72e8bc6ed1c5 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -95,21 +95,15 @@ struct lmk_event { struct list_head list; }; -void handle_lmk_event(struct task_struct *selected, short min_score_adj) +void handle_lmk_event(struct task_struct *selected, int selected_tasksize, + short min_score_adj) { int head; int tail; struct lmk_event *events; struct lmk_event *event; int res; - long rss_in_pages = -1; char taskname[MAX_TASKNAME]; - struct mm_struct *mm = get_task_mm(selected); - - if (mm) { - rss_in_pages = get_mm_rss(mm); - mmput(mm); - } res = get_cmdline(selected, taskname, MAX_TASKNAME - 1); @@ -148,7 +142,7 @@ void handle_lmk_event(struct task_struct *selected, short min_score_adj) event->maj_flt = selected->maj_flt; event->oom_score_adj = selected->signal->oom_score_adj; event->start_time = nsec_to_clock_t(selected->real_start_time); - event->rss_in_pages = rss_in_pages; + event->rss_in_pages = selected_tasksize; event->min_score_adj = min_score_adj; event_buffer.head = (head + 1) & (MAX_BUFFERED_EVENTS - 1); @@ -347,15 +341,17 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) free); lowmem_deathpending_timeout = jiffies + HZ; rem += selected_tasksize; + get_task_struct(selected); } lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n", sc->nr_to_scan, sc->gfp_mask, rem); rcu_read_unlock(); - if (selected) - handle_lmk_event(selected, min_score_adj); - + if (selected) { + handle_lmk_event(selected, selected_tasksize, min_score_adj); + put_task_struct(selected); + } return rem; } -- cgit v1.2.3 From 590cc988000e45455134c5f66a32c43e26d8041a Mon Sep 17 00:00:00 2001 From: Shadul Shaikh Date: Mon, 30 Sep 2019 15:58:05 +0530 Subject: msm: camera_v2: Avoid halting AXI bridge Avoid halting AXI bridge during CPP node close. Change-Id: I27b2f4a054aa9b910a55f7f6f60ea84f80e3db4d Signed-off-by: Shadul Shaikh --- .../platform/msm/camera_v2/pproc/cpp/msm_cpp.c | 50 ---------------------- 1 file changed, 50 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index 83abaea1fa44..d75af08846cd 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -1498,8 +1498,6 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { uint32_t i; int rc = -1; - int counter = 0; - u32 result = 0; struct cpp_device *cpp_dev = NULL; struct msm_device_queue *processing_q = NULL; struct msm_device_queue *eventData_q = NULL; @@ -1581,54 +1579,6 @@ static int cpp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) pr_debug("DEBUG_R1: 0x%x\n", msm_camera_io_r(cpp_dev->cpp_hw_base + 0x8C)); - /* mask IRQ status */ - msm_camera_io_w(0xB, cpp_dev->cpp_hw_base + 0xC); - - /* clear IRQ status */ - msm_camera_io_w(0xFFFFF, cpp_dev->cpp_hw_base + 0x14); - - /* MMSS_A_CPP_AXI_CMD = 0x16C, reset 0x1*/ - msm_camera_io_w(0x1, cpp_dev->cpp_hw_base + 0x16C); - - while (counter < MSM_CPP_POLL_RETRIES) { - result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10); - if (result & 0x2) - break; - /* - * Below usleep values are chosen based on experiments - * and this was the smallest number which works. This - * sleep is needed to leave enough time for hardware - * to update status register. - */ - usleep_range(200, 250); - counter++; - } - - pr_debug("CPP AXI done counter %d result 0x%x\n", - counter, result); - - /* clear IRQ status */ - msm_camera_io_w(0xFFFFF, cpp_dev->cpp_hw_base + 0x14); - counter = 0; - /* MMSS_A_CPP_RST_CMD_0 = 0x8, firmware reset = 0x3DF77 */ - msm_camera_io_w(0x3DF77, cpp_dev->cpp_hw_base + 0x8); - - while (counter < MSM_CPP_POLL_RETRIES) { - result = msm_camera_io_r(cpp_dev->cpp_hw_base + 0x10); - if (result & 0x1) - break; - /* - * Below usleep values are chosen based on experiments - * and this was the smallest number which works. This - * sleep is needed to leave enough time for hardware - * to update status register. - */ - usleep_range(200, 250); - counter++; - } - pr_debug("CPP reset done counter %d result 0x%x\n", - counter, result); - msm_camera_io_w(0x0, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL); msm_cpp_clear_timer(cpp_dev); cpp_release_hardware(cpp_dev); -- cgit v1.2.3 From 7670609da83b615c446ac999384f1f6a7a9f0839 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Mon, 16 Sep 2019 18:54:08 +0100 Subject: Remove taskname from lowmemorykiller kill reports Required because the lowmem_shrinker cannot use get_cmdline when called from the direct reclaim path. Direct reclaim in do_page_fault() takes mm->mmap_sem before calling shrinkers and get_cmdline also takes mm->mmap_sem by calling access_process_vm. Userspace should be able to recover taskname using the reported PID. Bug: 130017100 Signed-off-by: Jim Blackler Test: Manually Change-Id: I5f8b15bda60f9e2c0f6373ef54ad6fb95cda7a44 --- drivers/staging/android/lowmemorykiller.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 72e8bc6ed1c5..ddc602c7c48f 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -102,19 +102,6 @@ void handle_lmk_event(struct task_struct *selected, int selected_tasksize, int tail; struct lmk_event *events; struct lmk_event *event; - int res; - char taskname[MAX_TASKNAME]; - - res = get_cmdline(selected, taskname, MAX_TASKNAME - 1); - - /* No valid process name means this is definitely not associated with a - * userspace activity. - */ - - if (res <= 0 || res >= MAX_TASKNAME) - return; - - taskname[res] = '\0'; spin_lock(&lmk_event_lock); @@ -130,7 +117,7 @@ void handle_lmk_event(struct task_struct *selected, int selected_tasksize, events = (struct lmk_event *) event_buffer.buf; event = &events[head]; - memcpy(event->taskname, taskname, res + 1); + strncpy(event->taskname, selected->comm, MAX_TASKNAME); event->pid = selected->pid; event->uid = from_kuid_munged(current_user_ns(), task_uid(selected)); -- cgit v1.2.3 From fe064e0aca115afeadf8a5c4320067ab443c6800 Mon Sep 17 00:00:00 2001 From: Naitik Bharadiya Date: Fri, 20 Sep 2019 18:13:49 +0530 Subject: defconfig : Enable Configs for MSM8996 CONFIG_ENABLE_FP_SIMD_SETTINGS : Enable FP(Floating Point) and SIMD settings required during execution of AArch32 processes. CONFIG_MSM_APP_SETTINGS : Enable support for app specific setting on MSM8996. This is required for providing an interface so that app specific settings can be applied / cleared. Change-Id: Ife81b927dc58ef5e5fb7a6668286c176f16ad7bf Signed-off-by: Naitik Bharadiya --- arch/arm64/configs/msm-perf_defconfig | 2 ++ arch/arm64/configs/msm_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig index fbaff4d0b6c6..95fb47583db4 100644 --- a/arch/arm64/configs/msm-perf_defconfig +++ b/arch/arm64/configs/msm-perf_defconfig @@ -49,6 +49,8 @@ CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSM8996=y CONFIG_PCI=y CONFIG_PCI_MSM=y +CONFIG_ENABLE_FP_SIMD_SETTINGS=y +CONFIG_MSM_APP_SETTINGS=y CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_PREEMPT=y diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig index ccff9670af63..3661419528c2 100644 --- a/arch/arm64/configs/msm_defconfig +++ b/arch/arm64/configs/msm_defconfig @@ -46,6 +46,8 @@ CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSM8996=y CONFIG_PCI=y CONFIG_PCI_MSM=y +CONFIG_ENABLE_FP_SIMD_SETTINGS=y +CONFIG_MSM_APP_SETTINGS=y CONFIG_SCHED_MC=y CONFIG_NR_CPUS=8 CONFIG_PREEMPT=y -- cgit v1.2.3 From 24f4e5b8d6f228c98589f9a1beba507bd3908b33 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Mon, 30 Sep 2019 15:27:24 +0100 Subject: ANDROID: usb: gadget: Fix dependency for f_accessory The Android Accessory USB gadget functions use core HID functions. As such, compiling with CONFIG_HID=m and CONFIG_USB_GADGET=y fails to link: drivers/usb/gadget/function/f_accessory.o: In function `acc_complete_send_hid_event': f_accessory.c:(.text+0xd54): undefined reference to `hid_report_raw_event' drivers/usb/gadget/function/f_accessory.o: In function `acc_hid_work': f_accessory.c:(.text+0x2a98): undefined reference to `hid_destroy_device' f_accessory.c:(.text+0x2ad4): undefined reference to `hid_allocate_device' f_accessory.c:(.text+0x2b64): undefined reference to `hid_add_device' f_accessory.c:(.text+0x2d04): undefined reference to `hid_destroy_device' drivers/usb/gadget/function/f_accessory.o: In function `acc_hid_parse': f_accessory.c:(.text+0x2e24): undefined reference to `hid_parse_report' drivers/usb/gadget/function/f_accessory.o: In function `acc_function_bind_configfs': f_accessory.c:(.text+0x2f8c): undefined reference to `__hid_register_driver' drivers/usb/gadget/function/f_accessory.o: In function `acc_function_unbind': f_accessory.c:(.text+0x3bc8): undefined reference to `hid_unregister_driver' drivers/usb/gadget/function/f_accessory.o: In function `acc_hid_probe': f_accessory.c:(.text+0x3ef4): undefined reference to `hid_open_report' f_accessory.c:(.text+0x3f18): undefined reference to `hid_hw_start' Fix this by making the dependency on HID explicit. Bug: 140224784 Fixes: 8cc9024964a7 ("usb: gadget: Accessory:Migrate to USB_FUNCTION API") Signed-off-by: Quentin Perret Change-Id: Ibd8640d7766cc7802d8275bfe3adfa007f3318fe --- drivers/usb/gadget/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 5cf6802b02ae..6e9521407f57 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -400,6 +400,7 @@ config USB_CONFIGFS_F_PTP config USB_CONFIGFS_F_ACC boolean "Accessory gadget" depends on USB_CONFIGFS + depends on HID=y select USB_F_ACC help USB gadget Accessory support -- cgit v1.2.3 From 7eea87cef27f068f061934f18998aa9f6a92f5c1 Mon Sep 17 00:00:00 2001 From: Rama Krishna Phani A Date: Thu, 3 Oct 2019 11:50:06 +0530 Subject: msm: pcie: Use local variable for manipulation There is a chance that wr_offset can be modified to an arbitrary value as it is a global variable. Have a local copy of this value and use it for further manipulation. Change-Id: If3b76a0dd95e81bd057d89626818c72405f91d65 Signed-off-by: Rama Krishna Phani A --- drivers/pci/host/pci-msm.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 98aac17a91b5..9be5d601d38a 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -2067,6 +2067,7 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, u32 ep_l1sub_cap_reg1_offset = 0; u32 ep_link_ctrlstts_offset = 0; u32 ep_dev_ctrl2stts2_offset = 0; + u32 wr_ofst = 0; if (testcase >= 5 && testcase <= 10) { current_offset = @@ -2428,22 +2429,24 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, break; } + wr_ofst = wr_offset; + PCIE_DBG_FS(dev, "base: %s: 0x%p\nwr_offset: 0x%x\nwr_mask: 0x%x\nwr_value: 0x%x\n", dev->res[base_sel - 1].name, dev->res[base_sel - 1].base, - wr_offset, wr_mask, wr_value); + wr_ofst, wr_mask, wr_value); base_sel_size = resource_size(dev->res[base_sel - 1].resource); - if (wr_offset > base_sel_size - 4 || - msm_pcie_check_align(dev, wr_offset)) + if (wr_ofst > base_sel_size - 4 || + msm_pcie_check_align(dev, wr_ofst)) PCIE_DBG_FS(dev, "PCIe: RC%d: Invalid wr_offset: 0x%x. wr_offset should be no more than 0x%x\n", - dev->rc_idx, wr_offset, base_sel_size - 4); + dev->rc_idx, wr_ofst, base_sel_size - 4); else msm_pcie_write_reg_field(dev->res[base_sel - 1].base, - wr_offset, wr_mask, wr_value); + wr_ofst, wr_mask, wr_value); break; case 13: /* dump all registers of base_sel */ -- cgit v1.2.3 From 4f1af2bcab137526c66ea92d3026e3f2879281e2 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 4 Sep 2019 20:13:08 +0200 Subject: Revert "Bluetooth: validate BLE connection interval updates" [ Upstream commit 68d19d7d995759b96169da5aac313363f92a9075 ] This reverts commit c49a8682fc5d298d44e8d911f4fa14690ea9485e. There are devices which require low connection intervals for usable operation including keyboards and mice. Forcing a static connection interval for these types of devices has an impact in latency and causes a regression. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg Signed-off-by: Sasha Levin --- net/bluetooth/hci_event.c | 5 ----- net/bluetooth/l2cap_core.c | 9 +-------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index c4e94f34d048..37fe2b158c2a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -5062,11 +5062,6 @@ static void hci_le_remote_conn_param_req_evt(struct hci_dev *hdev, return send_conn_param_neg_reply(hdev, handle, HCI_ERROR_UNKNOWN_CONN_ID); - if (min < hcon->le_conn_min_interval || - max > hcon->le_conn_max_interval) - return send_conn_param_neg_reply(hdev, handle, - HCI_ERROR_INVALID_LL_PARAMS); - if (hci_check_conn_params(min, max, latency, timeout)) return send_conn_param_neg_reply(hdev, handle, HCI_ERROR_INVALID_LL_PARAMS); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8cfba78d26f6..c25f1e4846cd 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -5266,14 +5266,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, memset(&rsp, 0, sizeof(rsp)); - if (min < hcon->le_conn_min_interval || - max > hcon->le_conn_max_interval) { - BT_DBG("requested connection interval exceeds current bounds."); - err = -EINVAL; - } else { - err = hci_check_conn_params(min, max, latency, to_multiplier); - } - + err = hci_check_conn_params(min, max, latency, to_multiplier); if (err) rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED); else -- cgit v1.2.3 From c03d9a82384cbf6199b597c101f17437e754d8f5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 4 Sep 2019 11:54:20 -0400 Subject: HID: prodikeys: Fix general protection fault during probe commit 98375b86c79137416e9fd354177b85e768c16e56 upstream. The syzbot fuzzer provoked a general protection fault in the hid-prodikeys driver: kasan: CONFIG_KASAN_INLINE enabled kasan: GPF could be caused by NULL-ptr deref or user memory access general protection fault: 0000 [#1] SMP KASAN CPU: 0 PID: 12 Comm: kworker/0:1 Not tainted 5.3.0-rc5+ #28 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Workqueue: usb_hub_wq hub_event RIP: 0010:pcmidi_submit_output_report drivers/hid/hid-prodikeys.c:300 [inline] RIP: 0010:pcmidi_set_operational drivers/hid/hid-prodikeys.c:558 [inline] RIP: 0010:pcmidi_snd_initialise drivers/hid/hid-prodikeys.c:686 [inline] RIP: 0010:pk_probe+0xb51/0xfd0 drivers/hid/hid-prodikeys.c:836 Code: 0f 85 50 04 00 00 48 8b 04 24 4c 89 7d 10 48 8b 58 08 e8 b2 53 e4 fc 48 8b 54 24 20 48 b8 00 00 00 00 00 fc ff df 48 c1 ea 03 <80> 3c 02 00 0f 85 13 04 00 00 48 ba 00 00 00 00 00 fc ff df 49 8b The problem is caused by the fact that pcmidi_get_output_report() will return an error if the HID device doesn't provide the right sort of output report, but pcmidi_set_operational() doesn't bother to check the return code and assumes the function call always succeeds. This patch adds the missing check and aborts the probe operation if necessary. Reported-and-tested-by: syzbot+1088533649dafa1c9004@syzkaller.appspotmail.com Signed-off-by: Alan Stern CC: Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-prodikeys.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c index 3a207c0ac0e3..cba15edd47c2 100644 --- a/drivers/hid/hid-prodikeys.c +++ b/drivers/hid/hid-prodikeys.c @@ -556,10 +556,14 @@ static void pcmidi_setup_extra_keys( static int pcmidi_set_operational(struct pcmidi_snd *pm) { + int rc; + if (pm->ifnum != 1) return 0; /* only set up ONCE for interace 1 */ - pcmidi_get_output_report(pm); + rc = pcmidi_get_output_report(pm); + if (rc < 0) + return rc; pcmidi_submit_output_report(pm, 0xc1); return 0; } @@ -688,7 +692,11 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm) spin_lock_init(&pm->rawmidi_in_lock); init_sustain_timers(pm); - pcmidi_set_operational(pm); + err = pcmidi_set_operational(pm); + if (err < 0) { + pk_error("failed to find output report\n"); + goto fail_register; + } /* register it */ err = snd_card_register(card); -- cgit v1.2.3 From 30d86e698c284b42887c5731af390e4957b62fa1 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 21 Nov 2016 11:48:40 +0100 Subject: HID: lg: make transfer buffers DMA capable commit 061232f0d47fa10103f3efa3e890f002a930d902 upstream. Kernel v4.9 strictly enforces DMA capable buffers, so we need to remove buffers allocated on the stack. [jkosina@suse.cz: fix up second usage of hid_hw_raw_request(), spotted by 0day build bot] Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-lg.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index c690fae02cf8..29403e900f28 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -701,11 +701,16 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) /* Setup wireless link with Logitech Wii wheel */ if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) { - unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const unsigned char cbuf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + u8 *buf = kmemdup(cbuf, sizeof(cbuf), GFP_KERNEL); - ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf), - HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + if (!buf) { + ret = -ENOMEM; + goto err_free; + } + ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf), + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); if (ret >= 0) { /* insert a little delay of 10 jiffies ~ 40ms */ wait_queue_head_t wait; @@ -717,9 +722,10 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) buf[1] = 0xB2; get_random_bytes(&buf[2], 2); - ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf), + ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf), HID_FEATURE_REPORT, HID_REQ_SET_REPORT); } + kfree(buf); } if (drv_data->quirks & LG_FF) -- cgit v1.2.3 From ffc62dc252e1aaf1f93b6449c45bef581da5f066 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 20 Aug 2019 16:00:21 -0400 Subject: HID: logitech: Fix general protection fault caused by Logitech driver commit 5f9242775bb61f390f0885f23fc16397262c7538 upstream. The syzbot fuzzer found a general protection fault in the HID subsystem: kasan: CONFIG_KASAN_INLINE enabled kasan: GPF could be caused by NULL-ptr deref or user memory access general protection fault: 0000 [#1] SMP KASAN CPU: 0 PID: 3715 Comm: syz-executor.3 Not tainted 5.2.0-rc6+ #15 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:__pm_runtime_resume+0x49/0x180 drivers/base/power/runtime.c:1069 Code: ed 74 d5 fe 45 85 ed 0f 85 9a 00 00 00 e8 6f 73 d5 fe 48 8d bd c1 02 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 fa 48 c1 ea 03 <0f> b6 04 02 48 89 fa 83 e2 07 38 d0 7f 08 84 c0 0f 85 fe 00 00 00 RSP: 0018:ffff8881d99d78e0 EFLAGS: 00010202 RAX: dffffc0000000000 RBX: 0000000000000020 RCX: ffffc90003f3f000 RDX: 0000000416d8686d RSI: ffffffff82676841 RDI: 00000020b6c3436a RBP: 00000020b6c340a9 R08: ffff8881c6d64800 R09: fffffbfff0e84c25 R10: ffff8881d99d7940 R11: ffffffff87426127 R12: 0000000000000004 R13: 0000000000000000 R14: ffff8881d9b94000 R15: ffffffff897f9048 FS: 00007f047f542700(0000) GS:ffff8881db200000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000001b30f21000 CR3: 00000001ca032000 CR4: 00000000001406f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: pm_runtime_get_sync include/linux/pm_runtime.h:226 [inline] usb_autopm_get_interface+0x1b/0x50 drivers/usb/core/driver.c:1707 usbhid_power+0x7c/0xe0 drivers/hid/usbhid/hid-core.c:1234 hid_hw_power include/linux/hid.h:1038 [inline] hidraw_open+0x20d/0x740 drivers/hid/hidraw.c:282 chrdev_open+0x219/0x5c0 fs/char_dev.c:413 do_dentry_open+0x497/0x1040 fs/open.c:778 do_last fs/namei.c:3416 [inline] path_openat+0x1430/0x3ff0 fs/namei.c:3533 do_filp_open+0x1a1/0x280 fs/namei.c:3563 do_sys_open+0x3c0/0x580 fs/open.c:1070 do_syscall_64+0xb7/0x560 arch/x86/entry/common.c:301 entry_SYSCALL_64_after_hwframe+0x49/0xbe It turns out the fault was caused by a bug in the HID Logitech driver, which violates the requirement that every pathway calling hid_hw_start() must also call hid_hw_stop(). This patch fixes the bug by making sure the requirement is met. Reported-and-tested-by: syzbot+3cbe5cd105d2ad56a1df@syzkaller.appspotmail.com Signed-off-by: Alan Stern CC: Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-lg.c | 10 ++++++---- drivers/hid/hid-lg4ff.c | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 29403e900f28..0fd9fc135f3d 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -706,7 +706,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) if (!buf) { ret = -ENOMEM; - goto err_free; + goto err_stop; } ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf), @@ -738,9 +738,12 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = lg4ff_init(hdev); if (ret) - goto err_free; + goto err_stop; return 0; + +err_stop: + hid_hw_stop(hdev); err_free: kfree(drv_data); return ret; @@ -751,8 +754,7 @@ static void lg_remove(struct hid_device *hdev) struct lg_drv_data *drv_data = hid_get_drvdata(hdev); if (drv_data->quirks & LG_FF4) lg4ff_deinit(hdev); - else - hid_hw_stop(hdev); + hid_hw_stop(hdev); kfree(drv_data); } diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index fbddcb37ae98..dae1b9cdd2e5 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -1378,7 +1378,6 @@ int lg4ff_deinit(struct hid_device *hid) } } #endif - hid_hw_stop(hid); drv_data->device_props = NULL; kfree(entry); -- cgit v1.2.3 From 0bbb24a30e1abbb13752af0be8fd9b8c6049df52 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 21 Aug 2019 13:27:12 -0400 Subject: HID: hidraw: Fix invalid read in hidraw_ioctl commit 416dacb819f59180e4d86a5550052033ebb6d72c upstream. The syzbot fuzzer has reported a pair of problems in the hidraw_ioctl() function: slab-out-of-bounds read and use-after-free read. An example of the first: BUG: KASAN: slab-out-of-bounds in strlen+0x79/0x90 lib/string.c:525 Read of size 1 at addr ffff8881c8035f38 by task syz-executor.4/2833 CPU: 1 PID: 2833 Comm: syz-executor.4 Not tainted 5.3.0-rc2+ #1 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0xca/0x13e lib/dump_stack.c:113 print_address_description+0x6a/0x32c mm/kasan/report.c:351 __kasan_report.cold+0x1a/0x33 mm/kasan/report.c:482 kasan_report+0xe/0x12 mm/kasan/common.c:612 strlen+0x79/0x90 lib/string.c:525 strlen include/linux/string.h:281 [inline] hidraw_ioctl+0x245/0xae0 drivers/hid/hidraw.c:446 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:509 [inline] do_vfs_ioctl+0xd2d/0x1330 fs/ioctl.c:696 ksys_ioctl+0x9b/0xc0 fs/ioctl.c:713 __do_sys_ioctl fs/ioctl.c:720 [inline] __se_sys_ioctl fs/ioctl.c:718 [inline] __x64_sys_ioctl+0x6f/0xb0 fs/ioctl.c:718 do_syscall_64+0xb7/0x580 arch/x86/entry/common.c:296 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x459829 Code: fd b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 cb b7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007f7a68f6dc78 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 0000000000459829 RDX: 0000000000000000 RSI: 0000000080404805 RDI: 0000000000000004 RBP: 000000000075bf20 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00007f7a68f6e6d4 R13: 00000000004c21de R14: 00000000004d5620 R15: 00000000ffffffff The two problems have the same cause: hidraw_ioctl() fails to test whether the device has been removed. This patch adds the missing test. Reported-and-tested-by: syzbot+5a6c4ec678a0c6ee84ba@syzkaller.appspotmail.com Signed-off-by: Alan Stern CC: Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hidraw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index c0c4df198725..627a24d3ea7c 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -383,7 +383,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, mutex_lock(&minors_lock); dev = hidraw_table[minor]; - if (!dev) { + if (!dev || !dev->exist) { ret = -ENODEV; goto out; } -- cgit v1.2.3 From 9ce51a5b414a42887505a6504a2f0273b89906a5 Mon Sep 17 00:00:00 2001 From: Tokunori Ikegami Date: Tue, 6 Aug 2019 04:03:18 +0900 Subject: mtd: cfi_cmdset_0002: Use chip_good() to retry in do_write_oneword() commit 37c673ade35c707d50583b5b25091ff8ebdeafd7 upstream. As reported by the OpenWRT team, write requests sometimes fail on some platforms. Currently to check the state chip_ready() is used correctly as described by the flash memory S29GL256P11TFI01 datasheet. Also chip_good() is used to check if the write is succeeded and it was implemented by the commit fb4a90bfcd6d8 ("[MTD] CFI-0002 - Improve error checking"). But actually the write failure is caused on some platforms and also it can be fixed by using chip_good() to check the state and retry instead. Also it seems that it is caused after repeated about 1,000 times to retry the write one word with the reset command. By using chip_good() to check the state to be done it can be reduced the retry with reset. It is depended on the actual flash chip behavior so the root cause is unknown. Cc: Chris Packham Cc: Joakim Tjernlund Cc: linux-mtd@lists.infradead.org Cc: stable@vger.kernel.org Reported-by: Fabio Bettoni Signed-off-by: Felix Fietkau Signed-off-by: Hauke Mehrtens Signed-off-by: Tokunori Ikegami [vigneshr@ti.com: Fix a checkpatch warning] Signed-off-by: Vignesh Raghavendra Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/cfi_cmdset_0002.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index fb5a3052f144..7589d891b311 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -1626,29 +1626,35 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, continue; } - if (time_after(jiffies, timeo) && !chip_ready(map, adr)){ + /* + * We check "time_after" and "!chip_good" before checking + * "chip_good" to avoid the failure due to scheduling. + */ + if (time_after(jiffies, timeo) && !chip_good(map, adr, datum)) { xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); xip_disable(map, chip, adr); + ret = -EIO; break; } - if (chip_ready(map, adr)) + if (chip_good(map, adr, datum)) break; /* Latency issues. Drop the lock, wait a while and retry */ UDELAY(map, chip, adr, 1); } + /* Did we succeed? */ - if (!chip_good(map, adr, datum)) { + if (ret) { /* reset on all failures. */ map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_RETRIES) + if (++retry_cnt <= MAX_RETRIES) { + ret = 0; goto retry; - - ret = -EIO; + } } xip_enable(map, chip, adr); op_done: -- cgit v1.2.3 From b19b5a895ad3162663e597680b94a1d9f706c9cb Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 9 Sep 2019 00:29:52 -0500 Subject: crypto: talitos - fix missing break in switch statement commit 5fc194ea6d34dfad9833d3043ce41d6c52aff39a upstream. Add missing break statement in order to prevent the code from falling through to case CRYPTO_ALG_TYPE_AHASH. Fixes: aeb4c132f33d ("crypto: talitos - Convert to new AEAD interface") Cc: stable@vger.kernel.org Reported-by: kbuild test robot Signed-off-by: Gustavo A. R. Silva Reviewed-by: Christophe Leroy Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/talitos.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 014745271bb4..1c8857e7db89 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -2730,6 +2730,7 @@ static int talitos_remove(struct platform_device *ofdev) break; case CRYPTO_ALG_TYPE_AEAD: crypto_unregister_aead(&t_alg->algt.alg.aead); + break; case CRYPTO_ALG_TYPE_AHASH: crypto_unregister_ahash(&t_alg->algt.alg.hash); break; -- cgit v1.2.3 From 91573ae4aed0a49660abdad4d42f2a0db995ee5e Mon Sep 17 00:00:00 2001 From: Mao Wenan Date: Wed, 18 Sep 2019 16:37:33 +0800 Subject: net: rds: Fix NULL ptr use in rds_tcp_kill_sock After the commit c4e97b06cfdc ("net: rds: force to destroy connection if t_sock is NULL in rds_tcp_kill_sock()."), it introduced null-ptr-deref in rds_tcp_kill_sock as below: BUG: KASAN: null-ptr-deref on address 0000000000000020 Read of size 8 by task kworker/u16:10/910 CPU: 3 PID: 910 Comm: kworker/u16:10 Not tainted 4.4.178+ #3 Hardware name: linux,dummy-virt (DT) Workqueue: netns cleanup_net Call trace: [] dump_backtrace+0x0/0x618 [] show_stack+0x38/0x60 [] dump_stack+0x1a8/0x230 [] kasan_report_error+0xc8c/0xfc0 [] kasan_report+0x94/0xd8 [] __asan_load8+0x88/0x150 [] rds_tcp_dev_event+0x734/0xb48 [] raw_notifier_call_chain+0x150/0x1e8 [] call_netdevice_notifiers_info+0x90/0x110 [] netdev_run_todo+0x2f4/0xb08 [] rtnl_unlock+0x2c/0x48 [] default_device_exit_batch+0x444/0x528 [] ops_exit_list+0x1c0/0x240 [] cleanup_net+0x738/0xbf8 [] process_one_work+0x96c/0x13e0 [] worker_thread+0x7e0/0x1910 [] kthread+0x304/0x390 [] ret_from_fork+0x10/0x50 If the first loop add the tc->t_sock = NULL to the tmp_list, 1). list_for_each_entry_safe(tc, _tc, &rds_tcp_conn_list, t_tcp_node) then the second loop is to find connections to destroy, tc->t_sock might equal NULL, and tc->t_sock->sk happens null-ptr-deref. 2). list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node) Fixes: c4e97b06cfdc ("net: rds: force to destroy connection if t_sock is NULL in rds_tcp_kill_sock().") Signed-off-by: Mao Wenan Signed-off-by: Greg Kroah-Hartman --- net/rds/tcp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/rds/tcp.c b/net/rds/tcp.c index 554d4b461983..c10622a9321c 100644 --- a/net/rds/tcp.c +++ b/net/rds/tcp.c @@ -352,9 +352,11 @@ static void rds_tcp_kill_sock(struct net *net) } spin_unlock_irq(&rds_tcp_conn_lock); list_for_each_entry_safe(tc, _tc, &tmp_list, t_tcp_node) { - sk = tc->t_sock->sk; - sk->sk_prot->disconnect(sk, 0); - tcp_done(sk); + if (tc->t_sock) { + sk = tc->t_sock->sk; + sk->sk_prot->disconnect(sk, 0); + tcp_done(sk); + } if (tc->conn->c_passive) rds_conn_destroy(tc->conn->c_passive); rds_conn_destroy(tc->conn); -- cgit v1.2.3 From e68c9b0f48b61592e2311c828cff37388778c90a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 19 Feb 2019 16:46:47 +0100 Subject: ASoC: fsl: Fix of-node refcount unbalance in fsl_ssi_probe_from_dt() commit 2757970f6d0d0a112247600b23d38c0c728ceeb3 upstream. The node obtained from of_find_node_by_path() has to be unreferenced after the use, but we forgot it for the root node. Fixes: f0fba2ad1b6b ("ASoC: multi-component - ASoC Multi-Component Support") Cc: Timur Tabi Cc: Nicolin Chen Cc: Xiubo Li Cc: Fabio Estevam Signed-off-by: Takashi Iwai Acked-by: Nicolin Chen Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/fsl/fsl_ssi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 7ca67613e0d4..d46e9ad600b4 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1374,6 +1374,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) struct fsl_ssi_private *ssi_private; int ret = 0; struct device_node *np = pdev->dev.of_node; + struct device_node *root; const struct of_device_id *of_id; const char *p, *sprop; const uint32_t *iprop; @@ -1510,7 +1511,9 @@ static int fsl_ssi_probe(struct platform_device *pdev) * device tree. We also pass the address of the CPU DAI driver * structure. */ - sprop = of_get_property(of_find_node_by_path("/"), "compatible", NULL); + root = of_find_node_by_path("/"); + sprop = of_get_property(root, "compatible", NULL); + of_node_put(root); /* Sometimes the compatible name has a "fsl," prefix, so we strip it. */ p = strrchr(sprop, ','); if (p) -- cgit v1.2.3 From 7703936b97b69b704922b4538a3aaf4a469aed8b Mon Sep 17 00:00:00 2001 From: "Shih-Yuan Lee (FourDollars)" Date: Fri, 20 Sep 2019 21:40:53 +0800 Subject: ALSA: hda - Add laptop imic fixup for ASUS M9V laptop commit 7b485d175631be676424aedb8cd2f66d0c93da78 upstream. The same fixup to enable laptop imic is needed for ASUS M9V with AD1986A codec like another HP machine. Signed-off-by: Shih-Yuan Lee (FourDollars) Cc: Link: https://lore.kernel.org/r/20190920134052.GA8035@localhost Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_analog.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index e0fb8c6d1bc2..7d65c6df9aa8 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -370,6 +370,7 @@ static const struct hda_fixup ad1986a_fixups[] = { static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC), + SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9V", AD1986A_FIXUP_LAPTOP_IMIC), SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD), SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD), SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK), -- cgit v1.2.3 From 943341211598d18a3bc1d1febf44edc1e0c21eb4 Mon Sep 17 00:00:00 2001 From: Arkadiusz Miskiewicz Date: Wed, 15 Feb 2017 14:21:27 +0100 Subject: mac80211: Print text for disassociation reason MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 68506e9af132a6b5735c1dd4b11240da0cf5eeae ] When disassociation happens only numeric reason is printed in ieee80211_rx_mgmt_disassoc(). Add text variant, too. Signed-off-by: Arkadiusz Miśkiewicz Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/mac80211/mlme.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ae5387b93df3..3daf3ae4003b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2857,8 +2857,9 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - sdata_info(sdata, "disassociated from %pM (Reason: %u)\n", - mgmt->sa, reason_code); + sdata_info(sdata, "disassociated from %pM (Reason: %u=%s)\n", + mgmt->sa, reason_code, + ieee80211_get_reason_code_string(reason_code)); ieee80211_set_disassoc(sdata, 0, 0, false, NULL); -- cgit v1.2.3 From 3fea925a915ac7469c890a16d4fa45fc9ed531e5 Mon Sep 17 00:00:00 2001 From: Yu Wang Date: Fri, 10 May 2019 17:04:52 +0800 Subject: mac80211: handle deauthentication/disassociation from TDLS peer [ Upstream commit 79c92ca42b5a3e0ea172ea2ce8df8e125af237da ] When receiving a deauthentication/disassociation frame from a TDLS peer, a station should not disconnect the current AP, but only disable the current TDLS link if it's enabled. Without this change, a TDLS issue can be reproduced by following the steps as below: 1. STA-1 and STA-2 are connected to AP, bidirection traffic is running between STA-1 and STA-2. 2. Set up TDLS link between STA-1 and STA-2, stay for a while, then teardown TDLS link. 3. Repeat step #2 and monitor the connection between STA and AP. During the test, one STA may send a deauthentication/disassociation frame to another, after TDLS teardown, with reason code 6/7, which means: Class 2/3 frame received from nonassociated STA. On receive this frame, the receiver STA will disconnect the current AP and then reconnect. It's not a expected behavior, purpose of this frame should be disabling the TDLS link, not the link with AP. Cc: stable@vger.kernel.org Signed-off-by: Yu Wang Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/mlme.c | 12 +++++++++++- net/mac80211/tdls.c | 23 +++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7b271f3ded6b..72f76da88912 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2059,6 +2059,9 @@ void ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy, const u8 *addr); void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata); void ieee80211_tdls_chsw_work(struct work_struct *wk); +void ieee80211_tdls_handle_disconnect(struct ieee80211_sub_if_data *sdata, + const u8 *peer, u16 reason); +const char *ieee80211_get_reason_code_string(u16 reason_code); extern const struct ethtool_ops ieee80211_ethtool_ops; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3daf3ae4003b..24eec3cb922d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2743,7 +2743,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, #define case_WLAN(type) \ case WLAN_REASON_##type: return #type -static const char *ieee80211_get_reason_code_string(u16 reason_code) +const char *ieee80211_get_reason_code_string(u16 reason_code) { switch (reason_code) { case_WLAN(UNSPECIFIED); @@ -2808,6 +2808,11 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, if (len < 24 + 2) return; + if (!ether_addr_equal(mgmt->bssid, mgmt->sa)) { + ieee80211_tdls_handle_disconnect(sdata, mgmt->sa, reason_code); + return; + } + if (ifmgd->associated && ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid)) { const u8 *bssid = ifmgd->associated->bssid; @@ -2857,6 +2862,11 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); + if (!ether_addr_equal(mgmt->bssid, mgmt->sa)) { + ieee80211_tdls_handle_disconnect(sdata, mgmt->sa, reason_code); + return; + } + sdata_info(sdata, "disassociated from %pM (Reason: %u=%s)\n", mgmt->sa, reason_code, ieee80211_get_reason_code_string(reason_code)); diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index c9eeb3f12808..ce2ece424384 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -1963,3 +1963,26 @@ void ieee80211_tdls_chsw_work(struct work_struct *wk) } rtnl_unlock(); } + +void ieee80211_tdls_handle_disconnect(struct ieee80211_sub_if_data *sdata, + const u8 *peer, u16 reason) +{ + struct ieee80211_sta *sta; + + rcu_read_lock(); + sta = ieee80211_find_sta(&sdata->vif, peer); + if (!sta || !sta->tdls) { + rcu_read_unlock(); + return; + } + rcu_read_unlock(); + + tdls_dbg(sdata, "disconnected from TDLS peer %pM (Reason: %u=%s)\n", + peer, reason, + ieee80211_get_reason_code_string(reason)); + + ieee80211_tdls_oper_request(&sdata->vif, peer, + NL80211_TDLS_TEARDOWN, + WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE, + GFP_ATOMIC); +} -- cgit v1.2.3 From 2a8d47d551f3fd68d45b1564f1915343d8d26777 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Wed, 9 Jan 2019 23:03:25 -0500 Subject: locking/lockdep: Add debug_locks check in __lock_downgrade() [ Upstream commit 513e1073d52e55b8024b4f238a48de7587c64ccf ] Tetsuo Handa had reported he saw an incorrect "downgrading a read lock" warning right after a previous lockdep warning. It is likely that the previous warning turned off lock debugging causing the lockdep to have inconsistency states leading to the lock downgrade warning. Fix that by add a check for debug_locks at the beginning of __lock_downgrade(). Reported-by: Tetsuo Handa Reported-by: syzbot+53383ae265fb161ef488@syzkaller.appspotmail.com Signed-off-by: Waiman Long Signed-off-by: Peter Zijlstra (Intel) Cc: Andrew Morton Cc: Linus Torvalds Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Link: https://lkml.kernel.org/r/1547093005-26085-1-git-send-email-longman@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin --- kernel/locking/lockdep.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index f2df5f86af28..a419696709a1 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -3314,6 +3314,9 @@ __lock_set_class(struct lockdep_map *lock, const char *name, unsigned int depth; int i; + if (unlikely(!debug_locks)) + return 0; + depth = curr->lockdep_depth; /* * This function is about (re)setting the class of a held lock, -- cgit v1.2.3 From ba118859b4bc7986ce36c78e5b267d1bcaac1ea4 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 5 Sep 2019 14:56:47 +0100 Subject: irqchip/gic-v3-its: Fix LPI release for Multi-MSI devices [ Upstream commit c9c96e30ecaa0aafa225aa1a5392cb7db17c7a82 ] When allocating a range of LPIs for a Multi-MSI capable device, this allocation extended to the closest power of 2. But on the release path, the interrupts are released one by one. This results in not releasing the "extra" range, leaking the its_device. Trying to reprobe the device will then fail. Fix it by releasing the LPIs the same way we allocate them. Fixes: 8208d1708b88 ("irqchip/gic-v3-its: Align PCI Multi-MSI allocation on their size") Reported-by: Jiaxing Luo Tested-by: John Garry Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/f5e948aa-e32f-3f74-ae30-31fee06c2a74@huawei.com Signed-off-by: Sasha Levin --- drivers/irqchip/irq-gic-v3-its.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 114d5883d497..cf11d43ce241 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1372,14 +1372,13 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq, struct its_device *its_dev = irq_data_get_irq_chip_data(d); int i; + bitmap_release_region(its_dev->event_map.lpi_map, + its_get_event_id(irq_domain_get_irq_data(domain, virq)), + get_count_order(nr_irqs)); + for (i = 0; i < nr_irqs; i++) { struct irq_data *data = irq_domain_get_irq_data(domain, virq + i); - u32 event = its_get_event_id(data); - - /* Mark interrupt index as unused */ - clear_bit(event, its_dev->event_map.lpi_map); - /* Nuke the entry in the domain */ irq_domain_reset_irq_data(data); } -- cgit v1.2.3 From bf0b3b4b81c212d00e6bdc7171ad4a7122988d38 Mon Sep 17 00:00:00 2001 From: Surbhi Palande Date: Fri, 23 Aug 2019 15:40:45 -0700 Subject: f2fs: check all the data segments against all node ones [ Upstream commit 1166c1f2f69117ad254189ca781287afa6e550b6 ] As a part of the sanity checking while mounting, distinct segment number assignment to data and node segments is verified. Fixing a small bug in this verification between node and data segments. We need to check all the data segments with all the node segments. Fixes: 042be0f849e5f ("f2fs: fix to do sanity check with current segment number") Signed-off-by: Surbhi Palande Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/super.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index bd0dfaecfac3..aa07c01dc036 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1211,11 +1211,11 @@ int sanity_check_ckpt(struct f2fs_sb_info *sbi) } } for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { - for (j = i; j < NR_CURSEG_DATA_TYPE; j++) { + for (j = 0; j < NR_CURSEG_DATA_TYPE; j++) { if (le32_to_cpu(ckpt->cur_node_segno[i]) == le32_to_cpu(ckpt->cur_data_segno[j])) { f2fs_msg(sbi->sb, KERN_ERR, - "Data segment (%u) and Data segment (%u)" + "Node segment (%u) and Data segment (%u)" " has the same segno: %u", i, j, le32_to_cpu(ckpt->cur_node_segno[i])); return 1; -- cgit v1.2.3 From 810394b3917fe1854a3efa6a545fa46882e5bdbe Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Fri, 2 Aug 2019 18:15:48 +0800 Subject: Revert "f2fs: avoid out-of-range memory access" [ Upstream commit a37d0862d17411edb67677a580a6f505ec2225f6 ] As Pavel Machek reported: "We normally use -EUCLEAN to signal filesystem corruption. Plus, it is good idea to report it to the syslog and mark filesystem as "needing fsck" if filesystem can do that." Still we need improve the original patch with: - use unlikely keyword - add message print - return EUCLEAN However, after rethink this patch, I don't think we should add such condition check here as below reasons: - We have already checked the field in f2fs_sanity_check_ckpt(), - If there is fs corrupt or security vulnerability, there is nothing to guarantee the field is integrated after the check, unless we do the check before each of its use, however no filesystem does that. - We only have similar check for bitmap, which was added due to there is bitmap corruption happened on f2fs' runtime in product. - There are so many key fields in SB/CP/NAT did have such check after f2fs_sanity_check_{sb,cp,..}. So I propose to revert this unneeded check. This reverts commit 56f3ce675103e3fb9e631cfb4131fc768bc23e9a. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/segment.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 014bee5c0e75..6802cd754eda 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1510,11 +1510,6 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi) seg_i = CURSEG_I(sbi, i); segno = le32_to_cpu(ckpt->cur_data_segno[i]); blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]); - if (blk_off > ENTRIES_IN_SUM) { - f2fs_bug_on(sbi, 1); - f2fs_put_page(page, 1); - return -EFAULT; - } seg_i->next_segno = segno; reset_curseg(sbi, i, 0); seg_i->alloc_type = ckpt->alloc_type[i]; -- cgit v1.2.3 From c9aac2ca3403bc20f4c9a320c2e10e489ebda961 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Sat, 25 May 2019 23:07:25 +0800 Subject: f2fs: fix to do sanity check on segment bitmap of LFS curseg [ Upstream commit c854f4d681365498f53ba07843a16423625aa7e9 ] As Jungyeon Reported in bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=203233 - Reproduces gcc poc_13.c ./run.sh f2fs - Kernel messages F2FS-fs (sdb): Bitmap was wrongly set, blk:4608 kernel BUG at fs/f2fs/segment.c:2133! RIP: 0010:update_sit_entry+0x35d/0x3e0 Call Trace: f2fs_allocate_data_block+0x16c/0x5a0 do_write_page+0x57/0x100 f2fs_do_write_node_page+0x33/0xa0 __write_node_page+0x270/0x4e0 f2fs_sync_node_pages+0x5df/0x670 f2fs_write_checkpoint+0x364/0x13a0 f2fs_sync_fs+0xa3/0x130 f2fs_do_sync_file+0x1a6/0x810 do_fsync+0x33/0x60 __x64_sys_fsync+0xb/0x10 do_syscall_64+0x43/0x110 entry_SYSCALL_64_after_hwframe+0x44/0xa9 The testcase fails because that, in fuzzed image, current segment was allocated with LFS type, its .next_blkoff should point to an unused block address, but actually, its bitmap shows it's not. So during allocation, f2fs crash when setting bitmap. Introducing sanity_check_curseg() to check such inconsistence of current in-used segment. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/segment.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 6802cd754eda..e482cca005a6 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2262,6 +2262,41 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi) return init_victim_secmap(sbi); } +static int sanity_check_curseg(struct f2fs_sb_info *sbi) +{ + int i; + + /* + * In LFS/SSR curseg, .next_blkoff should point to an unused blkaddr; + * In LFS curseg, all blkaddr after .next_blkoff should be unused. + */ + for (i = 0; i < NO_CHECK_TYPE; i++) { + struct curseg_info *curseg = CURSEG_I(sbi, i); + struct seg_entry *se = get_seg_entry(sbi, curseg->segno); + unsigned int blkofs = curseg->next_blkoff; + + if (f2fs_test_bit(blkofs, se->cur_valid_map)) + goto out; + + if (curseg->alloc_type == SSR) + continue; + + for (blkofs += 1; blkofs < sbi->blocks_per_seg; blkofs++) { + if (!f2fs_test_bit(blkofs, se->cur_valid_map)) + continue; +out: + f2fs_msg(sbi->sb, KERN_ERR, + "Current segment's next free block offset is " + "inconsistent with bitmap, logtype:%u, " + "segno:%u, type:%u, next_blkoff:%u, blkofs:%u", + i, curseg->segno, curseg->alloc_type, + curseg->next_blkoff, blkofs); + return -EINVAL; + } + } + return 0; +} + /* * Update min, max modified time for cost-benefit GC algorithm */ @@ -2350,6 +2385,10 @@ int build_segment_manager(struct f2fs_sb_info *sbi) if (err) return err; + err = sanity_check_curseg(sbi); + if (err) + return err; + init_min_max_mtime(sbi); return 0; } -- cgit v1.2.3 From 736a524bf6efe6fc324609fe49ded340049df4de Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 3 Jun 2019 14:58:57 +0100 Subject: drm: Flush output polling on shutdown [ Upstream commit 3b295cb1a411d9c82bbfaa66bc17a8508716ed07 ] We need to mark the output polling as disabled to prevent concurrent irqs from queuing new work as shutdown the probe -- causing that work to execute after we have freed the structs: <4> [341.846490] DEBUG_LOCKS_WARN_ON(mutex_is_locked(lock)) <4> [341.846497] WARNING: CPU: 3 PID: 3300 at kernel/locking/mutex-debug.c:103 mutex_destroy+0x49/0x50 <4> [341.846508] Modules linked in: i915(-) vgem thunderbolt snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic mei_hdcp x86_pkg_temp_thermal coretemp crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm mcs7830 btusb usbnet btrtl mii btbcm btintel bluetooth ecdh_generic ecc mei_me mei prime_numbers i2c_hid pinctrl_sunrisepoint pinctrl_intel [last unloaded: i915] <4> [341.846546] CPU: 3 PID: 3300 Comm: i915_module_loa Tainted: G U 5.2.0-rc2-CI-CI_DRM_6175+ #1 <4> [341.846553] Hardware name: Dell Inc. XPS 13 9360/0823VW, BIOS 2.9.0 07/09/2018 <4> [341.846560] RIP: 0010:mutex_destroy+0x49/0x50 <4> [341.846565] Code: 00 00 5b c3 e8 a8 9f 3b 00 85 c0 74 ed 8b 05 3e 55 23 01 85 c0 75 e3 48 c7 c6 00 d0 08 82 48 c7 c7 a8 aa 07 82 e8 e7 08 fa ff <0f> 0b eb cc 0f 1f 00 48 b8 11 11 11 11 11 11 11 11 48 89 76 20 48 <4> [341.846578] RSP: 0018:ffffc900006cfdb0 EFLAGS: 00010286 <4> [341.846583] RAX: 0000000000000000 RBX: ffff88826759a168 RCX: 0000000000000000 <4> [341.846589] RDX: 0000000000000002 RSI: 0000000000000000 RDI: ffffffff8112844c <4> [341.846595] RBP: ffff8882708fa548 R08: 0000000000000000 R09: 0000000000039600 <4> [341.846601] R10: 0000000000000000 R11: 0000000000000ce4 R12: ffffffffa07de1e0 <4> [341.846607] R13: 0000000000000000 R14: 0000000000000000 R15: ffffffffa07de2d0 <4> [341.846613] FS: 00007f62b5ae0e40(0000) GS:ffff888276380000(0000) knlGS:0000000000000000 <4> [341.846620] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 <4> [341.846626] CR2: 000055a4e064f4a0 CR3: 0000000266b16006 CR4: 00000000003606e0 <4> [341.846632] Call Trace: <4> [341.846639] drm_fb_helper_fini.part.17+0xb3/0x100 <4> [341.846682] intel_fbdev_fini+0x20/0x80 [i915] <4> [341.846722] intel_modeset_cleanup+0x9a/0x140 [i915] <4> [341.846750] i915_driver_unload+0xa3/0x100 [i915] <4> [341.846778] i915_pci_remove+0x19/0x30 [i915] <4> [341.846784] pci_device_remove+0x36/0xb0 <4> [341.846790] device_release_driver_internal+0xd3/0x1b0 <4> [341.846795] driver_detach+0x3f/0x80 <4> [341.846800] bus_remove_driver+0x53/0xd0 <4> [341.846805] pci_unregister_driver+0x25/0xa0 <4> [341.846843] i915_exit+0x16/0x1c [i915] <4> [341.846849] __se_sys_delete_module+0x162/0x210 <4> [341.846855] ? trace_hardirqs_off_thunk+0x1a/0x1c <4> [341.846859] ? do_syscall_64+0xd/0x1c0 <4> [341.846864] do_syscall_64+0x55/0x1c0 <4> [341.846869] entry_SYSCALL_64_after_hwframe+0x49/0xbe <4> [341.846875] RIP: 0033:0x7f62b51871b7 <4> [341.846881] Code: 73 01 c3 48 8b 0d d1 8c 2c 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 b8 b0 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d a1 8c 2c 00 f7 d8 64 89 01 48 <4> [341.846897] RSP: 002b:00007ffe7a227138 EFLAGS: 00000206 ORIG_RAX: 00000000000000b0 <4> [341.846904] RAX: ffffffffffffffda RBX: 00007ffe7a2272b0 RCX: 00007f62b51871b7 <4> [341.846910] RDX: 0000000000000001 RSI: 0000000000000800 RDI: 0000557cd6b55948 <4> [341.846916] RBP: 0000557cd6b558e0 R08: 0000557cd6b5594c R09: 00007ffe7a227160 <4> [341.846922] R10: 00007ffe7a226134 R11: 0000000000000206 R12: 0000000000000000 <4> [341.846927] R13: 00007ffe7a227820 R14: 0000000000000000 R15: 0000000000000000 <4> [341.846936] irq event stamp: 3547847 <4> [341.846940] hardirqs last enabled at (3547847): [] _raw_spin_unlock_irqrestore+0x4c/0x60 <4> [341.846949] hardirqs last disabled at (3547846): [] _raw_spin_lock_irqsave+0xd/0x50 <4> [341.846957] softirqs last enabled at (3547376): [] __do_softirq+0x33a/0x4b9 <4> [341.846966] softirqs last disabled at (3547367): [] irq_exit+0xa9/0xc0 <4> [341.846973] WARNING: CPU: 3 PID: 3300 at kernel/locking/mutex-debug.c:103 mutex_destroy+0x49/0x50 <4> [341.846980] ---[ end trace ba94ca8952ba970e ]--- <7> [341.866547] [drm:intel_dp_detect [i915]] MST support? port A: no, sink: no, modparam: yes <7> [341.890480] [drm:drm_add_display_info] non_desktop set to 0 <7> [341.890530] [drm:drm_add_edid_modes] ELD: no CEA Extension found <7> [341.890537] [drm:drm_add_display_info] non_desktop set to 0 <7> [341.890578] [drm:drm_helper_probe_single_connector_modes] [CONNECTOR:86:eDP-1] probed modes : <7> [341.890589] [drm:drm_mode_debug_printmodeline] Modeline "3200x1800": 60 373250 3200 3248 3280 3360 1800 1803 1808 1852 0x48 0xa <7> [341.890602] [drm:drm_mode_debug_printmodeline] Modeline "3200x1800": 48 298600 3200 3248 3280 3360 1800 1803 1808 1852 0x40 0xa <4> [341.890628] general protection fault: 0000 [#1] PREEMPT SMP PTI <4> [341.890636] CPU: 0 PID: 508 Comm: kworker/0:4 Tainted: G U W 5.2.0-rc2-CI-CI_DRM_6175+ #1 <4> [341.890646] Hardware name: Dell Inc. XPS 13 9360/0823VW, BIOS 2.9.0 07/09/2018 <4> [341.890655] Workqueue: events output_poll_execute <4> [341.890663] RIP: 0010:drm_setup_crtcs+0x13e/0xbe0 <4> [341.890669] Code: 00 41 8b 44 24 58 85 c0 0f 8e f9 01 00 00 44 8b 6c 24 20 44 8b 74 24 28 31 db 31 ed 49 8b 44 24 60 48 63 d5 44 89 ee 83 c5 01 <48> 8b 04 d0 44 89 f2 48 8b 38 48 8b 87 88 01 00 00 48 8b 40 20 e8 <4> [341.890686] RSP: 0018:ffffc9000033fd40 EFLAGS: 00010202 <4> [341.890692] RAX: 6b6b6b6b6b6b6b6b RBX: 0000000000000002 RCX: 0000000000000000 <4> [341.890700] RDX: 0000000000000001 RSI: 0000000000000c80 RDI: 00000000ffffffff <4> [341.890707] RBP: 0000000000000002 R08: 0000000000000000 R09: 0000000000000000 <4> [341.890715] R10: 0000000000000c80 R11: 0000000000000000 R12: ffff888267599fe8 <4> [341.890722] R13: 0000000000000c80 R14: 0000000000000708 R15: 0000000000000007 <4> [341.890730] FS: 0000000000000000(0000) GS:ffff888276200000(0000) knlGS:0000000000000000 <4> [341.890739] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 <4> [341.890745] CR2: 000055a4e064f4a0 CR3: 000000026d234003 CR4: 00000000003606f0 <4> [341.890752] Call Trace: <4> [341.890760] drm_fb_helper_hotplug_event.part.24+0x89/0xb0 <4> [341.890768] drm_kms_helper_hotplug_event+0x21/0x30 <4> [341.890774] output_poll_execute+0x9d/0x1a0 <4> [341.890782] process_one_work+0x245/0x610 <4> [341.890790] worker_thread+0x37/0x380 <4> [341.890796] ? process_one_work+0x610/0x610 <4> [341.890802] kthread+0x119/0x130 <4> [341.890808] ? kthread_park+0x80/0x80 <4> [341.890815] ret_from_fork+0x3a/0x50 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=109964 Signed-off-by: Chris Wilson Reviewed-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20190603135910.15979-2-chris@chris-wilson.co.uk Signed-off-by: Sasha Levin --- drivers/gpu/drm/drm_probe_helper.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 1fe4b8e6596b..de1797b3a746 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -338,6 +338,9 @@ static void output_poll_execute(struct work_struct *work) enum drm_connector_status old_status; bool repoll = false, changed; + if (!dev->mode_config.poll_enabled) + return; + /* Pick up any changes detected by the probe functions. */ changed = dev->mode_config.delayed_event; dev->mode_config.delayed_event = false; @@ -501,7 +504,11 @@ EXPORT_SYMBOL(drm_kms_helper_poll_init); */ void drm_kms_helper_poll_fini(struct drm_device *dev) { - drm_kms_helper_poll_disable(dev); + if (!dev->mode_config.poll_enabled) + return; + + dev->mode_config.poll_enabled = false; + cancel_delayed_work_sync(&dev->mode_config.output_poll_work); } EXPORT_SYMBOL(drm_kms_helper_poll_fini); -- cgit v1.2.3 From e76fb5f7e8b9d5a80b928a2df8c86521c7963aeb Mon Sep 17 00:00:00 2001 From: Jian-Hong Pan Date: Tue, 3 Sep 2019 17:10:42 +0800 Subject: Bluetooth: btrtl: Additional Realtek 8822CE Bluetooth devices [ Upstream commit 6d0762b19c5963ff9e178e8af3626532ee04d93d ] The ASUS X412FA laptop contains a Realtek RTL8822CE device with an associated BT chip using a USB ID of 04ca:4005. This ID is added to the driver. The /sys/kernel/debug/usb/devices portion for this device is: T: Bus=01 Lev=01 Prnt=01 Port=09 Cnt=04 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=04ca ProdID=4005 Rev= 0.00 S: Manufacturer=Realtek S: Product=Bluetooth Radio S: SerialNumber=00e04c000001 C:* #Ifs= 2 Cfg#= 1 Atr=a0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=204707 Signed-off-by: Jian-Hong Pan Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b0a12e6dae43..fcc12c879659 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -353,6 +353,9 @@ static const struct usb_device_id blacklist_table[] = { /* Additional Realtek 8822BE Bluetooth devices */ { USB_DEVICE(0x0b05, 0x185c), .driver_info = BTUSB_REALTEK }, + /* Additional Realtek 8822CE Bluetooth devices */ + { USB_DEVICE(0x04ca, 0x4005), .driver_info = BTUSB_REALTEK }, + /* Silicon Wave based devices */ { USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE }, -- cgit v1.2.3 From d7065a5e68efd4ed633ccd8d2333f067e2e51101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 20 Sep 2019 16:08:21 +0200 Subject: arcnet: provide a buffer big enough to actually receive packets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 108639aac35eb57f1d0e8333f5fc8c7ff68df938 ] struct archdr is only big enough to hold the header of various types of arcnet packets. So to provide enough space to hold the data read from hardware provide a buffer large enough to hold a packet with maximal size. The problem was noticed by the stack protector which makes the kernel oops. Signed-off-by: Uwe Kleine-König Acked-by: Michael Grzeschik Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/arcnet/arcnet.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 6ea963e3b89a..85ffd0561827 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -1009,31 +1009,34 @@ EXPORT_SYMBOL(arcnet_interrupt); static void arcnet_rx(struct net_device *dev, int bufnum) { struct arcnet_local *lp = netdev_priv(dev); - struct archdr pkt; + union { + struct archdr pkt; + char buf[512]; + } rxdata; struct arc_rfc1201 *soft; int length, ofs; - soft = &pkt.soft.rfc1201; + soft = &rxdata.pkt.soft.rfc1201; - lp->hw.copy_from_card(dev, bufnum, 0, &pkt, ARC_HDR_SIZE); - if (pkt.hard.offset[0]) { - ofs = pkt.hard.offset[0]; + lp->hw.copy_from_card(dev, bufnum, 0, &rxdata.pkt, ARC_HDR_SIZE); + if (rxdata.pkt.hard.offset[0]) { + ofs = rxdata.pkt.hard.offset[0]; length = 256 - ofs; } else { - ofs = pkt.hard.offset[1]; + ofs = rxdata.pkt.hard.offset[1]; length = 512 - ofs; } /* get the full header, if possible */ - if (sizeof(pkt.soft) <= length) { - lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(pkt.soft)); + if (sizeof(rxdata.pkt.soft) <= length) { + lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(rxdata.pkt.soft)); } else { - memset(&pkt.soft, 0, sizeof(pkt.soft)); + memset(&rxdata.pkt.soft, 0, sizeof(rxdata.pkt.soft)); lp->hw.copy_from_card(dev, bufnum, ofs, soft, length); } arc_printk(D_DURING, dev, "Buffer #%d: received packet from %02Xh to %02Xh (%d+4 bytes)\n", - bufnum, pkt.hard.source, pkt.hard.dest, length); + bufnum, rxdata.pkt.hard.source, rxdata.pkt.hard.dest, length); dev->stats.rx_packets++; dev->stats.rx_bytes += length + ARC_HDR_SIZE; @@ -1042,13 +1045,13 @@ static void arcnet_rx(struct net_device *dev, int bufnum) if (arc_proto_map[soft->proto]->is_ip) { if (BUGLVL(D_PROTO)) { struct ArcProto - *oldp = arc_proto_map[lp->default_proto[pkt.hard.source]], + *oldp = arc_proto_map[lp->default_proto[rxdata.pkt.hard.source]], *newp = arc_proto_map[soft->proto]; if (oldp != newp) { arc_printk(D_PROTO, dev, "got protocol %02Xh; encap for host %02Xh is now '%c' (was '%c')\n", - soft->proto, pkt.hard.source, + soft->proto, rxdata.pkt.hard.source, newp->suffix, oldp->suffix); } } @@ -1057,10 +1060,10 @@ static void arcnet_rx(struct net_device *dev, int bufnum) lp->default_proto[0] = soft->proto; /* in striking contrast, the following isn't a hack. */ - lp->default_proto[pkt.hard.source] = soft->proto; + lp->default_proto[rxdata.pkt.hard.source] = soft->proto; } /* call the protocol-specific receiver. */ - arc_proto_map[soft->proto]->rx(dev, bufnum, &pkt, length); + arc_proto_map[soft->proto]->rx(dev, bufnum, &rxdata.pkt, length); } static void null_rx(struct net_device *dev, int bufnum, -- cgit v1.2.3 From b5f703829cf6bd81275a7a3ca31b3902f0a0f171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 18 Sep 2019 14:01:46 +0200 Subject: cdc_ncm: fix divide-by-zero caused by invalid wMaxPacketSize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 3fe4b3351301660653a2bc73f2226da0ebd2b95e ] Endpoints with zero wMaxPacketSize are not usable for transferring data. Ignore such endpoints when looking for valid in, out and status pipes, to make the driver more robust against invalid and meaningless descriptors. The wMaxPacketSize of the out pipe is used as divisor. So this change fixes a divide-by-zero bug. Reported-by: syzbot+ce366e2b8296e25d84f5@syzkaller.appspotmail.com Signed-off-by: Bjørn Mork Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/cdc_ncm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 1e921e5eddc7..442efbccd005 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -636,8 +636,12 @@ cdc_ncm_find_endpoints(struct usbnet *dev, struct usb_interface *intf) u8 ep; for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) { - e = intf->cur_altsetting->endpoint + ep; + + /* ignore endpoints which cannot transfer data */ + if (!usb_endpoint_maxp(&e->desc)) + continue; + switch (e->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_INT: if (usb_endpoint_dir_in(&e->desc)) { -- cgit v1.2.3 From cecefdab590bc58c9304a2b9c1275d981e267251 Mon Sep 17 00:00:00 2001 From: Peter Mamonov Date: Wed, 18 Sep 2019 19:27:55 +0300 Subject: net/phy: fix DP83865 10 Mbps HDX loopback disable function [ Upstream commit e47488b2df7f9cb405789c7f5d4c27909fc597ae ] According to the DP83865 datasheet "the 10 Mbps HDX loopback can be disabled in the expanded memory register 0x1C0.1". The driver erroneously used bit 0 instead of bit 1. Fixes: 4621bf129856 ("phy: Add file missed in previous commit.") Signed-off-by: Peter Mamonov Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/national.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c index 0a7b9c7f09a2..5c40655ec808 100644 --- a/drivers/net/phy/national.c +++ b/drivers/net/phy/national.c @@ -110,14 +110,17 @@ static void ns_giga_speed_fallback(struct phy_device *phydev, int mode) static void ns_10_base_t_hdx_loopack(struct phy_device *phydev, int disable) { + u16 lb_dis = BIT(1); + if (disable) - ns_exp_write(phydev, 0x1c0, ns_exp_read(phydev, 0x1c0) | 1); + ns_exp_write(phydev, 0x1c0, + ns_exp_read(phydev, 0x1c0) | lb_dis); else ns_exp_write(phydev, 0x1c0, - ns_exp_read(phydev, 0x1c0) & 0xfffe); + ns_exp_read(phydev, 0x1c0) & ~lb_dis); pr_debug("10BASE-T HDX loopback %s\n", - (ns_exp_read(phydev, 0x1c0) & 0x0001) ? "off" : "on"); + (ns_exp_read(phydev, 0x1c0) & lb_dis) ? "off" : "on"); } static int ns_config_init(struct phy_device *phydev) -- cgit v1.2.3 From 4c8afdc16e45c49656cc66981f5c30ac0baf69a8 Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Tue, 24 Sep 2019 19:11:52 +0800 Subject: openvswitch: change type of UPCALL_PID attribute to NLA_UNSPEC [ Upstream commit ea8564c865299815095bebeb4b25bef474218e4c ] userspace openvswitch patch "(dpif-linux: Implement the API functions to allow multiple handler threads read upcall)" changes its type from U32 to UNSPEC, but leave the kernel unchanged and after kernel 6e237d099fac "(netlink: Relax attr validation for fixed length types)", this bug is exposed by the below warning [ 57.215841] netlink: 'ovs-vswitchd': attribute type 5 has an invalid length. Fixes: 5cd667b0a456 ("openvswitch: Allow each vport to have an array of 'port_id's") Signed-off-by: Li RongQing Acked-by: Pravin B Shelar Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/openvswitch/datapath.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index deadfdab1bc3..caa23ee913f0 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -2152,7 +2152,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) }, [OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 }, [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 }, - [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_U32 }, + [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_UNSPEC }, [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, }; -- cgit v1.2.3 From 9601d33226baf4155960ea24a164b584e9c38ef2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Sep 2019 08:05:39 -0700 Subject: sch_netem: fix a divide by zero in tabledist() [ Upstream commit b41d936b5ecfdb3a4abc525ce6402a6c49cffddc ] syzbot managed to crash the kernel in tabledist() loading an empty distribution table. t = dist->table[rnd % dist->size]; Simply return an error when such load is attempted. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_netem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 7acf1f2b8dfc..2a431628af59 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -713,7 +713,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) int i; size_t s; - if (n > NETEM_DIST_MAX) + if (!n || n > NETEM_DIST_MAX) return -EINVAL; s = sizeof(struct disttable) + n * sizeof(s16); -- cgit v1.2.3 From 2a7604cde62bdebaec8cc2e487349ed47dabb8a0 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 20 Sep 2019 18:18:26 +0200 Subject: skge: fix checksum byte order [ Upstream commit 5aafeb74b5bb65b34cc87c7623f9fa163a34fa3b ] Running old skge driver on PowerPC causes checksum errors because hardware reported 1's complement checksum is in little-endian byte order. Reported-by: Benoit Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/marvell/skge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c index c9f4b5412844..b97a070074b7 100644 --- a/drivers/net/ethernet/marvell/skge.c +++ b/drivers/net/ethernet/marvell/skge.c @@ -3114,7 +3114,7 @@ static struct sk_buff *skge_rx_get(struct net_device *dev, skb_put(skb, len); if (dev->features & NETIF_F_RXCSUM) { - skb->csum = csum; + skb->csum = le16_to_cpu(csum); skb->ip_summed = CHECKSUM_COMPLETE; } -- cgit v1.2.3 From 608557096364a7307467e3f5b005630dd2835f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Wed, 18 Sep 2019 14:17:38 +0200 Subject: usbnet: ignore endpoints with invalid wMaxPacketSize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8d3d7c2029c1b360f1a6b0a2fca470b57eb575c0 ] Endpoints with zero wMaxPacketSize are not usable for transferring data. Ignore such endpoints when looking for valid in, out and status pipes, to make the drivers more robust against invalid and meaningless descriptors. The wMaxPacketSize of these endpoints are used for memory allocations and as divisors in many usbnet minidrivers. Avoiding zero is therefore critical. Signed-off-by: Bjørn Mork Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/usbnet.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 2502681369cd..6c531abe198b 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -115,6 +115,11 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) int intr = 0; e = alt->endpoint + ep; + + /* ignore endpoints which cannot transfer data */ + if (!usb_endpoint_maxp(&e->desc)) + continue; + switch (e->desc.bmAttributes) { case USB_ENDPOINT_XFER_INT: if (!usb_endpoint_dir_in(&e->desc)) -- cgit v1.2.3 From a4d63b4102316eb10cc1bf37274d50a4d4f8962c Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 19 Sep 2019 10:23:08 +0200 Subject: usbnet: sanity checking of packet sizes and device mtu [ Upstream commit 280ceaed79f18db930c0cc8bb21f6493490bf29c ] After a reset packet sizes and device mtu can change and need to be reevaluated to calculate queue sizes. Malicious devices can set this to zero and we divide by it. Introduce sanity checking. Reported-and-tested-by: syzbot+6102c120be558c885f04@syzkaller.appspotmail.com Signed-off-by: Oliver Neukum Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/usbnet.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 6c531abe198b..5a09aff4155a 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -352,6 +352,8 @@ void usbnet_update_max_qlen(struct usbnet *dev) { enum usb_device_speed speed = dev->udev->speed; + if (!dev->rx_urb_size || !dev->hard_mtu) + goto insanity; switch (speed) { case USB_SPEED_HIGH: dev->rx_qlen = MAX_QUEUE_MEMORY / dev->rx_urb_size; @@ -367,6 +369,7 @@ void usbnet_update_max_qlen(struct usbnet *dev) dev->tx_qlen = 5 * MAX_QUEUE_MEMORY / dev->hard_mtu; break; default: +insanity: dev->rx_qlen = dev->tx_qlen = 4; } } -- cgit v1.2.3 From a03818269bfbc2ff6d25e3e44eb2247df53648ca Mon Sep 17 00:00:00 2001 From: Ori Nimron Date: Fri, 20 Sep 2019 09:35:45 +0200 Subject: mISDN: enforce CAP_NET_RAW for raw sockets [ Upstream commit b91ee4aa2a2199ba4d4650706c272985a5a32d80 ] When creating a raw AF_ISDN socket, CAP_NET_RAW needs to be checked first. Signed-off-by: Ori Nimron Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/mISDN/socket.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 8cbb75d09a1d..75962c62304d 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -763,6 +763,8 @@ base_sock_create(struct net *net, struct socket *sock, int protocol, int kern) if (sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; + if (!capable(CAP_NET_RAW)) + return -EPERM; sk = sk_alloc(net, PF_ISDN, GFP_KERNEL, &mISDN_proto, kern); if (!sk) -- cgit v1.2.3 From ec1e04b8979464990e000850d14d3e562999a82d Mon Sep 17 00:00:00 2001 From: Ori Nimron Date: Fri, 20 Sep 2019 09:35:46 +0200 Subject: appletalk: enforce CAP_NET_RAW for raw sockets [ Upstream commit 6cc03e8aa36c51f3b26a0d21a3c4ce2809c842ac ] When creating a raw AF_APPLETALK socket, CAP_NET_RAW needs to be checked first. Signed-off-by: Ori Nimron Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/appletalk/ddp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 4246df3b7ae8..e23bf739492c 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -1029,6 +1029,11 @@ static int atalk_create(struct net *net, struct socket *sock, int protocol, */ if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) goto out; + + rc = -EPERM; + if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) + goto out; + rc = -ENOMEM; sk = sk_alloc(net, PF_APPLETALK, GFP_KERNEL, &ddp_proto, kern); if (!sk) -- cgit v1.2.3 From c15d89b5cb86dfcdee536d093ece512091ed6e5c Mon Sep 17 00:00:00 2001 From: Ori Nimron Date: Fri, 20 Sep 2019 09:35:47 +0200 Subject: ax25: enforce CAP_NET_RAW for raw sockets [ Upstream commit 0614e2b73768b502fc32a75349823356d98aae2c ] When creating a raw AF_AX25 socket, CAP_NET_RAW needs to be checked first. Signed-off-by: Ori Nimron Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ax25/af_ax25.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 2772f6a13fcb..de55a3f001dc 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -859,6 +859,8 @@ static int ax25_create(struct net *net, struct socket *sock, int protocol, break; case SOCK_RAW: + if (!capable(CAP_NET_RAW)) + return -EPERM; break; default: return -ESOCKTNOSUPPORT; -- cgit v1.2.3 From a279cd311c1e3870de25fe48e948487b4785e9cd Mon Sep 17 00:00:00 2001 From: Ori Nimron Date: Fri, 20 Sep 2019 09:35:48 +0200 Subject: ieee802154: enforce CAP_NET_RAW for raw sockets [ Upstream commit e69dbd4619e7674c1679cba49afd9dd9ac347eef ] When creating a raw AF_IEEE802154 socket, CAP_NET_RAW needs to be checked first. Signed-off-by: Ori Nimron Signed-off-by: Greg Kroah-Hartman Acked-by: Stefan Schmidt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ieee802154/socket.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c index 47b397264f24..cb6c0772ea36 100644 --- a/net/ieee802154/socket.c +++ b/net/ieee802154/socket.c @@ -999,6 +999,9 @@ static int ieee802154_create(struct net *net, struct socket *sock, switch (sock->type) { case SOCK_RAW: + rc = -EPERM; + if (!capable(CAP_NET_RAW)) + goto out; proto = &ieee802154_raw_prot; ops = &ieee802154_raw_ops; break; -- cgit v1.2.3 From 001ff467264f3e51c8bb18de5cbe62e91d05cfc5 Mon Sep 17 00:00:00 2001 From: Ori Nimron Date: Fri, 20 Sep 2019 09:35:49 +0200 Subject: nfc: enforce CAP_NET_RAW for raw sockets [ Upstream commit 3a359798b176183ef09efb7a3dc59abad1cc7104 ] When creating a raw AF_NFC socket, CAP_NET_RAW needs to be checked first. Signed-off-by: Ori Nimron Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/nfc/llcp_sock.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c index 9c222a106c7f..2dfd1c815203 100644 --- a/net/nfc/llcp_sock.c +++ b/net/nfc/llcp_sock.c @@ -1005,10 +1005,13 @@ static int llcp_sock_create(struct net *net, struct socket *sock, sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; - if (sock->type == SOCK_RAW) + if (sock->type == SOCK_RAW) { + if (!capable(CAP_NET_RAW)) + return -EPERM; sock->ops = &llcp_rawsock_ops; - else + } else { sock->ops = &llcp_sock_ops; + } sk = nfc_llcp_sock_alloc(sock, sock->type, GFP_ATOMIC, kern); if (sk == NULL) -- cgit v1.2.3 From f49a9f57ed39b6bc75649764785a6173b910e553 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 20 Jul 2019 12:33:37 +0100 Subject: ALSA: hda: Flush interrupts on disabling [ Upstream commit caa8422d01e983782548648e125fd617cadcec3f ] I was looking at <4> [241.835158] general protection fault: 0000 [#1] PREEMPT SMP PTI <4> [241.835181] CPU: 1 PID: 214 Comm: kworker/1:3 Tainted: G U 5.2.0-CI-CI_DRM_6509+ #1 <4> [241.835199] Hardware name: Dell Inc. OptiPlex 745 /0GW726, BIOS 2.3.1 05/21/2007 <4> [241.835234] Workqueue: events snd_hdac_bus_process_unsol_events [snd_hda_core] <4> [241.835256] RIP: 0010:input_handle_event+0x16d/0x5e0 <4> [241.835270] Code: 48 8b 93 58 01 00 00 8b 52 08 89 50 04 8b 83 f8 06 00 00 48 8b 93 00 07 00 00 8d 70 01 48 8d 04 c2 83 e1 08 89 b3 f8 06 00 00 <66> 89 28 66 44 89 60 02 44 89 68 04 8b 93 f8 06 00 00 0f 84 fd fe <4> [241.835304] RSP: 0018:ffffc9000019fda0 EFLAGS: 00010046 <4> [241.835317] RAX: 6b6b6b6ec6c6c6c3 RBX: ffff8880290fefc8 RCX: 0000000000000000 <4> [241.835332] RDX: 000000006b6b6b6b RSI: 000000006b6b6b6c RDI: 0000000000000046 <4> [241.835347] RBP: 0000000000000005 R08: 0000000000000000 R09: 0000000000000001 <4> [241.835362] R10: ffffc9000019faa0 R11: 0000000000000000 R12: 0000000000000004 <4> [241.835377] R13: 0000000000000000 R14: ffff8880290ff1d0 R15: 0000000000000293 <4> [241.835392] FS: 0000000000000000(0000) GS:ffff88803de80000(0000) knlGS:0000000000000000 <4> [241.835409] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 <4> [241.835422] CR2: 00007ffe9a99e9b7 CR3: 000000002f588000 CR4: 00000000000006e0 <4> [241.835436] Call Trace: <4> [241.835449] input_event+0x45/0x70 <4> [241.835464] snd_jack_report+0xdc/0x100 <4> [241.835490] snd_hda_jack_report_sync+0x83/0xc0 [snd_hda_codec] <4> [241.835512] snd_hdac_bus_process_unsol_events+0x5a/0x70 [snd_hda_core] <4> [241.835530] process_one_work+0x245/0x610 which has the hallmarks of a worker queued from interrupt after it was supposedly cancelled (note the POISON_FREE), and I could not see where the interrupt would be flushed on shutdown so added the likely suspects. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=111174 Signed-off-by: Chris Wilson Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/hda/hdac_controller.c | 2 ++ sound/pci/hda/hda_intel.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/hda/hdac_controller.c b/sound/hda/hdac_controller.c index 4727f5b80e76..acc2c7dbfb15 100644 --- a/sound/hda/hdac_controller.c +++ b/sound/hda/hdac_controller.c @@ -340,6 +340,8 @@ static void azx_int_disable(struct hdac_bus *bus) list_for_each_entry(azx_dev, &bus->stream_list, list) snd_hdac_stream_updateb(azx_dev, SD_CTL, SD_INT_MASK, 0); + synchronize_irq(bus->irq); + /* disable SIE for all streams */ snd_hdac_chip_writeb(bus, INTCTL, 0); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ef8955abd918..96ccab15da83 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1274,9 +1274,9 @@ static int azx_free(struct azx *chip) } if (bus->chip_init) { + azx_stop_chip(chip); azx_clear_irq_pending(chip); azx_stop_all_streams(chip); - azx_stop_chip(chip); } if (bus->irq >= 0) -- cgit v1.2.3 From ae6be6302e18dea7df8a61634f89d91c4abb986a Mon Sep 17 00:00:00 2001 From: Oleksandr Suvorov Date: Fri, 19 Jul 2019 10:05:37 +0000 Subject: ASoC: sgtl5000: Fix charge pump source assignment [ Upstream commit b6319b061ba279577fd7030a9848fbd6a17151e3 ] If VDDA != VDDIO and any of them is greater than 3.1V, charge pump source can be assigned automatically [1]. [1] https://www.nxp.com/docs/en/data-sheet/SGTL5000.pdf Signed-off-by: Oleksandr Suvorov Reviewed-by: Marcel Ziswiler Reviewed-by: Igor Opaniuk Reviewed-by: Fabio Estevam Link: https://lore.kernel.org/r/20190719100524.23300-7-oleksandr.suvorov@toradex.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/sgtl5000.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 08b40460663c..549f853c4092 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1166,12 +1166,17 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) SGTL5000_INT_OSC_EN); /* Enable VDDC charge pump */ ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP; - } else if (vddio >= 3100 && vdda >= 3100) { + } else { ana_pwr &= ~SGTL5000_VDDC_CHRGPMP_POWERUP; - /* VDDC use VDDIO rail */ - lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD; - lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO << - SGTL5000_VDDC_MAN_ASSN_SHIFT; + /* + * if vddio == vdda the source of charge pump should be + * assigned manually to VDDIO + */ + if (vddio == vdda) { + lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD; + lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO << + SGTL5000_VDDC_MAN_ASSN_SHIFT; + } } snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL, lreg_ctrl); -- cgit v1.2.3 From 2989ee3412b7135b8362a0cc1ae30d6dd31e61d4 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Tue, 16 Jul 2019 19:15:18 +0200 Subject: dmaengine: bcm2835: Print error in case setting DMA mask fails [ Upstream commit 72503b25ee363827aafffc3e8d872e6a92a7e422 ] During enabling of the RPi 4, we found out that the driver doesn't provide a helpful error message in case setting DMA mask fails. So add one. Signed-off-by: Stefan Wahren Link: https://lore.kernel.org/r/1563297318-4900-1-git-send-email-wahrenst@gmx.net Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/bcm2835-dma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 996c4b00d323..d6cdc3be03fc 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -595,8 +595,10 @@ static int bcm2835_dma_probe(struct platform_device *pdev) pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - if (rc) + if (rc) { + dev_err(&pdev->dev, "Unable to set DMA mask\n"); return rc; + } od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL); if (!od) -- cgit v1.2.3 From 28b772b6890184b5de673230be6991402f6d05c4 Mon Sep 17 00:00:00 2001 From: Nick Stoughton Date: Wed, 17 Jul 2019 14:56:06 -0700 Subject: leds: leds-lp5562 allow firmware files up to the maximum length [ Upstream commit ed2abfebb041473092b41527903f93390d38afa7 ] Firmware files are in ASCII, using 2 hex characters per byte. The maximum length of a firmware string is therefore 16 (commands) * 2 (bytes per command) * 2 (characters per byte) = 64 Fixes: ff45262a85db ("leds: add new LP5562 LED driver") Signed-off-by: Nick Stoughton Acked-by: Pavel Machek Signed-off-by: Jacek Anaszewski Signed-off-by: Sasha Levin --- drivers/leds/leds-lp5562.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c index 0360c59dbdc9..fc8b2e7bcfef 100644 --- a/drivers/leds/leds-lp5562.c +++ b/drivers/leds/leds-lp5562.c @@ -263,7 +263,11 @@ static void lp5562_firmware_loaded(struct lp55xx_chip *chip) { const struct firmware *fw = chip->fw; - if (fw->size > LP5562_PROGRAM_LENGTH) { + /* + * the firmware is encoded in ascii hex character, with 2 chars + * per byte + */ + if (fw->size > (LP5562_PROGRAM_LENGTH * 2)) { dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n", fw->size); return; -- cgit v1.2.3 From 78335bc692d72f54348e95ee62e1942401faf995 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 28 Jun 2019 08:14:53 -0400 Subject: media: dib0700: fix link error for dibx000_i2c_set_speed [ Upstream commit 765bb8610d305ee488b35d07e2a04ae52fb2df9c ] When CONFIG_DVB_DIB9000 is disabled, we can still compile code that now fails to link against dibx000_i2c_set_speed: drivers/media/usb/dvb-usb/dib0700_devices.o: In function `dib01x0_pmu_update.constprop.7': dib0700_devices.c:(.text.unlikely+0x1c9c): undefined reference to `dibx000_i2c_set_speed' The call sites are both through dib01x0_pmu_update(), which gets passed an 'i2c' pointer from dib9000_get_i2c_master(), which has returned NULL. Checking this pointer seems to be a good idea anyway, and it avoids the link failure in most cases. Sean Young found another case that is not fixed by that, where certain gcc versions leave an unused function in place that causes the link error, but adding an explict IS_ENABLED() check also solves this. Fixes: b7f54910ce01 ("V4L/DVB (4647): Added module for DiB0700 based devices") Signed-off-by: Arnd Bergmann Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/usb/dvb-usb/dib0700_devices.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 38c03283a441..e1316c7b7c2e 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -2418,9 +2418,13 @@ static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) 8, 0x0486, }; + if (!IS_ENABLED(CONFIG_DVB_DIB9000)) + return -ENODEV; if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &dib9090_dib0090_config) == NULL) return -ENODEV; i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + if (!i2c) + return -ENODEV; if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0) return -ENODEV; dib0700_set_i2c_speed(adap->dev, 1500); @@ -2496,10 +2500,14 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) 0, 0x00ef, 8, 0x0406, }; + if (!IS_ENABLED(CONFIG_DVB_DIB9000)) + return -ENODEV; i2c = dib9000_get_tuner_interface(adap->fe_adap[0].fe); if (dvb_attach(dib0090_fw_register, adap->fe_adap[0].fe, i2c, &nim9090md_dib0090_config[0]) == NULL) return -ENODEV; i2c = dib9000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + if (!i2c) + return -ENODEV; if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0) return -ENODEV; -- cgit v1.2.3 From 84a6dd572b18177bc66dd90b4a865eb3f8c0a1c0 Mon Sep 17 00:00:00 2001 From: Luke Nowakowski-Krijger Date: Wed, 17 Jul 2019 10:19:46 -0400 Subject: media: hdpvr: Add device num check and handling [ Upstream commit d4a6a9537bc32811486282206ecfb7c53754b74d ] Add hdpvr device num check and error handling We need to increment the device count atomically before we checkout a device to make sure that we do not reach the max count, otherwise we get out-of-bounds errors as reported by syzbot. Reported-and-tested-by: syzbot+aac8d0d7205f112045d2@syzkaller.appspotmail.com Signed-off-by: Luke Nowakowski-Krijger Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/usb/hdpvr/hdpvr-core.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index 08f0ca7aa012..924517b09fc9 100644 --- a/drivers/media/usb/hdpvr/hdpvr-core.c +++ b/drivers/media/usb/hdpvr/hdpvr-core.c @@ -278,6 +278,7 @@ static int hdpvr_probe(struct usb_interface *interface, #endif size_t buffer_size; int i; + int dev_num; int retval = -ENOMEM; /* allocate memory for our device state and initialize it */ @@ -386,8 +387,17 @@ static int hdpvr_probe(struct usb_interface *interface, } #endif + dev_num = atomic_inc_return(&dev_nr); + if (dev_num >= HDPVR_MAX) { + v4l2_err(&dev->v4l2_dev, + "max device number reached, device register failed\n"); + atomic_dec(&dev_nr); + retval = -ENODEV; + goto reg_fail; + } + retval = hdpvr_register_videodev(dev, &interface->dev, - video_nr[atomic_inc_return(&dev_nr)]); + video_nr[dev_num]); if (retval < 0) { v4l2_err(&dev->v4l2_dev, "registering videodev failed\n"); goto reg_fail; -- cgit v1.2.3 From 5da394bd2dc1679d52f0e0d9f220739b9a404741 Mon Sep 17 00:00:00 2001 From: Vincent Guittot Date: Mon, 1 Jul 2019 17:47:02 +0200 Subject: sched/fair: Fix imbalance due to CPU affinity [ Upstream commit f6cad8df6b30a5d2bbbd2e698f74b4cafb9fb82b ] The load_balance() has a dedicated mecanism to detect when an imbalance is due to CPU affinity and must be handled at parent level. In this case, the imbalance field of the parent's sched_group is set. The description of sg_imbalanced() gives a typical example of two groups of 4 CPUs each and 4 tasks each with a cpumask covering 1 CPU of the first group and 3 CPUs of the second group. Something like: { 0 1 2 3 } { 4 5 6 7 } * * * * But the load_balance fails to fix this UC on my octo cores system made of 2 clusters of quad cores. Whereas the load_balance is able to detect that the imbalanced is due to CPU affinity, it fails to fix it because the imbalance field is cleared before letting parent level a chance to run. In fact, when the imbalance is detected, the load_balance reruns without the CPU with pinned tasks. But there is no other running tasks in the situation described above and everything looks balanced this time so the imbalance field is immediately cleared. The imbalance field should not be cleared if there is no other task to move when the imbalance is detected. Signed-off-by: Vincent Guittot Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: https://lkml.kernel.org/r/1561996022-28829-1-git-send-email-vincent.guittot@linaro.org Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin --- kernel/sched/fair.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 19d735ab44db..cd2fb8384fbe 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7313,9 +7313,10 @@ more_balance: out_balanced: /* * We reach balance although we may have faced some affinity - * constraints. Clear the imbalance flag if it was set. + * constraints. Clear the imbalance flag only if other tasks got + * a chance to move and fix the imbalance. */ - if (sd_parent) { + if (sd_parent && !(env.flags & LBF_ALL_PINNED)) { int *group_imbalance = &sd_parent->groups->sgc->imbalance; if (*group_imbalance) -- cgit v1.2.3 From 5043f2cf144aa92ce04bcf88d4f7e217439eab72 Mon Sep 17 00:00:00 2001 From: Juri Lelli Date: Fri, 19 Jul 2019 08:34:55 +0200 Subject: sched/core: Fix CPU controller for !RT_GROUP_SCHED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit a07db5c0865799ebed1f88be0df50c581fb65029 ] On !CONFIG_RT_GROUP_SCHED configurations it is currently not possible to move RT tasks between cgroups to which CPU controller has been attached; but it is oddly possible to first move tasks around and then make them RT (setschedule to FIFO/RR). E.g.: # mkdir /sys/fs/cgroup/cpu,cpuacct/group1 # chrt -fp 10 $$ # echo $$ > /sys/fs/cgroup/cpu,cpuacct/group1/tasks bash: echo: write error: Invalid argument # chrt -op 0 $$ # echo $$ > /sys/fs/cgroup/cpu,cpuacct/group1/tasks # chrt -fp 10 $$ # cat /sys/fs/cgroup/cpu,cpuacct/group1/tasks 2345 2598 # chrt -p 2345 pid 2345's current scheduling policy: SCHED_FIFO pid 2345's current scheduling priority: 10 Also, as Michal noted, it is currently not possible to enable CPU controller on unified hierarchy with !CONFIG_RT_GROUP_SCHED (if there are any kernel RT threads in root cgroup, they can't be migrated to the newly created CPU controller's root in cgroup_update_dfl_csses()). Existing code comes with a comment saying the "we don't support RT-tasks being in separate groups". Such comment is however stale and belongs to pre-RT_GROUP_SCHED times. Also, it doesn't make much sense for !RT_GROUP_ SCHED configurations, since checks related to RT bandwidth are not performed at all in these cases. Make moving RT tasks between CPU controller groups viable by removing special case check for RT (and DEADLINE) tasks. Signed-off-by: Juri Lelli Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Michal Koutný Reviewed-by: Daniel Bristot de Oliveira Acked-by: Tejun Heo Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: lizefan@huawei.com Cc: longman@redhat.com Cc: luca.abeni@santannapisa.it Cc: rostedt@goodmis.org Link: https://lkml.kernel.org/r/20190719063455.27328-1-juri.lelli@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin --- kernel/sched/core.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 0e70bfeded7f..d81bcc6362ff 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -8339,10 +8339,6 @@ static int cpu_cgroup_can_attach(struct cgroup_taskset *tset) #ifdef CONFIG_RT_GROUP_SCHED if (!sched_rt_can_attach(css_tg(css), task)) return -EINVAL; -#else - /* We don't support RT-tasks being in separate groups */ - if (task->sched_class != &fair_sched_class) - return -EINVAL; #endif } return 0; -- cgit v1.2.3 From 03b8c7430457993761da4b1f5e54a1a56cf7a4b0 Mon Sep 17 00:00:00 2001 From: Grzegorz Halat Date: Fri, 28 Jun 2019 14:28:13 +0200 Subject: x86/reboot: Always use NMI fallback when shutdown via reboot vector IPI fails [ Upstream commit 747d5a1bf293dcb33af755a6d285d41b8c1ea010 ] A reboot request sends an IPI via the reboot vector and waits for all other CPUs to stop. If one or more CPUs are in critical regions with interrupts disabled then the IPI is not handled on those CPUs and the shutdown hangs if native_stop_other_cpus() is called with the wait argument set. Such a situation can happen when one CPU was stopped within a lock held section and another CPU is trying to acquire that lock with interrupts disabled. There are other scenarios which can cause such a lockup as well. In theory the shutdown should be attempted by an NMI IPI after the timeout period elapsed. Though the wait loop after sending the reboot vector IPI prevents this. It checks the wait request argument and the timeout. If wait is set, which is true for sys_reboot() then it won't fall through to the NMI shutdown method after the timeout period has finished. This was an oversight when the NMI shutdown mechanism was added to handle the 'reboot IPI is not working' situation. The mechanism was added to deal with stuck panic shutdowns, which do not have the wait request set, so the 'wait request' case was probably not considered. Remove the wait check from the post reboot vector IPI wait loop and enforce that the wait loop in the NMI fallback path is invoked even if NMI IPIs are disabled or the registration of the NMI handler fails. That second wait loop will then hang if not all CPUs shutdown and the wait argument is set. [ tglx: Avoid the hard to parse line break in the NMI fallback path, add comments and massage the changelog ] Fixes: 7d007d21e539 ("x86/reboot: Use NMI to assist in shutting down if IRQ fails") Signed-off-by: Grzegorz Halat Signed-off-by: Thomas Gleixner Cc: Don Zickus Link: https://lkml.kernel.org/r/20190628122813.15500-1-ghalat@redhat.com Signed-off-by: Sasha Levin --- arch/x86/kernel/smp.c | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 12c8286206ce..6a0ba9d09b0e 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -176,6 +176,12 @@ asmlinkage __visible void smp_reboot_interrupt(void) irq_exit(); } +static int register_stop_handler(void) +{ + return register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback, + NMI_FLAG_FIRST, "smp_stop"); +} + static void native_stop_other_cpus(int wait) { unsigned long flags; @@ -209,39 +215,41 @@ static void native_stop_other_cpus(int wait) apic->send_IPI_allbutself(REBOOT_VECTOR); /* - * Don't wait longer than a second if the caller - * didn't ask us to wait. + * Don't wait longer than a second for IPI completion. The + * wait request is not checked here because that would + * prevent an NMI shutdown attempt in case that not all + * CPUs reach shutdown state. */ timeout = USEC_PER_SEC; - while (num_online_cpus() > 1 && (wait || timeout--)) + while (num_online_cpus() > 1 && timeout--) udelay(1); } - - /* if the REBOOT_VECTOR didn't work, try with the NMI */ - if ((num_online_cpus() > 1) && (!smp_no_nmi_ipi)) { - if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback, - NMI_FLAG_FIRST, "smp_stop")) - /* Note: we ignore failures here */ - /* Hope the REBOOT_IRQ is good enough */ - goto finish; - - /* sync above data before sending IRQ */ - wmb(); - pr_emerg("Shutting down cpus with NMI\n"); + /* if the REBOOT_VECTOR didn't work, try with the NMI */ + if (num_online_cpus() > 1) { + /* + * If NMI IPI is enabled, try to register the stop handler + * and send the IPI. In any case try to wait for the other + * CPUs to stop. + */ + if (!smp_no_nmi_ipi && !register_stop_handler()) { + /* Sync above data before sending IRQ */ + wmb(); - apic->send_IPI_allbutself(NMI_VECTOR); + pr_emerg("Shutting down cpus with NMI\n"); + apic->send_IPI_allbutself(NMI_VECTOR); + } /* - * Don't wait longer than a 10 ms if the caller - * didn't ask us to wait. + * Don't wait longer than 10 ms if the caller didn't + * reqeust it. If wait is true, the machine hangs here if + * one or more CPUs do not reach shutdown state. */ timeout = USEC_PER_MSEC * 10; while (num_online_cpus() > 1 && (wait || timeout--)) udelay(1); } -finish: local_irq_save(flags); disable_local_APIC(); mcheck_cpu_clear(this_cpu_ptr(&cpu_info)); -- cgit v1.2.3 From 3b6cccf414ac23606aaa68e43392be52493eb279 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 22 Jul 2019 20:47:08 +0200 Subject: x86/apic: Soft disable APIC before initializing it [ Upstream commit 2640da4cccf5cc613bf26f0998b9e340f4b5f69c ] If the APIC was already enabled on entry of setup_local_APIC() then disabling it soft via the SPIV register makes a lot of sense. That masks all LVT entries and brings it into a well defined state. Otherwise previously enabled LVTs which are not touched in the setup function stay unmasked and might surprise the just booting kernel. Signed-off-by: Thomas Gleixner Acked-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/20190722105219.068290579@linutronix.de Signed-off-by: Sasha Levin --- arch/x86/kernel/apic/apic.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 834d1b5b4355..be3d4dcf3a10 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -1265,6 +1265,14 @@ void setup_local_APIC(void) return; } + /* + * If this comes from kexec/kcrash the APIC might be enabled in + * SPIV. Soft disable it before doing further initialization. + */ + value = apic_read(APIC_SPIV); + value &= ~APIC_SPIV_APIC_ENABLED; + apic_write(APIC_SPIV, value); + #ifdef CONFIG_X86_32 /* Pound the ESR really hard over the head with a big hammer - mbligh */ if (lapic_is_integrated() && apic->disable_esr) { -- cgit v1.2.3 From c5f680b2ca2c6708052db733af90bc5a61a59065 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 26 Jul 2019 11:42:34 +0200 Subject: ALSA: hda - Show the fatal CORB/RIRB error more clearly [ Upstream commit dd65f7e19c6961ba6a69f7c925021b7a270cb950 ] The last fallback of CORB/RIRB communication error recovery is to turn on the single command mode, and this last resort usually means that something is really screwed up. Instead of a normal dev_err(), show the error more clearly with dev_WARN() with the caller stack trace. Also, show the bus-reset fallback also as an error, too. Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/pci/hda/hda_controller.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 273364c39171..9cdf86f04e03 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -667,10 +667,13 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr, */ if (hbus->allow_bus_reset && !hbus->response_reset && !hbus->in_reset) { hbus->response_reset = 1; + dev_err(chip->card->dev, + "No response from codec, resetting bus: last cmd=0x%08x\n", + bus->last_cmd[addr]); return -EAGAIN; /* give a chance to retry */ } - dev_err(chip->card->dev, + dev_WARN(chip->card->dev, "azx_get_response timeout, switching to single_cmd mode: last cmd=0x%08x\n", bus->last_cmd[addr]); chip->single_cmd = 1; -- cgit v1.2.3 From 9916480fc2b674b47968bf3b0f5f490b2805548e Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Fri, 26 Jul 2019 10:14:42 +0800 Subject: ALSA: i2c: ak4xxx-adda: Fix a possible null pointer dereference in build_adc_controls() [ Upstream commit 2127c01b7f63b06a21559f56a8c81a3c6535bd1a ] In build_adc_controls(), there is an if statement on line 773 to check whether ak->adc_info is NULL: if (! ak->adc_info || ! ak->adc_info[mixer_ch].switch_name) When ak->adc_info is NULL, it is used on line 792: knew.name = ak->adc_info[mixer_ch].selector_name; Thus, a possible null-pointer dereference may occur. To fix this bug, referring to lines 773 and 774, ak->adc_info and ak->adc_info[mixer_ch].selector_name are checked before being used. This bug is found by a static analysis tool STCheck written by us. Signed-off-by: Jia-Ju Bai Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/i2c/other/ak4xxx-adda.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index bf377dc192aa..d33e02c31712 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -789,11 +789,12 @@ static int build_adc_controls(struct snd_akm4xxx *ak) return err; memset(&knew, 0, sizeof(knew)); - knew.name = ak->adc_info[mixer_ch].selector_name; - if (!knew.name) { + if (!ak->adc_info || + !ak->adc_info[mixer_ch].selector_name) { knew.name = "Capture Channel"; knew.index = mixer_ch + ak->idx_offset * 2; - } + } else + knew.name = ak->adc_info[mixer_ch].selector_name; knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; knew.info = ak4xxx_capture_source_info; -- cgit v1.2.3 From a8d7151b7f3a6bee52ee17e690ca5f1f74684ff3 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 30 Jul 2019 05:50:44 -0300 Subject: media: iguanair: add sanity checks [ Upstream commit ab1cbdf159beba7395a13ab70bc71180929ca064 ] The driver needs to check the endpoint types, too, as opposed to the number of endpoints. This also requires moving the check earlier. Reported-by: syzbot+01a77b82edaa374068e1@syzkaller.appspotmail.com Signed-off-by: Oliver Neukum Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/rc/iguanair.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index ee60e17fba05..cda4ce612dcf 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -430,6 +430,10 @@ static int iguanair_probe(struct usb_interface *intf, int ret, pipein, pipeout; struct usb_host_interface *idesc; + idesc = intf->altsetting; + if (idesc->desc.bNumEndpoints < 2) + return -ENODEV; + ir = kzalloc(sizeof(*ir), GFP_KERNEL); rc = rc_allocate_device(); if (!ir || !rc) { @@ -444,18 +448,13 @@ static int iguanair_probe(struct usb_interface *intf, ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); ir->urb_out = usb_alloc_urb(0, GFP_KERNEL); - if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out) { + if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out || + !usb_endpoint_is_int_in(&idesc->endpoint[0].desc) || + !usb_endpoint_is_int_out(&idesc->endpoint[1].desc)) { ret = -ENOMEM; goto out; } - idesc = intf->altsetting; - - if (idesc->desc.bNumEndpoints < 2) { - ret = -ENODEV; - goto out; - } - ir->rc = rc; ir->dev = &intf->dev; ir->udev = udev; -- cgit v1.2.3 From fe120e1253bc81e0914ad8e7e21aebca3f8ee8c1 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 24 Jul 2019 04:05:12 +0530 Subject: base: soc: Export soc_device_register/unregister APIs [ Upstream commit f7ccc7a397cf2ef64aebb2f726970b93203858d2 ] Qcom Socinfo driver can be built as a module, so export these two APIs. Tested-by: Vinod Koul Signed-off-by: Vinod Koul Signed-off-by: Vaishali Thakkar Reviewed-by: Greg Kroah-Hartman Reviewed-by: Stephen Boyd Reviewed-by: Bjorn Andersson Signed-off-by: Bjorn Andersson Signed-off-by: Sasha Levin --- drivers/base/soc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/base/soc.c b/drivers/base/soc.c index 75b98aad6faf..84242e6b2897 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c @@ -146,6 +146,7 @@ out2: out1: return ERR_PTR(ret); } +EXPORT_SYMBOL_GPL(soc_device_register); /* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */ void soc_device_unregister(struct soc_device *soc_dev) @@ -154,6 +155,7 @@ void soc_device_unregister(struct soc_device *soc_dev) device_unregister(&soc_dev->dev); } +EXPORT_SYMBOL_GPL(soc_device_unregister); static int __init soc_bus_register(void) { -- cgit v1.2.3 From 9812dc6f0db6ba42f4ca4037cd7ff005531694f1 Mon Sep 17 00:00:00 2001 From: Ard van Breemen Date: Fri, 2 Aug 2019 13:52:14 +0200 Subject: ALSA: usb-audio: Skip bSynchAddress endpoint check if it is invalid [ Upstream commit 1b34121d9f26d272b0b2334209af6b6fc82d4bf1 ] The Linux kernel assumes that get_endpoint(alts,0) and get_endpoint(alts,1) are eachothers feedback endpoints. To reassure that validity it will test bsynchaddress to comply with that assumption. But if the bsyncaddress is 0 (invalid), it will flag that as a wrong assumption and return an error. Fix: Skip the test if bSynchAddress is 0. Note: those with a valid bSynchAddress should have a code quirck added. Signed-off-by: Ard van Breemen Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/usb/pcm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 1ea1384bc236..f84c55ecd0fb 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -460,6 +460,7 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, } ep = get_endpoint(alts, 1)->bEndpointAddress; if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && + get_endpoint(alts, 0)->bSynchAddress != 0 && ((is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) { dev_err(&dev->dev, -- cgit v1.2.3 From 41330a743f732efd431b00244479cd83ca747486 Mon Sep 17 00:00:00 2001 From: chenzefeng Date: Tue, 6 Aug 2019 15:46:33 +0800 Subject: ia64:unwind: fix double free for mod->arch.init_unw_table [ Upstream commit c5e5c48c16422521d363c33cfb0dcf58f88c119b ] The function free_module in file kernel/module.c as follow: void free_module(struct module *mod) { ...... module_arch_cleanup(mod); ...... module_arch_freeing_init(mod); ...... } Both module_arch_cleanup and module_arch_freeing_init function would free the mod->arch.init_unw_table, which cause double free. Here, set mod->arch.init_unw_table = NULL after remove the unwind table to avoid double free. Signed-off-by: chenzefeng Signed-off-by: Tony Luck Signed-off-by: Sasha Levin --- arch/ia64/kernel/module.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c index 36b2c94a8eb5..14c7184daaf6 100644 --- a/arch/ia64/kernel/module.c +++ b/arch/ia64/kernel/module.c @@ -912,8 +912,12 @@ module_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mo void module_arch_cleanup (struct module *mod) { - if (mod->arch.init_unw_table) + if (mod->arch.init_unw_table) { unw_remove_unwind_table(mod->arch.init_unw_table); - if (mod->arch.core_unw_table) + mod->arch.init_unw_table = NULL; + } + if (mod->arch.core_unw_table) { unw_remove_unwind_table(mod->arch.core_unw_table); + mod->arch.core_unw_table = NULL; + } } -- cgit v1.2.3 From 6809adb82cea49a131ee6de36c45950b11821dc5 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Wed, 24 Jul 2019 11:09:21 +0200 Subject: md: don't call spare_active in md_reap_sync_thread if all member devices can't work [ Upstream commit 0d8ed0e9bf9643f27f4816dca61081784dedb38d ] When add one disk to array, the md_reap_sync_thread is responsible to activate the spare and set In_sync flag for the new member in spare_active(). But if raid1 has one member disk A, and disk B is added to the array. Then we offline A before all the datas are synchronized from A to B, obviously B doesn't have the latest data as A, but B is still marked with In_sync flag. So let's not call spare_active under the condition, otherwise B is still showed with 'U' state which is not correct. Signed-off-by: Guoqing Jiang Signed-off-by: Song Liu Signed-off-by: Sasha Levin --- drivers/md/md.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 067af77bb729..d1b09657c193 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -8445,7 +8445,8 @@ void md_reap_sync_thread(struct mddev *mddev) /* resync has finished, collect result */ md_unregister_thread(&mddev->sync_thread); if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) && - !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { + !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) && + mddev->degraded != mddev->raid_disks) { /* success...*/ /* activate any spares */ if (mddev->pers->spare_active(mddev)) { -- cgit v1.2.3 From 6b544c54638b36610c5154ebf8243124f10f6aa5 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Wed, 24 Jul 2019 11:09:20 +0200 Subject: md: don't set In_sync if array is frozen [ Upstream commit 062f5b2ae12a153644c765e7ba3b0f825427be1d ] When a disk is added to array, the following path is called in mdadm. Manage_subdevs -> sysfs_freeze_array -> Manage_add -> sysfs_set_str(&info, NULL, "sync_action","idle") Then from kernel side, Manage_add invokes the path (add_new_disk -> validate_super = super_1_validate) to set In_sync flag. Since In_sync means "device is in_sync with rest of array", and the new added disk need to resync thread to help the synchronization of data. And md_reap_sync_thread would call spare_active to set In_sync for the new added disk finally. So don't set In_sync if array is in frozen. Signed-off-by: Guoqing Jiang Signed-off-by: Song Liu Signed-off-by: Sasha Levin --- drivers/md/md.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index d1b09657c193..d59d79b77fd6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1667,8 +1667,15 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev) if (!(le32_to_cpu(sb->feature_map) & MD_FEATURE_RECOVERY_BITMAP)) rdev->saved_raid_disk = -1; - } else - set_bit(In_sync, &rdev->flags); + } else { + /* + * If the array is FROZEN, then the device can't + * be in_sync with rest of array. + */ + if (!test_bit(MD_RECOVERY_FROZEN, + &mddev->recovery)) + set_bit(In_sync, &rdev->flags); + } rdev->raid_disk = role; break; } -- cgit v1.2.3 From f39d3370a3e4c59eb4ae5ea387d6ea623e7a026a Mon Sep 17 00:00:00 2001 From: Xiaofei Tan Date: Fri, 26 Jul 2019 09:43:37 +0800 Subject: efi: cper: print AER info of PCIe fatal error [ Upstream commit b194a77fcc4001dc40aecdd15d249648e8a436d1 ] AER info of PCIe fatal error is not printed in the current driver. Because APEI driver will panic directly for fatal error, and can't run to the place of printing AER info. An example log is as following: {763}[Hardware Error]: Hardware error from APEI Generic Hardware Error Source: 11 {763}[Hardware Error]: event severity: fatal {763}[Hardware Error]: Error 0, type: fatal {763}[Hardware Error]: section_type: PCIe error {763}[Hardware Error]: port_type: 0, PCIe end point {763}[Hardware Error]: version: 4.0 {763}[Hardware Error]: command: 0x0000, status: 0x0010 {763}[Hardware Error]: device_id: 0000:82:00.0 {763}[Hardware Error]: slot: 0 {763}[Hardware Error]: secondary_bus: 0x00 {763}[Hardware Error]: vendor_id: 0x8086, device_id: 0x10fb {763}[Hardware Error]: class_code: 000002 Kernel panic - not syncing: Fatal hardware error! This issue was imported by the patch, '37448adfc7ce ("aerdrv: Move cper_print_aer() call out of interrupt context")'. To fix this issue, this patch adds print of AER info in cper_print_pcie() for fatal error. Here is the example log after this patch applied: {24}[Hardware Error]: Hardware error from APEI Generic Hardware Error Source: 10 {24}[Hardware Error]: event severity: fatal {24}[Hardware Error]: Error 0, type: fatal {24}[Hardware Error]: section_type: PCIe error {24}[Hardware Error]: port_type: 0, PCIe end point {24}[Hardware Error]: version: 4.0 {24}[Hardware Error]: command: 0x0546, status: 0x4010 {24}[Hardware Error]: device_id: 0000:01:00.0 {24}[Hardware Error]: slot: 0 {24}[Hardware Error]: secondary_bus: 0x00 {24}[Hardware Error]: vendor_id: 0x15b3, device_id: 0x1019 {24}[Hardware Error]: class_code: 000002 {24}[Hardware Error]: aer_uncor_status: 0x00040000, aer_uncor_mask: 0x00000000 {24}[Hardware Error]: aer_uncor_severity: 0x00062010 {24}[Hardware Error]: TLP Header: 000000c0 01010000 00000001 00000000 Kernel panic - not syncing: Fatal hardware error! Fixes: 37448adfc7ce ("aerdrv: Move cper_print_aer() call out of interrupt context") Signed-off-by: Xiaofei Tan Reviewed-by: James Morse [ardb: put parens around terms of && operator] Signed-off-by: Ard Biesheuvel Signed-off-by: Sasha Levin --- drivers/firmware/efi/cper.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index d42537425438..f40f7df4b734 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -384,6 +384,21 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, printk( "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", pfx, pcie->bridge.secondary_status, pcie->bridge.control); + + /* Fatal errors call __ghes_panic() before AER handler prints this */ + if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) && + (gdata->error_severity & CPER_SEV_FATAL)) { + struct aer_capability_regs *aer; + + aer = (struct aer_capability_regs *)pcie->aer_info; + printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n", + pfx, aer->uncor_status, aer->uncor_mask); + printk("%saer_uncor_severity: 0x%08x\n", + pfx, aer->uncor_severity); + printk("%sTLP Header: %08x %08x %08x %08x\n", pfx, + aer->header_log.dw0, aer->header_log.dw1, + aer->header_log.dw2, aer->header_log.dw3); + } } static void cper_estatus_print_section( -- cgit v1.2.3 From 3553e7fb0b9ca279c78ffebbf38c2b313f1221f1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 16 Aug 2019 03:38:13 -0300 Subject: media: gspca: zero usb_buf on error [ Upstream commit 4843a543fad3bf8221cf14e5d5f32d15cee89e84 ] If reg_r() fails, then gspca_dev->usb_buf was left uninitialized, and some drivers used the contents of that buffer in logic. This caused several syzbot errors: https://syzkaller.appspot.com/bug?extid=397fd082ce5143e2f67d https://syzkaller.appspot.com/bug?extid=1a35278dd0ebfb3a038a https://syzkaller.appspot.com/bug?extid=06ddf1788cfd048c5e82 I analyzed the gspca drivers and zeroed the buffer where needed. Reported-and-tested-by: syzbot+1a35278dd0ebfb3a038a@syzkaller.appspotmail.com Reported-and-tested-by: syzbot+397fd082ce5143e2f67d@syzkaller.appspotmail.com Reported-and-tested-by: syzbot+06ddf1788cfd048c5e82@syzkaller.appspotmail.com Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/usb/gspca/konica.c | 5 +++++ drivers/media/usb/gspca/nw80x.c | 5 +++++ drivers/media/usb/gspca/ov519.c | 10 ++++++++++ drivers/media/usb/gspca/ov534.c | 5 +++++ drivers/media/usb/gspca/ov534_9.c | 1 + drivers/media/usb/gspca/se401.c | 5 +++++ drivers/media/usb/gspca/sn9c20x.c | 5 +++++ drivers/media/usb/gspca/sonixb.c | 5 +++++ drivers/media/usb/gspca/sonixj.c | 5 +++++ drivers/media/usb/gspca/spca1528.c | 5 +++++ drivers/media/usb/gspca/sq930x.c | 5 +++++ drivers/media/usb/gspca/sunplus.c | 5 +++++ drivers/media/usb/gspca/vc032x.c | 5 +++++ drivers/media/usb/gspca/w996Xcf.c | 5 +++++ 14 files changed, 71 insertions(+) diff --git a/drivers/media/usb/gspca/konica.c b/drivers/media/usb/gspca/konica.c index 0f6d57fbf91b..624b4d24716d 100644 --- a/drivers/media/usb/gspca/konica.c +++ b/drivers/media/usb/gspca/konica.c @@ -127,6 +127,11 @@ static void reg_r(struct gspca_dev *gspca_dev, u16 value, u16 index) if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, 2); } } diff --git a/drivers/media/usb/gspca/nw80x.c b/drivers/media/usb/gspca/nw80x.c index 599f755e75b8..7ebeee98dc1b 100644 --- a/drivers/media/usb/gspca/nw80x.c +++ b/drivers/media/usb/gspca/nw80x.c @@ -1584,6 +1584,11 @@ static void reg_r(struct gspca_dev *gspca_dev, if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); return; } if (len == 1) diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c index c95f32a0c02b..c7aafdbb5738 100644 --- a/drivers/media/usb/gspca/ov519.c +++ b/drivers/media/usb/gspca/ov519.c @@ -2116,6 +2116,11 @@ static int reg_r(struct sd *sd, u16 index) } else { PERR("reg_r %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; + /* + * Make sure the result is zeroed to avoid uninitialized + * values. + */ + gspca_dev->usb_buf[0] = 0; } return ret; @@ -2142,6 +2147,11 @@ static int reg_r8(struct sd *sd, } else { PERR("reg_r8 %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, 8); } return ret; diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index bfff1d1c70ab..466f984312dd 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -644,6 +644,11 @@ static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg) if (ret < 0) { pr_err("read failed %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the result is zeroed to avoid uninitialized + * values. + */ + gspca_dev->usb_buf[0] = 0; } return gspca_dev->usb_buf[0]; } diff --git a/drivers/media/usb/gspca/ov534_9.c b/drivers/media/usb/gspca/ov534_9.c index 47085cf2d723..f2dca0606935 100644 --- a/drivers/media/usb/gspca/ov534_9.c +++ b/drivers/media/usb/gspca/ov534_9.c @@ -1157,6 +1157,7 @@ static u8 reg_r(struct gspca_dev *gspca_dev, u16 reg) if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + return 0; } return gspca_dev->usb_buf[0]; } diff --git a/drivers/media/usb/gspca/se401.c b/drivers/media/usb/gspca/se401.c index 5102cea50471..6adbb0eca71f 100644 --- a/drivers/media/usb/gspca/se401.c +++ b/drivers/media/usb/gspca/se401.c @@ -115,6 +115,11 @@ static void se401_read_req(struct gspca_dev *gspca_dev, u16 req, int silent) pr_err("read req failed req %#04x error %d\n", req, err); gspca_dev->usb_err = err; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, READ_REQ_SIZE); } } diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c index d0ee899584a9..e5bd1e84fd87 100644 --- a/drivers/media/usb/gspca/sn9c20x.c +++ b/drivers/media/usb/gspca/sn9c20x.c @@ -924,6 +924,11 @@ static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length) if (unlikely(result < 0 || result != length)) { pr_err("Read register %02x failed %d\n", reg, result); gspca_dev->usb_err = result; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); } } diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c index 6696b2ec34e9..83e98b85ab6a 100644 --- a/drivers/media/usb/gspca/sonixb.c +++ b/drivers/media/usb/gspca/sonixb.c @@ -466,6 +466,11 @@ static void reg_r(struct gspca_dev *gspca_dev, dev_err(gspca_dev->v4l2_dev.dev, "Error reading register %02x: %d\n", value, res); gspca_dev->usb_err = res; + /* + * Make sure the result is zeroed to avoid uninitialized + * values. + */ + gspca_dev->usb_buf[0] = 0; } } diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c index fd1c8706d86a..67e23557a1a9 100644 --- a/drivers/media/usb/gspca/sonixj.c +++ b/drivers/media/usb/gspca/sonixj.c @@ -1175,6 +1175,11 @@ static void reg_r(struct gspca_dev *gspca_dev, if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); } } diff --git a/drivers/media/usb/gspca/spca1528.c b/drivers/media/usb/gspca/spca1528.c index f38fd8949609..ee93bd443df5 100644 --- a/drivers/media/usb/gspca/spca1528.c +++ b/drivers/media/usb/gspca/spca1528.c @@ -84,6 +84,11 @@ static void reg_r(struct gspca_dev *gspca_dev, if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); } } diff --git a/drivers/media/usb/gspca/sq930x.c b/drivers/media/usb/gspca/sq930x.c index e274cf19a3ea..b236e9dcd468 100644 --- a/drivers/media/usb/gspca/sq930x.c +++ b/drivers/media/usb/gspca/sq930x.c @@ -438,6 +438,11 @@ static void reg_r(struct gspca_dev *gspca_dev, if (ret < 0) { pr_err("reg_r %04x failed %d\n", value, ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); } } diff --git a/drivers/media/usb/gspca/sunplus.c b/drivers/media/usb/gspca/sunplus.c index 46c9f2229a18..cc3e1478c5a0 100644 --- a/drivers/media/usb/gspca/sunplus.c +++ b/drivers/media/usb/gspca/sunplus.c @@ -268,6 +268,11 @@ static void reg_r(struct gspca_dev *gspca_dev, if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); } } diff --git a/drivers/media/usb/gspca/vc032x.c b/drivers/media/usb/gspca/vc032x.c index b4efb2fb36fa..5032b9d7d9bb 100644 --- a/drivers/media/usb/gspca/vc032x.c +++ b/drivers/media/usb/gspca/vc032x.c @@ -2919,6 +2919,11 @@ static void reg_r_i(struct gspca_dev *gspca_dev, if (ret < 0) { pr_err("reg_r err %d\n", ret); gspca_dev->usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(gspca_dev->usb_buf, 0, USB_BUF_SZ); } } static void reg_r(struct gspca_dev *gspca_dev, diff --git a/drivers/media/usb/gspca/w996Xcf.c b/drivers/media/usb/gspca/w996Xcf.c index fb9fe2ef3a6f..a74ac595656f 100644 --- a/drivers/media/usb/gspca/w996Xcf.c +++ b/drivers/media/usb/gspca/w996Xcf.c @@ -139,6 +139,11 @@ static int w9968cf_read_sb(struct sd *sd) } else { pr_err("Read SB reg [01] failed\n"); sd->gspca_dev.usb_err = ret; + /* + * Make sure the buffer is zeroed to avoid uninitialized + * values. + */ + memset(sd->gspca_dev.usb_buf, 0, 2); } udelay(W9968CF_I2C_BUS_DELAY); -- cgit v1.2.3 From 89052e706600df609299bbf6e33297da705e97c8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Aug 2019 18:33:17 +0200 Subject: dmaengine: iop-adma: use correct printk format strings [ Upstream commit 00c9755524fbaa28117be774d7c92fddb5ca02f3 ] When compile-testing on other architectures, we get lots of warnings about incorrect format strings, like: drivers/dma/iop-adma.c: In function 'iop_adma_alloc_slots': drivers/dma/iop-adma.c:307:6: warning: format '%x' expects argument of type 'unsigned int', but argument 6 has type 'dma_addr_t {aka long long unsigned int}' [-Wformat=] drivers/dma/iop-adma.c: In function 'iop_adma_prep_dma_memcpy': >> drivers/dma/iop-adma.c:518:40: warning: format '%u' expects argument of type 'unsigned int', but argument 5 has type 'size_t {aka long unsigned int}' [-Wformat=] Use %zu for printing size_t as required, and cast the dma_addr_t arguments to 'u64' for printing with %llx. Ideally this should use the %pad format string, but that requires an lvalue argument that doesn't work here. Link: https://lore.kernel.org/r/20190809163334.489360-3-arnd@arndb.de Signed-off-by: Arnd Bergmann Acked-by: Vinod Koul Signed-off-by: Arnd Bergmann Signed-off-by: Sasha Levin --- drivers/dma/iop-adma.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index e4f43125e0fb..a390415c97a8 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -126,9 +126,9 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan) list_for_each_entry_safe(iter, _iter, &iop_chan->chain, chain_node) { pr_debug("\tcookie: %d slot: %d busy: %d " - "this_desc: %#x next_desc: %#x ack: %d\n", + "this_desc: %#x next_desc: %#llx ack: %d\n", iter->async_tx.cookie, iter->idx, busy, - iter->async_tx.phys, iop_desc_get_next_desc(iter), + iter->async_tx.phys, (u64)iop_desc_get_next_desc(iter), async_tx_test_ack(&iter->async_tx)); prefetch(_iter); prefetch(&_iter->async_tx); @@ -316,9 +316,9 @@ retry: int i; dev_dbg(iop_chan->device->common.dev, "allocated slot: %d " - "(desc %p phys: %#x) slots_per_op %d\n", + "(desc %p phys: %#llx) slots_per_op %d\n", iter->idx, iter->hw_desc, - iter->async_tx.phys, slots_per_op); + (u64)iter->async_tx.phys, slots_per_op); /* pre-ack all but the last descriptor */ if (num_slots != slots_per_op) @@ -526,7 +526,7 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest, return NULL; BUG_ON(len > IOP_ADMA_MAX_BYTE_COUNT); - dev_dbg(iop_chan->device->common.dev, "%s len: %u\n", + dev_dbg(iop_chan->device->common.dev, "%s len: %zu\n", __func__, len); spin_lock_bh(&iop_chan->lock); @@ -559,7 +559,7 @@ iop_adma_prep_dma_xor(struct dma_chan *chan, dma_addr_t dma_dest, BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT); dev_dbg(iop_chan->device->common.dev, - "%s src_cnt: %d len: %u flags: %lx\n", + "%s src_cnt: %d len: %zu flags: %lx\n", __func__, src_cnt, len, flags); spin_lock_bh(&iop_chan->lock); @@ -592,7 +592,7 @@ iop_adma_prep_dma_xor_val(struct dma_chan *chan, dma_addr_t *dma_src, if (unlikely(!len)) return NULL; - dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %u\n", + dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %zu\n", __func__, src_cnt, len); spin_lock_bh(&iop_chan->lock); @@ -630,7 +630,7 @@ iop_adma_prep_dma_pq(struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src, BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT); dev_dbg(iop_chan->device->common.dev, - "%s src_cnt: %d len: %u flags: %lx\n", + "%s src_cnt: %d len: %zu flags: %lx\n", __func__, src_cnt, len, flags); if (dmaf_p_disabled_continue(flags)) @@ -693,7 +693,7 @@ iop_adma_prep_dma_pq_val(struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src, return NULL; BUG_ON(len > IOP_ADMA_XOR_MAX_BYTE_COUNT); - dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %u\n", + dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %zu\n", __func__, src_cnt, len); spin_lock_bh(&iop_chan->lock); -- cgit v1.2.3 From f39c1742f807389f1932ea2a74d70757b72ffd91 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 7 Aug 2019 11:21:27 -0300 Subject: media: omap3isp: Don't set streaming state on random subdevs [ Upstream commit 7ef57be07ac146e70535747797ef4aee0f06e9f9 ] The streaming state should be set to the first upstream sub-device only, not everywhere, for a sub-device driver itself knows how to best control the streaming state of its own upstream sub-devices. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/platform/omap3isp/isp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 136ea1848701..f41e0d08de93 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -917,6 +917,10 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, s_stream, mode); pipe->do_propagation = true; } + + /* Stop at the first external sub-device. */ + if (subdev->dev != isp->dev) + break; } return 0; @@ -1031,6 +1035,10 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) isp->crashed |= 1U << subdev->entity.id; failure = -ETIMEDOUT; } + + /* Stop at the first external sub-device. */ + if (subdev->dev != isp->dev) + break; } return failure; -- cgit v1.2.3 From 0fc9c24adca9b54156597c69e896810b3a5b9c3d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Aug 2019 16:40:35 +0200 Subject: net: lpc-enet: fix printk format strings [ Upstream commit de6f97b2bace0e2eb6c3a86e124d1e652a587b56 ] compile-testing this driver on other architectures showed multiple warnings: drivers/net/ethernet/nxp/lpc_eth.c: In function 'lpc_eth_drv_probe': drivers/net/ethernet/nxp/lpc_eth.c:1337:19: warning: format '%d' expects argument of type 'int', but argument 4 has type 'resource_size_t {aka long long unsigned int}' [-Wformat=] drivers/net/ethernet/nxp/lpc_eth.c:1342:19: warning: format '%x' expects argument of type 'unsigned int', but argument 4 has type 'dma_addr_t {aka long long unsigned int}' [-Wformat=] Use format strings that work on all architectures. Link: https://lore.kernel.org/r/20190809144043.476786-10-arnd@arndb.de Reported-by: kbuild test robot Signed-off-by: Arnd Bergmann Signed-off-by: Sasha Levin --- drivers/net/ethernet/nxp/lpc_eth.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index 057665180f13..ba14bad81a21 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -1417,13 +1417,14 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) pldat->dma_buff_base_p = dma_handle; netdev_dbg(ndev, "IO address space :%pR\n", res); - netdev_dbg(ndev, "IO address size :%d\n", resource_size(res)); + netdev_dbg(ndev, "IO address size :%zd\n", + (size_t)resource_size(res)); netdev_dbg(ndev, "IO address (mapped) :0x%p\n", pldat->net_base); netdev_dbg(ndev, "IRQ number :%d\n", ndev->irq); - netdev_dbg(ndev, "DMA buffer size :%d\n", pldat->dma_buff_size); - netdev_dbg(ndev, "DMA buffer P address :0x%08x\n", - pldat->dma_buff_base_p); + netdev_dbg(ndev, "DMA buffer size :%zd\n", pldat->dma_buff_size); + netdev_dbg(ndev, "DMA buffer P address :%pad\n", + &pldat->dma_buff_base_p); netdev_dbg(ndev, "DMA buffer V address :0x%p\n", pldat->dma_buff_base_v); @@ -1470,8 +1471,8 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) if (ret) goto err_out_unregister_netdev; - netdev_info(ndev, "LPC mac at 0x%08x irq %d\n", - res->start, ndev->irq); + netdev_info(ndev, "LPC mac at 0x%08lx irq %d\n", + (unsigned long)res->start, ndev->irq); phydev = pldat->phy_dev; -- cgit v1.2.3 From 4678cdb0851cdaee0bda3d9eb975e71613a472e7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 15 Aug 2019 09:40:52 -0300 Subject: media: radio/si470x: kill urb on error [ Upstream commit 0d616f2a3fdbf1304db44d451d9f07008556923b ] In the probe() function radio->int_in_urb was not killed if an error occurred in the probe sequence. It was also missing in the disconnect. This caused this syzbot issue: https://syzkaller.appspot.com/bug?extid=2d4fc2a0c45ad8da7e99 Reported-and-tested-by: syzbot+2d4fc2a0c45ad8da7e99@syzkaller.appspotmail.com Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/radio/si470x/radio-si470x-usb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index 091d793f6583..c9347d5aac04 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -743,7 +743,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, /* start radio */ retval = si470x_start_usb(radio); if (retval < 0) - goto err_all; + goto err_buf; /* set initial frequency */ si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ @@ -758,6 +758,8 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, return 0; err_all: + usb_kill_urb(radio->int_in_urb); +err_buf: kfree(radio->buffer); err_ctrl: v4l2_ctrl_handler_free(&radio->hdl); @@ -831,6 +833,7 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf) mutex_lock(&radio->lock); v4l2_device_disconnect(&radio->v4l2_dev); video_unregister_device(&radio->videodev); + usb_kill_urb(radio->int_in_urb); usb_set_intfdata(intf, NULL); mutex_unlock(&radio->lock); v4l2_device_put(&radio->v4l2_dev); -- cgit v1.2.3 From 11b1a42a99d3ce1d59ab2d7ffa4f52b3e87bf59e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 15 Aug 2019 10:00:33 -0300 Subject: media: hdpvr: add terminating 0 at end of string [ Upstream commit 8b8900b729e4f31f12ac1127bde137c775c327e6 ] dev->usbc_buf was passed as argument for %s, but it was not safeguarded by a terminating 0. This caused this syzbot issue: https://syzkaller.appspot.com/bug?extid=79d18aac4bf1770dd050 Reported-and-tested-by: syzbot+79d18aac4bf1770dd050@syzkaller.appspotmail.com Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/usb/hdpvr/hdpvr-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index 924517b09fc9..7b5c493f02b0 100644 --- a/drivers/media/usb/hdpvr/hdpvr-core.c +++ b/drivers/media/usb/hdpvr/hdpvr-core.c @@ -143,6 +143,7 @@ static int device_authorization(struct hdpvr_device *dev) dev->fw_ver = dev->usbc_buf[1]; + dev->usbc_buf[46] = '\0'; v4l2_info(&dev->v4l2_dev, "firmware version 0x%x dated %s\n", dev->fw_ver, &dev->usbc_buf[2]); -- cgit v1.2.3 From 70e2968f3bf2bce0abf2a2e9a9516652d035a376 Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Sun, 18 Aug 2019 02:40:14 -0300 Subject: media: saa7146: add cleanup in hexium_attach() [ Upstream commit 42e64117d3b4a759013f77bbcf25ab6700e55de7 ] If saa7146_register_device() fails, no cleanup is executed, leading to memory/resource leaks. To fix this issue, perform necessary cleanup work before returning the error. Signed-off-by: Wenwen Wang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/pci/saa7146/hexium_gemini.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index d4b3ce828285..343cd75fcd8d 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -304,6 +304,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER); if (ret < 0) { pr_err("cannot register capture v4l2 device. skipping.\n"); + saa7146_vv_release(dev); + i2c_del_adapter(&hexium->i2c_adapter); + kfree(hexium); return ret; } -- cgit v1.2.3 From a9df2fd8e064ea6426297adf2ac78b5e4a6d2b4b Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Sat, 17 Aug 2019 02:27:46 -0300 Subject: media: cpia2_usb: fix memory leaks [ Upstream commit 1c770f0f52dca1a2323c594f01f5ec6f1dddc97f ] In submit_urbs(), 'cam->sbuf[i].data' is allocated through kmalloc_array(). However, it is not deallocated if the following allocation for urbs fails. To fix this issue, free 'cam->sbuf[i].data' if usb_alloc_urb() fails. Signed-off-by: Wenwen Wang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/usb/cpia2/cpia2_usb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index 41ea00ac3a87..76b9cb940b87 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -665,6 +665,10 @@ static int submit_urbs(struct camera_data *cam) ERR("%s: usb_alloc_urb error!\n", __func__); for (j = 0; j < i; j++) usb_free_urb(cam->sbuf[j].urb); + for (j = 0; j < NUM_SBUF; j++) { + kfree(cam->sbuf[j].data); + cam->sbuf[j].data = NULL; + } return -ENOMEM; } -- cgit v1.2.3 From 9dfd33530c9401ac656a3d3428e977e7cce13b99 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Tue, 20 Aug 2019 19:05:55 -0300 Subject: media: saa7134: fix terminology around saa7134_i2c_eeprom_md7134_gate() [ Upstream commit 9d802222a3405599d6e1984d9324cddf592ea1f4 ] saa7134_i2c_eeprom_md7134_gate() function and the associated comment uses an inverted i2c gate open / closed terminology. Let's fix this. Signed-off-by: Maciej S. Szmigiero Signed-off-by: Hans Verkuil [hverkuil-cisco@xs4all.nl: fix alignment checkpatch warning] Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/pci/saa7134/saa7134-i2c.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c index bc957528f69f..e636fca36e3d 100644 --- a/drivers/media/pci/saa7134/saa7134-i2c.c +++ b/drivers/media/pci/saa7134/saa7134-i2c.c @@ -355,7 +355,11 @@ static struct i2c_client saa7134_client_template = { /* ----------------------------------------------------------- */ -/* On Medion 7134 reading EEPROM needs DVB-T demod i2c gate open */ +/* + * On Medion 7134 reading the SAA7134 chip config EEPROM needs DVB-T + * demod i2c gate closed due to an address clash between this EEPROM + * and the demod one. + */ static void saa7134_i2c_eeprom_md7134_gate(struct saa7134_dev *dev) { u8 subaddr = 0x7, dmdregval; @@ -372,14 +376,14 @@ static void saa7134_i2c_eeprom_md7134_gate(struct saa7134_dev *dev) ret = i2c_transfer(&dev->i2c_adap, i2cgatemsg_r, 2); if ((ret == 2) && (dmdregval & 0x2)) { - pr_debug("%s: DVB-T demod i2c gate was left closed\n", + pr_debug("%s: DVB-T demod i2c gate was left open\n", dev->name); data[0] = subaddr; data[1] = (dmdregval & ~0x2); if (i2c_transfer(&dev->i2c_adap, i2cgatemsg_w, 1) != 1) - pr_err("%s: EEPROM i2c gate open failure\n", - dev->name); + pr_err("%s: EEPROM i2c gate close failure\n", + dev->name); } } -- cgit v1.2.3 From 7ff7d1e7a749843920201489aaed20154eff5a15 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 22 Aug 2019 11:55:07 -0300 Subject: media: ov9650: add a sanity check [ Upstream commit 093347abc7a4e0490e3c962ecbde2dc272a8f708 ] As pointed by cppcheck: [drivers/media/i2c/ov9650.c:706]: (error) Shifting by a negative value is undefined behaviour [drivers/media/i2c/ov9650.c:707]: (error) Shifting by a negative value is undefined behaviour [drivers/media/i2c/ov9650.c:721]: (error) Shifting by a negative value is undefined behaviour Prevent mangling with gains with invalid values. As pointed by Sylvester, this should never happen in practice, as min value of V4L2_CID_GAIN control is 16 (gain is always >= 16 and m is always >= 0), but it is too hard for a static analyzer to get this, as the logic with validates control min/max is elsewhere inside V4L2 core. Reviewed-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/i2c/ov9650.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 1ee6a5527c38..d11de02ecb63 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -707,6 +707,11 @@ static int ov965x_set_gain(struct ov965x *ov965x, int auto_gain) for (m = 6; m >= 0; m--) if (gain >= (1 << m) * 16) break; + + /* Sanity check: don't adjust the gain with a negative value */ + if (m < 0) + return -EINVAL; + rgain = (gain - ((1 << m) * 16)) / (1 << m); rgain |= (((1 << m) - 1) << 4); -- cgit v1.2.3 From 318e486d4ed967187b91957d1683b8e75e2b1ea6 Mon Sep 17 00:00:00 2001 From: Al Stone Date: Tue, 27 Aug 2019 18:21:20 -0600 Subject: ACPI / CPPC: do not require the _PSD method [ Upstream commit 4c4cdc4c63853fee48c02e25c8605fb65a6c9924 ] According to the ACPI 6.3 specification, the _PSD method is optional when using CPPC. The underlying assumption is that each CPU can change frequency independently from all other CPUs; _PSD is provided to tell the OS that some processors can NOT do that. However, the acpi_get_psd() function returns ENODEV if there is no _PSD method present, or an ACPI error status if an error occurs when evaluating _PSD, if present. This makes _PSD mandatory when using CPPC, in violation of the specification, and only on Linux. This has forced some firmware writers to provide a dummy _PSD, even though it is irrelevant, but only because Linux requires it; other OSPMs follow the spec. We really do not want to have OS specific ACPI tables, though. So, correct acpi_get_psd() so that it does not return an error if there is no _PSD method present, but does return a failure when the method can not be executed properly. This allows _PSD to be optional as it should be. Signed-off-by: Al Stone Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- drivers/acpi/cppc_acpi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 0afd1981e350..43c27c04c40a 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -137,8 +137,10 @@ static int acpi_get_psd(struct cpc_desc *cpc_ptr, acpi_handle handle) union acpi_object *psd = NULL; struct acpi_psd_package *pdomain; - status = acpi_evaluate_object_typed(handle, "_PSD", NULL, &buffer, - ACPI_TYPE_PACKAGE); + status = acpi_evaluate_object_typed(handle, "_PSD", NULL, + &buffer, ACPI_TYPE_PACKAGE); + if (status == AE_NOT_FOUND) /* _PSD is optional */ + return 0; if (ACPI_FAILURE(status)) return -ENODEV; -- cgit v1.2.3 From bf3afb03d4d56a1e29ae71bd7d6ce4a62e757cd4 Mon Sep 17 00:00:00 2001 From: Tzvetomir Stoyanov Date: Mon, 5 Aug 2019 16:43:15 -0400 Subject: libtraceevent: Change users plugin directory [ Upstream commit e97fd1383cd77c467d2aed7fa4e596789df83977 ] To be compliant with XDG user directory layout, the user's plugin directory is changed from ~/.traceevent/plugins to ~/.local/lib/traceevent/plugins/ Suggested-by: Patrick McLean Signed-off-by: Tzvetomir Stoyanov Cc: Andrew Morton Cc: Jiri Olsa Cc: Namhyung Kim Cc: Patrick McLean Cc: linux-trace-devel@vger.kernel.org Link: https://lore.kernel.org/linux-trace-devel/20190313144206.41e75cf8@patrickm/ Link: http://lore.kernel.org/linux-trace-devel/20190801074959.22023-4-tz.stoyanov@gmail.com Link: http://lore.kernel.org/lkml/20190805204355.344622683@goodmis.org Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin --- tools/lib/traceevent/Makefile | 6 +++--- tools/lib/traceevent/event-plugin.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 7851df1490e0..cc3315da6dc3 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile @@ -54,15 +54,15 @@ set_plugin_dir := 1 # Set plugin_dir to preffered global plugin location # If we install under $HOME directory we go under -# $(HOME)/.traceevent/plugins +# $(HOME)/.local/lib/traceevent/plugins # # We dont set PLUGIN_DIR in case we install under $HOME # directory, because by default the code looks under: -# $(HOME)/.traceevent/plugins by default. +# $(HOME)/.local/lib/traceevent/plugins by default. # ifeq ($(plugin_dir),) ifeq ($(prefix),$(HOME)) -override plugin_dir = $(HOME)/.traceevent/plugins +override plugin_dir = $(HOME)/.local/lib/traceevent/plugins set_plugin_dir := 0 else override plugin_dir = $(libdir)/traceevent/plugins diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c index a16756ae3526..5fe7889606a2 100644 --- a/tools/lib/traceevent/event-plugin.c +++ b/tools/lib/traceevent/event-plugin.c @@ -30,7 +30,7 @@ #include "event-parse.h" #include "event-utils.h" -#define LOCAL_PLUGIN_DIR ".traceevent/plugins" +#define LOCAL_PLUGIN_DIR ".local/lib/traceevent/plugins/" static struct registered_plugin_options { struct registered_plugin_options *next; -- cgit v1.2.3 From 4bda2b79a9d04c8ba31681c66e95877dbb433416 Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Fri, 16 Aug 2019 00:08:27 -0500 Subject: ACPI: custom_method: fix memory leaks [ Upstream commit 03d1571d9513369c17e6848476763ebbd10ec2cb ] In cm_write(), 'buf' is allocated through kzalloc(). In the following execution, if an error occurs, 'buf' is not deallocated, leading to memory leaks. To fix this issue, free 'buf' before returning the error. Fixes: 526b4af47f44 ("ACPI: Split out custom_method functionality into an own driver") Signed-off-by: Wenwen Wang Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin --- drivers/acpi/custom_method.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c index c68e72414a67..435bd0ffc8c0 100644 --- a/drivers/acpi/custom_method.c +++ b/drivers/acpi/custom_method.c @@ -48,8 +48,10 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, if ((*ppos > max_size) || (*ppos + count > max_size) || (*ppos + count < count) || - (count > uncopied_bytes)) + (count > uncopied_bytes)) { + kfree(buf); return -EINVAL; + } if (copy_from_user(buf + (*ppos), user_buf, count)) { kfree(buf); @@ -69,6 +71,7 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf, add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE); } + kfree(buf); return count; } -- cgit v1.2.3 From a8d1f3f889226bab381d660135328ad5ce9807c7 Mon Sep 17 00:00:00 2001 From: Wang Shenran Date: Wed, 24 Jul 2019 11:01:10 +0300 Subject: hwmon: (acpi_power_meter) Change log level for 'unsafe software power cap' [ Upstream commit 6e4d91aa071810deac2cd052161aefb376ecf04e ] At boot time, the acpi_power_meter driver logs the following error level message: "Ignoring unsafe software power cap". Having read about it from a few sources, it seems that the error message can be quite misleading. While the message can imply that Linux is ignoring the fact that the system is operating in potentially dangerous conditions, the truth is the driver found an ACPI_PMC object that supports software power capping. The driver simply decides not to use it, perhaps because it doesn't support the object. The best solution is probably changing the log level from error to warning. All sources I have found, regarding the error, have downplayed its significance. There is not much of a reason for it to be on error level, while causing potential confusions or misinterpretations. Signed-off-by: Wang Shenran Link: https://lore.kernel.org/r/20190724080110.6952-1-shenran268@gmail.com Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/acpi_power_meter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 579bdf93be43..e27f7e12c05b 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -693,8 +693,8 @@ static int setup_attrs(struct acpi_power_meter_resource *resource) if (resource->caps.flags & POWER_METER_CAN_CAP) { if (!can_cap_in_hardware()) { - dev_err(&resource->acpi_dev->dev, - "Ignoring unsafe software power cap!\n"); + dev_warn(&resource->acpi_dev->dev, + "Ignoring unsafe software power cap!\n"); goto skip_unsafe_cap; } -- cgit v1.2.3 From b8c11e01be7f7fcbda697e8cf9aa1f4ec65816f6 Mon Sep 17 00:00:00 2001 From: Yufen Yu Date: Tue, 3 Sep 2019 21:12:41 +0800 Subject: md/raid1: fail run raid1 array when active disk less than one [ Upstream commit 07f1a6850c5d5a65c917c3165692b5179ac4cb6b ] When run test case: mdadm -CR /dev/md1 -l 1 -n 4 /dev/sd[a-d] --assume-clean --bitmap=internal mdadm -S /dev/md1 mdadm -A /dev/md1 /dev/sd[b-c] --run --force mdadm --zero /dev/sda mdadm /dev/md1 -a /dev/sda echo offline > /sys/block/sdc/device/state echo offline > /sys/block/sdb/device/state sleep 5 mdadm -S /dev/md1 echo running > /sys/block/sdb/device/state echo running > /sys/block/sdc/device/state mdadm -A /dev/md1 /dev/sd[a-c] --run --force mdadm run fail with kernel message as follow: [ 172.986064] md: kicking non-fresh sdb from array! [ 173.004210] md: kicking non-fresh sdc from array! [ 173.022383] md/raid1:md1: active with 0 out of 4 mirrors [ 173.022406] md1: failed to create bitmap (-5) In fact, when active disk in raid1 array less than one, we need to return fail in raid1_run(). Reviewed-by: NeilBrown Signed-off-by: Yufen Yu Signed-off-by: Song Liu Signed-off-by: Sasha Levin --- drivers/md/raid1.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 82e284d2b202..abb99515068b 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -2958,6 +2958,13 @@ static int run(struct mddev *mddev) !test_bit(In_sync, &conf->mirrors[i].rdev->flags) || test_bit(Faulty, &conf->mirrors[i].rdev->flags)) mddev->degraded++; + /* + * RAID1 needs at least one disk in active + */ + if (conf->raid_disks - mddev->degraded < 1) { + ret = -EINVAL; + goto abort; + } if (conf->raid_disks - mddev->degraded == 1) mddev->recovery_cp = MaxSector; @@ -2992,8 +2999,12 @@ static int run(struct mddev *mddev) ret = md_integrity_register(mddev); if (ret) { md_unregister_thread(&mddev->thread); - raid1_free(mddev, conf); + goto abort; } + return 0; + +abort: + raid1_free(mddev, conf); return ret; } -- cgit v1.2.3 From 77a4084872bb4c0456263cce83f48cb2b41044e6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 23 Aug 2019 15:56:14 +0300 Subject: dmaengine: ti: edma: Do not reset reserved paRAM slots [ Upstream commit c5dbe60664b3660f5ac5854e21273ea2e7ff698f ] Skip resetting paRAM slots marked as reserved as they might be used by other cores. Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20190823125618.8133-2-peter.ujfalusi@ti.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/edma.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 85674a8d0436..e508c8c5f3fd 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -2218,9 +2218,6 @@ static int edma_probe(struct platform_device *pdev) ecc->default_queue = info->default_queue; - for (i = 0; i < ecc->num_slots; i++) - edma_write_slot(ecc, i, &dummy_paramset); - if (info->rsv) { /* Set the reserved slots in inuse list */ rsv_slots = info->rsv->rsv_slots; @@ -2233,6 +2230,12 @@ static int edma_probe(struct platform_device *pdev) } } + for (i = 0; i < ecc->num_slots; i++) { + /* Reset only unused - not reserved - paRAM slots */ + if (!test_bit(i, ecc->slot_inuse)) + edma_write_slot(ecc, i, &dummy_paramset); + } + /* Clear the xbar mapped channels in unused list */ xbar_chans = info->xbar_chans; if (xbar_chans) { -- cgit v1.2.3 From c0505afc8a8e0ed7323c94caec9c21cac3358634 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 3 Sep 2019 20:08:21 +0900 Subject: kprobes: Prohibit probing on BUG() and WARN() address [ Upstream commit e336b4027775cb458dc713745e526fa1a1996b2a ] Since BUG() and WARN() may use a trap (e.g. UD2 on x86) to get the address where the BUG() has occurred, kprobes can not do single-step out-of-line that instruction. So prohibit probing on such address. Without this fix, if someone put a kprobe on WARN(), the kernel will crash with invalid opcode error instead of outputing warning message, because kernel can not find correct bug address. Signed-off-by: Masami Hiramatsu Acked-by: Steven Rostedt (VMware) Acked-by: Naveen N. Rao Cc: Anil S Keshavamurthy Cc: David S . Miller Cc: Linus Torvalds Cc: Naveen N . Rao Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Thomas Gleixner Link: https://lkml.kernel.org/r/156750890133.19112.3393666300746167111.stgit@devnote2 Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin --- include/linux/bug.h | 5 +++++ kernel/kprobes.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/linux/bug.h b/include/linux/bug.h index 7f4818673c41..581a53dfbd31 100644 --- a/include/linux/bug.h +++ b/include/linux/bug.h @@ -102,6 +102,11 @@ int is_valid_bugaddr(unsigned long addr); #else /* !CONFIG_GENERIC_BUG */ +static inline void *find_bug(unsigned long bugaddr) +{ + return NULL; +} + static inline enum bug_trap_type report_bug(unsigned long bug_addr, struct pt_regs *regs) { diff --git a/kernel/kprobes.c b/kernel/kprobes.c index a53998cba804..fdde50d39a46 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1454,7 +1454,8 @@ static int check_kprobe_address_safe(struct kprobe *p, /* Ensure it is not in reserved area nor out of text */ if (!kernel_text_address((unsigned long) p->addr) || within_kprobe_blacklist((unsigned long) p->addr) || - jump_label_text_reserved(p->addr, p->addr)) { + jump_label_text_reserved(p->addr, p->addr) || + find_bug((unsigned long)p->addr)) { ret = -EINVAL; goto out; } -- cgit v1.2.3 From e328a6282d42f0924d4d75393d486a2acf48a9f1 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 6 Sep 2019 08:55:24 +0300 Subject: ASoC: dmaengine: Make the pcm->name equal to pcm->id if the name is not set [ Upstream commit 2ec42f3147e1610716f184b02e65d7f493eed925 ] Some tools use the snd_pcm_info_get_name() to try to identify PCMs or for other purposes. Currently it is left empty with the dmaengine-pcm, in this case copy the pcm->id string as pcm->name. For example IGT is using this to find the HDMI PCM for testing audio on it. Signed-off-by: Peter Ujfalusi Reported-by: Arthur She Link: https://lore.kernel.org/r/20190906055524.7393-1-peter.ujfalusi@ti.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/soc-generic-dmaengine-pcm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 6fd1906af387..fe65754c2e50 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -301,6 +301,12 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!dmaengine_pcm_can_report_residue(dev, pcm->chan[i])) pcm->flags |= SND_DMAENGINE_PCM_FLAG_NO_RESIDUE; + + if (rtd->pcm->streams[i].pcm->name[0] == '\0') { + strncpy(rtd->pcm->streams[i].pcm->name, + rtd->pcm->streams[i].pcm->id, + sizeof(rtd->pcm->streams[i].pcm->name)); + } } return 0; -- cgit v1.2.3 From 16b6055dcbc214d63330e760e5cebad9c507df0b Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Tue, 3 Sep 2019 07:51:14 -0400 Subject: mmc: sdhci: Fix incorrect switch to HS mode [ Upstream commit c894e33ddc1910e14d6f2a2016f60ab613fd8b37 ] When switching from any MMC speed mode that requires 1.8v (HS200, HS400 and HS400ES) to High Speed (HS) mode, the system ends up configured for SDR12 with a 50MHz clock which is an illegal mode. This happens because the SDHCI_CTRL_VDD_180 bit in the SDHCI_HOST_CONTROL2 register is left set and when this bit is set, the speed mode is controlled by the SDHCI_CTRL_UHS field in the SDHCI_HOST_CONTROL2 register. The SDHCI_CTRL_UHS field will end up being set to 0 (SDR12) by sdhci_set_uhs_signaling() because there is no UHS mode being set. The fix is to change sdhci_set_uhs_signaling() to set the SDHCI_CTRL_UHS field to SDR25 (which is the same as HS) for any switch to HS mode. This was found on a new eMMC controller that does strict checking of the speed mode and the corresponding clock rate. It caused the switch to HS400 mode to fail because part of the sequence to switch to HS400 requires a switch from HS200 to HS before going to HS400. Suggested-by: Adrian Hunter Signed-off-by: Al Cooper Signed-off-by: Ulf Hansson Signed-off-by: Sasha Levin --- drivers/mmc/host/sdhci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 62d37d2ac557..1d6dfde1104d 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1452,7 +1452,9 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing) ctrl_2 |= SDHCI_CTRL_UHS_SDR104; else if (timing == MMC_TIMING_UHS_SDR12) ctrl_2 |= SDHCI_CTRL_UHS_SDR12; - else if (timing == MMC_TIMING_UHS_SDR25) + else if (timing == MMC_TIMING_SD_HS || + timing == MMC_TIMING_MMC_HS || + timing == MMC_TIMING_UHS_SDR25) ctrl_2 |= SDHCI_CTRL_UHS_SDR25; else if (timing == MMC_TIMING_UHS_SDR50) ctrl_2 |= SDHCI_CTRL_UHS_SDR50; -- cgit v1.2.3 From a580cba06adc7ba60c1b3f34d26f2b681862bfd0 Mon Sep 17 00:00:00 2001 From: Kevin Easton Date: Wed, 10 Jul 2019 13:31:38 +0000 Subject: libertas: Add missing sentinel at end of if_usb.c fw_table [ Upstream commit 764f3f1ecffc434096e0a2b02f1a6cc964a89df6 ] This sentinel tells the firmware loading process when to stop. Reported-and-tested-by: syzbot+98156c174c5a2cad9f8f@syzkaller.appspotmail.com Signed-off-by: Kevin Easton Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin --- drivers/net/wireless/libertas/if_usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index dff08a2896a3..d271eaf1f949 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -49,7 +49,8 @@ static const struct lbs_fw_table fw_table[] = { { MODEL_8388, "libertas/usb8388_v5.bin", NULL }, { MODEL_8388, "libertas/usb8388.bin", NULL }, { MODEL_8388, "usb8388.bin", NULL }, - { MODEL_8682, "libertas/usb8682.bin", NULL } + { MODEL_8682, "libertas/usb8682.bin", NULL }, + { 0, NULL, NULL } }; static struct usb_device_id if_usb_table[] = { -- cgit v1.2.3 From b54d1e51bba72256f977912b6b4197bd1494c72e Mon Sep 17 00:00:00 2001 From: Tomas Bortoli Date: Wed, 31 Jul 2019 12:19:05 -0300 Subject: media: ttusb-dec: Fix info-leak in ttusb_dec_send_command() [ Upstream commit a10feaf8c464c3f9cfdd3a8a7ce17e1c0d498da1 ] The function at issue does not always initialize each byte allocated for 'b' and can therefore leak uninitialized memory to a USB device in the call to usb_bulk_msg() Use kzalloc() instead of kmalloc() Signed-off-by: Tomas Bortoli Reported-by: syzbot+0522702e9d67142379f1@syzkaller.appspotmail.com Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/usb/ttusb-dec/ttusb_dec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index a5de46f04247..f9b5de7ace01 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -272,7 +272,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, dprintk("%s\n", __func__); - b = kmalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL); + b = kzalloc(COMMAND_PACKET_SIZE + 4, GFP_KERNEL); if (!b) return -ENOMEM; -- cgit v1.2.3 From 22404e0663c94d06f3b1fe6d23a86b292cc630ab Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Aug 2019 09:58:07 +0200 Subject: ALSA: hda/realtek - Blacklist PC beep for Lenovo ThinkCentre M73/93 [ Upstream commit 051c78af14fcd74a22b5af45548ad9d588247cc7 ] Lenovo ThinkCentre M73 and M93 don't seem to have a proper beep although the driver tries to probe and set up blindly. Blacklist these machines for suppressing the beep creation. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=204635 Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/pci/hda/patch_realtek.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d5ca16048ce0..55bae9e6de27 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -977,6 +977,9 @@ static const struct snd_pci_quirk beep_white_list[] = { SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1), SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1), SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1), + /* blacklist -- no beep available */ + SND_PCI_QUIRK(0x17aa, 0x309e, "Lenovo ThinkCentre M73", 0), + SND_PCI_QUIRK(0x17aa, 0x30a3, "Lenovo ThinkCentre M93", 0), {} }; -- cgit v1.2.3 From 6454910f3171b4ac428fc160dccb29abeece3d9d Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Tue, 16 Jul 2019 17:00:33 +0800 Subject: btrfs: extent-tree: Make sure we only allocate extents from block groups with the same type [ Upstream commit 2a28468e525f3924efed7f29f2bc5a2926e7e19a ] [BUG] With fuzzed image and MIXED_GROUPS super flag, we can hit the following BUG_ON(): kernel BUG at fs/btrfs/delayed-ref.c:491! invalid opcode: 0000 [#1] PREEMPT SMP NOPTI CPU: 0 PID: 1849 Comm: sync Tainted: G O 5.2.0-custom #27 RIP: 0010:update_existing_head_ref.cold+0x44/0x46 [btrfs] Call Trace: add_delayed_ref_head+0x20c/0x2d0 [btrfs] btrfs_add_delayed_tree_ref+0x1fc/0x490 [btrfs] btrfs_free_tree_block+0x123/0x380 [btrfs] __btrfs_cow_block+0x435/0x500 [btrfs] btrfs_cow_block+0x110/0x240 [btrfs] btrfs_search_slot+0x230/0xa00 [btrfs] ? __lock_acquire+0x105e/0x1e20 btrfs_insert_empty_items+0x67/0xc0 [btrfs] alloc_reserved_file_extent+0x9e/0x340 [btrfs] __btrfs_run_delayed_refs+0x78e/0x1240 [btrfs] ? kvm_clock_read+0x18/0x30 ? __sched_clock_gtod_offset+0x21/0x50 btrfs_run_delayed_refs.part.0+0x4e/0x180 [btrfs] btrfs_run_delayed_refs+0x23/0x30 [btrfs] btrfs_commit_transaction+0x53/0x9f0 [btrfs] btrfs_sync_fs+0x7c/0x1c0 [btrfs] ? __ia32_sys_fdatasync+0x20/0x20 sync_fs_one_sb+0x23/0x30 iterate_supers+0x95/0x100 ksys_sync+0x62/0xb0 __ia32_sys_sync+0xe/0x20 do_syscall_64+0x65/0x240 entry_SYSCALL_64_after_hwframe+0x49/0xbe [CAUSE] This situation is caused by several factors: - Fuzzed image The extent tree of this fs missed one backref for extent tree root. So we can allocated space from that slot. - MIXED_BG feature Super block has MIXED_BG flag. - No mixed block groups exists All block groups are just regular ones. This makes data space_info->block_groups[] contains metadata block groups. And when we reserve space for data, we can use space in metadata block group. Then we hit the following file operations: - fallocate We need to allocate data extents. find_free_extent() choose to use the metadata block to allocate space from, and choose the space of extent tree root, since its backref is missing. This generate one delayed ref head with is_data = 1. - extent tree update We need to update extent tree at run_delayed_ref time. This generate one delayed ref head with is_data = 0, for the same bytenr of old extent tree root. Then we trigger the BUG_ON(). [FIX] The quick fix here is to check block_group->flags before using it. The problem can only happen for MIXED_GROUPS fs. Regular filesystems won't have space_info with DATA|METADATA flag, and no way to hit the bug. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=203255 Reported-by: Jungyeon Yoon Signed-off-by: Qu Wenruo Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/extent-tree.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index df2bb4b61a00..4c316ca3ee78 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -7168,6 +7168,14 @@ search: */ if ((flags & extra) && !(block_group->flags & extra)) goto loop; + + /* + * This block group has different flags than we want. + * It's possible that we have MIXED_GROUP flag but no + * block group is mixed. Just skip such block group. + */ + btrfs_release_block_group(block_group, delalloc); + continue; } have_block_group: -- cgit v1.2.3 From e875c35b74ac5b5e89ca6933bdd5d8a5e6d5fbf0 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 7 Aug 2019 11:19:00 -0300 Subject: media: omap3isp: Set device on omap3isp subdevs [ Upstream commit e9eb103f027725053a4b02f93d7f2858b56747ce ] The omap3isp driver registered subdevs without the dev field being set. Do that now. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/platform/omap3isp/ispccdc.c | 1 + drivers/media/platform/omap3isp/ispccp2.c | 1 + drivers/media/platform/omap3isp/ispcsi2.c | 1 + drivers/media/platform/omap3isp/isppreview.c | 1 + drivers/media/platform/omap3isp/ispresizer.c | 1 + drivers/media/platform/omap3isp/ispstat.c | 2 ++ 6 files changed, 7 insertions(+) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index a6a61cce43dd..e349f5d990b7 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -2603,6 +2603,7 @@ int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, int ret; /* Register the subdev and video node. */ + ccdc->subdev.dev = vdev->mdev->dev; ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); if (ret < 0) goto error; diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index 38e6a974c5b1..e6b19b785c2f 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -1025,6 +1025,7 @@ int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, int ret; /* Register the subdev and video nodes. */ + ccp2->subdev.dev = vdev->mdev->dev; ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); if (ret < 0) goto error; diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index a78338d012b4..029b434b7609 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -1201,6 +1201,7 @@ int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, int ret; /* Register the subdev and video nodes. */ + csi2->subdev.dev = vdev->mdev->dev; ret = v4l2_device_register_subdev(vdev, &csi2->subdev); if (ret < 0) goto error; diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index 13803270d104..c9e8845de1b1 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -2223,6 +2223,7 @@ int omap3isp_preview_register_entities(struct isp_prev_device *prev, int ret; /* Register the subdev and video nodes. */ + prev->subdev.dev = vdev->mdev->dev; ret = v4l2_device_register_subdev(vdev, &prev->subdev); if (ret < 0) goto error; diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 7cfb43dc0ffd..d4e53cbe9193 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -1679,6 +1679,7 @@ int omap3isp_resizer_register_entities(struct isp_res_device *res, int ret; /* Register the subdev and video nodes. */ + res->subdev.dev = vdev->mdev->dev; ret = v4l2_device_register_subdev(vdev, &res->subdev); if (ret < 0) goto error; diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index 94d4c295d3d0..c54c5c494b75 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -1010,6 +1010,8 @@ void omap3isp_stat_unregister_entities(struct ispstat *stat) int omap3isp_stat_register_entities(struct ispstat *stat, struct v4l2_device *vdev) { + stat->subdev.dev = vdev->mdev->dev; + return v4l2_device_register_subdev(vdev, &stat->subdev); } -- cgit v1.2.3 From 02842b98ab1ea2f00c3f0a0c5eeb0776ee4bed0d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 10 Sep 2019 22:51:51 +0900 Subject: ALSA: firewire-tascam: handle error code when getting current source of clock commit 2617120f4de6d0423384e0e86b14c78b9de84d5a upstream. The return value of snd_tscm_stream_get_clock() is ignored. This commit checks the value and handle error. Fixes: e453df44f0d6 ("ALSA: firewire-tascam: add PCM functionality") Cc: # v4.4+ Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20190910135152.29800-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/firewire/tascam/tascam-pcm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/firewire/tascam/tascam-pcm.c b/sound/firewire/tascam/tascam-pcm.c index 380d3db969a5..64edb44d74f6 100644 --- a/sound/firewire/tascam/tascam-pcm.c +++ b/sound/firewire/tascam/tascam-pcm.c @@ -81,6 +81,9 @@ static int pcm_open(struct snd_pcm_substream *substream) goto err_locked; err = snd_tscm_stream_get_clock(tscm, &clock); + if (err < 0) + goto err_locked; + if (clock != SND_TSCM_CLOCK_INTERNAL || amdtp_stream_pcm_running(&tscm->rx_stream) || amdtp_stream_pcm_running(&tscm->tx_stream)) { -- cgit v1.2.3 From 82a136986dbc112af10666ce530624808a6b9b67 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 10 Sep 2019 22:51:52 +0900 Subject: ALSA: firewire-tascam: check intermediate state of clock status and retry commit e1a00b5b253a4f97216b9a33199a863987075162 upstream. 2 bytes in MSB of register for clock status is zero during intermediate state after changing status of sampling clock in models of TASCAM FireWire series. The duration of this state differs depending on cases. During the state, it's better to retry reading the register for current status of the clock. In current implementation, the intermediate state is checked only when getting current sampling transmission frequency, then retry reading. This care is required for the other operations to read the register. This commit moves the codes of check and retry into helper function commonly used for operations to read the register. Fixes: e453df44f0d6 ("ALSA: firewire-tascam: add PCM functionality") Cc: # v4.4+ Signed-off-by: Takashi Sakamoto Link: https://lore.kernel.org/r/20190910135152.29800-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/firewire/tascam/tascam-stream.c | 42 +++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/sound/firewire/tascam/tascam-stream.c b/sound/firewire/tascam/tascam-stream.c index e4c306398b35..d8a9e313eae6 100644 --- a/sound/firewire/tascam/tascam-stream.c +++ b/sound/firewire/tascam/tascam-stream.c @@ -9,20 +9,37 @@ #include #include "tascam.h" +#define CLOCK_STATUS_MASK 0xffff0000 +#define CLOCK_CONFIG_MASK 0x0000ffff + #define CALLBACK_TIMEOUT 500 static int get_clock(struct snd_tscm *tscm, u32 *data) { + int trial = 0; __be32 reg; int err; - err = snd_fw_transaction(tscm->unit, TCODE_READ_QUADLET_REQUEST, - TSCM_ADDR_BASE + TSCM_OFFSET_CLOCK_STATUS, - ®, sizeof(reg), 0); - if (err >= 0) + while (trial++ < 5) { + err = snd_fw_transaction(tscm->unit, TCODE_READ_QUADLET_REQUEST, + TSCM_ADDR_BASE + TSCM_OFFSET_CLOCK_STATUS, + ®, sizeof(reg), 0); + if (err < 0) + return err; + *data = be32_to_cpu(reg); + if (*data & CLOCK_STATUS_MASK) + break; - return err; + // In intermediate state after changing clock status. + msleep(50); + } + + // Still in the intermediate state. + if (trial >= 5) + return -EAGAIN; + + return 0; } static int set_clock(struct snd_tscm *tscm, unsigned int rate, @@ -35,7 +52,7 @@ static int set_clock(struct snd_tscm *tscm, unsigned int rate, err = get_clock(tscm, &data); if (err < 0) return err; - data &= 0x0000ffff; + data &= CLOCK_CONFIG_MASK; if (rate > 0) { data &= 0x000000ff; @@ -80,17 +97,14 @@ static int set_clock(struct snd_tscm *tscm, unsigned int rate, int snd_tscm_stream_get_rate(struct snd_tscm *tscm, unsigned int *rate) { - u32 data = 0x0; - unsigned int trials = 0; + u32 data; int err; - while (data == 0x0 || trials++ < 5) { - err = get_clock(tscm, &data); - if (err < 0) - return err; + err = get_clock(tscm, &data); + if (err < 0) + return err; - data = (data & 0xff000000) >> 24; - } + data = (data & 0xff000000) >> 24; /* Check base rate. */ if ((data & 0x0f) == 0x01) -- cgit v1.2.3 From 291697f621a082ebd1a26ee5e8bfde62dc05890f Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Thu, 11 Jul 2019 16:29:37 +0200 Subject: printk: Do not lose last line in kmsg buffer dump [ Upstream commit b46eff55ad5bd98e746c0a7022fe7ee071de5fee ] kmsg_dump_get_buffer() is supposed to select all the youngest log messages which fit into the provided buffer. It determines the correct start index by using msg_print_text() with a NULL buffer to calculate the size of each entry. However, when performing the actual writes, msg_print_text() only writes the entry to the buffer if the written len is lesser than the size of the buffer. So if the lengths of the selected youngest log messages happen to precisely fill up the provided buffer, the last log message is not included. We don't want to modify msg_print_text() to fill up the buffer and start returning a length which is equal to the size of the buffer, since callers of its other users, such as kmsg_dump_get_line(), depend upon the current behaviour. Instead, fix kmsg_dump_get_buffer() to compensate for this. For example, with the following two final prints: [ 6.427502] AAAAAAAAAAAAA [ 6.427769] BBBBBBBB12345 A dump of a 64-byte buffer filled by kmsg_dump_get_buffer(), before this patch: 00000000: 3c 30 3e 5b 20 20 20 20 36 2e 35 32 32 31 39 37 <0>[ 6.522197 00000010: 5d 20 41 41 41 41 41 41 41 41 41 41 41 41 41 0a ] AAAAAAAAAAAAA. 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ After this patch: 00000000: 3c 30 3e 5b 20 20 20 20 36 2e 34 35 36 36 37 38 <0>[ 6.456678 00000010: 5d 20 42 42 42 42 42 42 42 42 31 32 33 34 35 0a ] BBBBBBBB12345. 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ Link: http://lkml.kernel.org/r/20190711142937.4083-1-vincent.whitchurch@axis.com Fixes: e2ae715d66bf4bec ("kmsg - kmsg_dump() use iterator to receive log buffer content") To: rostedt@goodmis.org Cc: linux-kernel@vger.kernel.org Cc: # v3.5+ Signed-off-by: Vincent Whitchurch Reviewed-by: Sergey Senozhatsky Signed-off-by: Petr Mladek Signed-off-by: Sasha Levin --- kernel/printk/printk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index dd689ab22806..5a1b2a914b4e 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -3048,7 +3048,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, seq = dumper->cur_seq; idx = dumper->cur_idx; prev = 0; - while (l > size && seq < dumper->next_seq) { + while (l >= size && seq < dumper->next_seq) { struct printk_log *msg = log_from_idx(idx); l -= msg_print_text(msg, prev, true, NULL, 0); -- cgit v1.2.3 From d9768d068b4ee98932eb24205f39c60397d57571 Mon Sep 17 00:00:00 2001 From: Vasily Averin Date: Fri, 13 Sep 2019 18:17:11 +0300 Subject: fuse: fix missing unlock_page in fuse_writepage() commit d5880c7a8620290a6c90ced7a0e8bd0ad9419601 upstream. unlock_page() was missing in case of an already in-flight write against the same page. Signed-off-by: Vasily Averin Fixes: ff17be086477 ("fuse: writepage: skip already in flight") Cc: # v3.13 Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/fuse/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index ab93c4591f8c..e0ec8b80c873 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1706,6 +1706,7 @@ static int fuse_writepage(struct page *page, struct writeback_control *wbc) WARN_ON(wbc->sync_mode == WB_SYNC_ALL); redirty_page_for_writepage(wbc, page); + unlock_page(page); return 0; } -- cgit v1.2.3 From f5c0d4a616cfb199d8a8b9adac0366886d0f2dd0 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 5 Sep 2019 16:44:17 +0200 Subject: parisc: Disable HP HSC-PCI Cards to prevent kernel crash commit 5fa1659105fac63e0f3c199b476025c2e04111ce upstream. The HP Dino PCI controller chip can be used in two variants: as on-board controller (e.g. in B160L), or on an Add-On card ("Card-Mode") to bridge PCI components to systems without a PCI bus, e.g. to a HSC/GSC bus. One such Add-On card is the HP HSC-PCI Card which has one or more DEC Tulip PCI NIC chips connected to the on-card Dino PCI controller. Dino in Card-Mode has a big disadvantage: All PCI memory accesses need to go through the DINO_MEM_DATA register, so Linux drivers will not be able to use the ioremap() function. Without ioremap() many drivers will not work, one example is the tulip driver which then simply crashes the kernel if it tries to access the ports on the HP HSC card. This patch disables the HP HSC card if it finds one, and as such fixes the kernel crash on a HP D350/2 machine. Signed-off-by: Helge Deller Noticed-by: Phil Scarr Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/parisc/dino.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 005ea632ba53..8524faf28acb 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -160,6 +160,15 @@ struct dino_device (struct dino_device *)__pdata; }) +/* Check if PCI device is behind a Card-mode Dino. */ +static int pci_dev_is_behind_card_dino(struct pci_dev *dev) +{ + struct dino_device *dino_dev; + + dino_dev = DINO_DEV(parisc_walk_tree(dev->bus->bridge)); + return is_card_dino(&dino_dev->hba.dev->id); +} + /* * Dino Configuration Space Accessor Functions */ @@ -442,6 +451,21 @@ static void quirk_cirrus_cardbus(struct pci_dev *dev) } DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832, quirk_cirrus_cardbus ); +#ifdef CONFIG_TULIP +static void pci_fixup_tulip(struct pci_dev *dev) +{ + if (!pci_dev_is_behind_card_dino(dev)) + return; + if (!(pci_resource_flags(dev, 1) & IORESOURCE_MEM)) + return; + pr_warn("%s: HP HSC-PCI Cards with card-mode Dino not yet supported.\n", + pci_name(dev)); + /* Disable this card by zeroing the PCI resources */ + memset(&dev->resource[0], 0, sizeof(dev->resource[0])); + memset(&dev->resource[1], 0, sizeof(dev->resource[1])); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_DEC, PCI_ANY_ID, pci_fixup_tulip); +#endif /* CONFIG_TULIP */ static void __init dino_bios_init(void) -- cgit v1.2.3 From 5de105cc60f8d3b58661d9084f9a409bb720c0c0 Mon Sep 17 00:00:00 2001 From: Jan Dakinevich Date: Tue, 27 Aug 2019 13:07:09 +0000 Subject: KVM: x86: always stop emulation on page fault commit 8530a79c5a9f4e29e6ffb35ec1a79d81f4968ec8 upstream. inject_emulated_exception() returns true if and only if nested page fault happens. However, page fault can come from guest page tables walk, either nested or not nested. In both cases we should stop an attempt to read under RIP and give guest to step over its own page fault handler. This is also visible when an emulated instruction causes a #GP fault and the VMware backdoor is enabled. To handle the VMware backdoor, KVM intercepts #GP faults; with only the next patch applied, x86_emulate_instruction() injects a #GP but returns EMULATE_FAIL instead of EMULATE_DONE. EMULATE_FAIL causes handle_exception_nmi() (or gp_interception() for SVM) to re-inject the original #GP because it thinks emulation failed due to a non-VMware opcode. This patch prevents the issue as x86_emulate_instruction() will return EMULATE_DONE after injecting the #GP. Fixes: 6ea6e84309ca ("KVM: x86: inject exceptions produced by x86_decode_insn") Cc: stable@vger.kernel.org Cc: Denis Lunev Cc: Roman Kagan Cc: Denis Plotnikov Signed-off-by: Jan Dakinevich Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/x86.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 74674a6e4827..393d9846a04f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5486,8 +5486,10 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, if (reexecute_instruction(vcpu, cr2, write_fault_to_spt, emulation_type)) return EMULATE_DONE; - if (ctxt->have_exception && inject_emulated_exception(vcpu)) + if (ctxt->have_exception) { + inject_emulated_exception(vcpu); return EMULATE_DONE; + } if (emulation_type & EMULTYPE_SKIP) return EMULATE_FAIL; return handle_emulation_failure(vcpu); -- cgit v1.2.3 From bcb66cfc3fcf5a879b93eb6e6b5a60487d80b63d Mon Sep 17 00:00:00 2001 From: Jan Dakinevich Date: Tue, 27 Aug 2019 13:07:08 +0000 Subject: KVM: x86: set ctxt->have_exception in x86_decode_insn() commit c8848cee74ff05638e913582a476bde879c968ad upstream. x86_emulate_instruction() takes into account ctxt->have_exception flag during instruction decoding, but in practice this flag is never set in x86_decode_insn(). Fixes: 6ea6e84309ca ("KVM: x86: inject exceptions produced by x86_decode_insn") Cc: stable@vger.kernel.org Cc: Denis Lunev Cc: Roman Kagan Cc: Denis Plotnikov Signed-off-by: Jan Dakinevich Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/emulate.c | 2 ++ arch/x86/kvm/x86.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 5dd56e3517f3..6c7847b3aa2d 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -5245,6 +5245,8 @@ done_prefixes: ctxt->memopp->addr.mem.ea + ctxt->_eip); done: + if (rc == X86EMUL_PROPAGATE_FAULT) + ctxt->have_exception = true; return (rc != X86EMUL_CONTINUE) ? EMULATION_FAILED : EMULATION_OK; } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 393d9846a04f..441b8b70277f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5487,6 +5487,12 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, emulation_type)) return EMULATE_DONE; if (ctxt->have_exception) { + /* + * #UD should result in just EMULATION_FAILED, and trap-like + * exception should not be encountered during decode. + */ + WARN_ON_ONCE(ctxt->exception.vector == UD_VECTOR || + exception_type(ctxt->exception.vector) == EXCPT_TRAP); inject_emulated_exception(vcpu); return EMULATE_DONE; } -- cgit v1.2.3 From 10ec9d66ff15d6888e47efaf09602b2da7a7606e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 3 Sep 2019 16:36:45 -0700 Subject: KVM: x86: Manually calculate reserved bits when loading PDPTRS commit 16cfacc8085782dab8e365979356ce1ca87fd6cc upstream. Manually generate the PDPTR reserved bit mask when explicitly loading PDPTRs. The reserved bits that are being tracked by the MMU reflect the current paging mode, which is unlikely to be PAE paging in the vast majority of flows that use load_pdptrs(), e.g. CR0 and CR4 emulation, __set_sregs(), etc... This can cause KVM to incorrectly signal a bad PDPTR, or more likely, miss a reserved bit check and subsequently fail a VM-Enter due to a bad VMCS.GUEST_PDPTR. Add a one off helper to generate the reserved bits instead of sharing code across the MMU's calculations and the PDPTR emulation. The PDPTR reserved bits are basically set in stone, and pushing a helper into the MMU's calculation adds unnecessary complexity without improving readability. Oppurtunistically fix/update the comment for load_pdptrs(). Note, the buggy commit also introduced a deliberate functional change, "Also remove bit 5-6 from rsvd_bits_mask per latest SDM.", which was effectively (and correctly) reverted by commit cd9ae5fe47df ("KVM: x86: Fix page-tables reserved bits"). A bit of SDM archaeology shows that the SDM from late 2008 had a bug (likely a copy+paste error) where it listed bits 6:5 as AVL and A for PDPTEs used for 4k entries but reserved for 2mb entries. I.e. the SDM contradicted itself, and bits 6:5 are and always have been reserved. Fixes: 20c466b56168d ("KVM: Use rsvd_bits_mask in load_pdptrs()") Cc: stable@vger.kernel.org Cc: Nadav Amit Reported-by: Doug Reiland Signed-off-by: Sean Christopherson Reviewed-by: Peter Xu Signed-off-by: Paolo Bonzini Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/x86.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 441b8b70277f..2b47fd3d4b8c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -523,8 +523,14 @@ static int kvm_read_nested_guest_page(struct kvm_vcpu *vcpu, gfn_t gfn, data, offset, len, access); } +static inline u64 pdptr_rsvd_bits(struct kvm_vcpu *vcpu) +{ + return rsvd_bits(cpuid_maxphyaddr(vcpu), 63) | rsvd_bits(5, 8) | + rsvd_bits(1, 2); +} + /* - * Load the pae pdptrs. Return true is they are all valid. + * Load the pae pdptrs. Return 1 if they are all valid, 0 otherwise. */ int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3) { @@ -543,8 +549,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3) } for (i = 0; i < ARRAY_SIZE(pdpte); ++i) { if (is_present_gpte(pdpte[i]) && - (pdpte[i] & - vcpu->arch.mmu.guest_rsvd_check.rsvd_bits_mask[0][2])) { + (pdpte[i] & pdptr_rsvd_bits(vcpu))) { ret = 0; goto out; } -- cgit v1.2.3 From 16740be2f6b55e6c1c51bd28268d7980fd66ec8f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 18 Aug 2019 12:03:23 -0300 Subject: media: sn9c20x: Add MSI MS-1039 laptop to flip_dmi_table commit 7e0bb5828311f811309bed5749528ca04992af2f upstream. Like a bunch of other MSI laptops the MS-1039 uses a 0c45:627b SN9C201 + OV7660 webcam which is mounted upside down. Add it to the sn9c20x flip_dmi_table to deal with this. Cc: stable@vger.kernel.org Reported-by: Rui Salvaterra Signed-off-by: Hans de Goede Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/gspca/sn9c20x.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c index e5bd1e84fd87..6136eb683306 100644 --- a/drivers/media/usb/gspca/sn9c20x.c +++ b/drivers/media/usb/gspca/sn9c20x.c @@ -138,6 +138,13 @@ static const struct dmi_system_id flip_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "0341") } }, + { + .ident = "MSI MS-1039", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "MS-1039"), + } + }, { .ident = "MSI MS-1632", .matches = { -- cgit v1.2.3 From 789536b7f01446d952d054d412065674024e3024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amadeusz=20S=C5=82awi=C5=84ski?= Date: Tue, 27 Aug 2019 16:17:08 +0200 Subject: ASoC: Intel: Fix use of potentially uninitialized variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 810f3b860850148788fc1ed8a6f5f807199fed65 upstream. If ipc->ops.reply_msg_match is NULL, we may end up using uninitialized mask value. reported by smatch: sound/soc/intel/common/sst-ipc.c:266 sst_ipc_reply_find_msg() error: uninitialized symbol 'mask'. Signed-off-by: Amadeusz Sławiński Link: https://lore.kernel.org/r/20190827141712.21015-3-amadeuszx.slawinski@linux.intel.com Reviewed-by: Pierre-Louis Bossart Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/intel/common/sst-ipc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index a12c7bb08d3b..b96bf44be2d5 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c @@ -211,6 +211,8 @@ struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, if (ipc->ops.reply_msg_match != NULL) header = ipc->ops.reply_msg_match(header, &mask); + else + mask = (u64)-1; if (list_empty(&ipc->rx_list)) { dev_err(ipc->dev, "error: rx list empty but received 0x%llx\n", -- cgit v1.2.3 From 8b49a407ce256d147861562e19f71a759e97b140 Mon Sep 17 00:00:00 2001 From: Luis Araneda Date: Thu, 8 Aug 2019 08:52:43 -0400 Subject: ARM: zynq: Use memcpy_toio instead of memcpy on smp bring-up commit b7005d4ef4f3aa2dc24019ffba03a322557ac43d upstream. This fixes a kernel panic on memcpy when FORTIFY_SOURCE is enabled. The initial smp implementation on commit aa7eb2bb4e4a ("arm: zynq: Add smp support") used memcpy, which worked fine until commit ee333554fed5 ("ARM: 8749/1: Kconfig: Add ARCH_HAS_FORTIFY_SOURCE") enabled overflow checks at runtime, producing a read overflow panic. The computed size of memcpy args are: - p_size (dst): 4294967295 = (size_t) -1 - q_size (src): 1 - size (len): 8 Additionally, the memory is marked as __iomem, so one of the memcpy_* functions should be used for read/write. Fixes: aa7eb2bb4e4a ("arm: zynq: Add smp support") Signed-off-by: Luis Araneda Cc: stable@vger.kernel.org Signed-off-by: Michal Simek Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-zynq/platsmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-zynq/platsmp.c b/arch/arm/mach-zynq/platsmp.c index f66816c49186..dabe33ac988e 100644 --- a/arch/arm/mach-zynq/platsmp.c +++ b/arch/arm/mach-zynq/platsmp.c @@ -65,7 +65,7 @@ int zynq_cpun_start(u32 address, int cpu) * 0x4: Jump by mov instruction * 0x8: Jumping address */ - memcpy((__force void *)zero, &zynq_secondary_trampoline, + memcpy_toio(zero, &zynq_secondary_trampoline, trampoline_size); writel(address, zero + trampoline_size); -- cgit v1.2.3 From c22df8ea7c5831d6fdca2f6f136f0d32d7064ff9 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Tue, 3 Sep 2019 14:18:02 -0300 Subject: alarmtimer: Use EOPNOTSUPP instead of ENOTSUPP commit f18ddc13af981ce3c7b7f26925f099e7c6929aba upstream. ENOTSUPP is not supposed to be returned to userspace. This was found on an OpenPower machine, where the RTC does not support set_alarm. On that system, a clock_nanosleep(CLOCK_REALTIME_ALARM, ...) results in "524 Unknown error 524" Replace it with EOPNOTSUPP which results in the expected "95 Operation not supported" error. Fixes: 1c6b39ad3f01 (alarmtimers: Return -ENOTSUPP if no RTC device is present) Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Thomas Gleixner Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20190903171802.28314-1-cascardo@canonical.com Signed-off-by: Greg Kroah-Hartman --- kernel/time/alarmtimer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index e78480b81f8d..70aef327b6e8 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -530,7 +530,7 @@ static int alarm_timer_create(struct k_itimer *new_timer) struct alarm_base *base; if (!alarmtimer_get_rtcdev()) - return -ENOTSUPP; + return -EOPNOTSUPP; if (!capable(CAP_WAKE_ALARM)) return -EPERM; @@ -759,7 +759,7 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags, struct restart_block *restart; if (!alarmtimer_get_rtcdev()) - return -ENOTSUPP; + return -EOPNOTSUPP; if (flags & ~TIMER_ABSTIME) return -EINVAL; -- cgit v1.2.3 From c7925cc21fb29dc5edfb00f61c82cfb8a6db52d2 Mon Sep 17 00:00:00 2001 From: Xiao Ni Date: Mon, 8 Jul 2019 10:14:32 +0800 Subject: md/raid6: Set R5_ReadError when there is read failure on parity disk commit 143f6e733b73051cd22dcb80951c6c929da413ce upstream. 7471fb77ce4d ("md/raid6: Fix anomily when recovering a single device in RAID6.") avoids rereading P when it can be computed from other members. However, this misses the chance to re-write the right data to P. This patch sets R5_ReadError if the re-read fails. Also, when re-read is skipped, we also missed the chance to reset rdev->read_errors to 0. It can fail the disk when there are many read errors on P member disk (other disks don't have read error) V2: upper layer read request don't read parity/Q data. So there is no need to consider such situation. This is Reported-by: kbuild test robot Fixes: 7471fb77ce4d ("md/raid6: Fix anomily when recovering a single device in RAID6.") Cc: #4.4+ Signed-off-by: Xiao Ni Signed-off-by: Song Liu Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid5.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 764e0e155ae2..f061c81e15e1 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2394,7 +2394,9 @@ static void raid5_end_read_request(struct bio * bi) && !test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) retry = 1; if (retry) - if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) { + if (sh->qd_idx >= 0 && sh->pd_idx == i) + set_bit(R5_ReadError, &sh->dev[i].flags); + else if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) { set_bit(R5_ReadError, &sh->dev[i].flags); clear_bit(R5_ReadNoMerge, &sh->dev[i].flags); } else -- cgit v1.2.3 From b85938f66b6ef4680a06e3229c10f5d6353f53d9 Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Wed, 28 Aug 2019 16:11:10 -0500 Subject: cfg80211: Purge frame registrations on iftype change commit c1d3ad84eae35414b6b334790048406bd6301b12 upstream. Currently frame registrations are not purged, even when changing the interface type. This can lead to potentially weird situations where frames possibly not allowed on a given interface type remain registered due to the type switching happening after registration. The kernel currently relies on userspace apps to actually purge the registrations themselves, this is not something that the kernel should rely on. Add a call to cfg80211_mlme_purge_registrations() to forcefully remove any registrations left over prior to switching the iftype. Cc: stable@vger.kernel.org Signed-off-by: Denis Kenzior Link: https://lore.kernel.org/r/20190828211110.15005-1-denkenz@gmail.com Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/wireless/util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/wireless/util.c b/net/wireless/util.c index 1d239564baa3..405388772fc4 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -974,6 +974,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, } cfg80211_process_rdev_events(rdev); + cfg80211_mlme_purge_registrations(dev->ieee80211_ptr); } err = rdev_change_virtual_intf(rdev, dev, ntype, flags, params); -- cgit v1.2.3 From 4e9518d21cf0244247b2386f11949fb4ccf38667 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 26 Aug 2019 22:13:25 +0900 Subject: /dev/mem: Bail out upon SIGKILL. commit 8619e5bdeee8b2c685d686281f2d2a6017c4bc15 upstream. syzbot found that a thread can stall for minutes inside read_mem() or write_mem() after that thread was killed by SIGKILL [1]. Reading from iomem areas of /dev/mem can be slow, depending on the hardware. While reading 2GB at one read() is legal, delaying termination of killed thread for minutes is bad. Thus, allow reading/writing /dev/mem and /dev/kmem to be preemptible and killable. [ 1335.912419][T20577] read_mem: sz=4096 count=2134565632 [ 1335.943194][T20577] read_mem: sz=4096 count=2134561536 [ 1335.978280][T20577] read_mem: sz=4096 count=2134557440 [ 1336.011147][T20577] read_mem: sz=4096 count=2134553344 [ 1336.041897][T20577] read_mem: sz=4096 count=2134549248 Theoretically, reading/writing /dev/mem and /dev/kmem can become "interruptible". But this patch chose "killable". Future patch will make them "interruptible" so that we can revert to "killable" if some program regressed. [1] https://syzkaller.appspot.com/bug?id=a0e3436829698d5824231251fad9d8e998f94f5e Signed-off-by: Tetsuo Handa Cc: stable Reported-by: syzbot Link: https://lore.kernel.org/r/1566825205-10703-1-git-send-email-penguin-kernel@I-love.SAKURA.ne.jp Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/char/mem.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 23f52a897283..6ebe2b86d8eb 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -95,6 +95,13 @@ void __weak unxlate_dev_mem_ptr(phys_addr_t phys, void *addr) } #endif +static inline bool should_stop_iteration(void) +{ + if (need_resched()) + cond_resched(); + return fatal_signal_pending(current); +} + /* * This funcion reads the *physical* memory. The f_pos points directly to the * memory location. @@ -161,6 +168,8 @@ static ssize_t read_mem(struct file *file, char __user *buf, p += sz; count -= sz; read += sz; + if (should_stop_iteration()) + break; } *ppos += read; @@ -232,6 +241,8 @@ static ssize_t write_mem(struct file *file, const char __user *buf, p += sz; count -= sz; written += sz; + if (should_stop_iteration()) + break; } *ppos += written; @@ -443,6 +454,10 @@ static ssize_t read_kmem(struct file *file, char __user *buf, read += sz; low_count -= sz; count -= sz; + if (should_stop_iteration()) { + count = 0; + break; + } } } @@ -467,6 +482,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf, buf += sz; read += sz; p += sz; + if (should_stop_iteration()) + break; } free_page((unsigned long)kbuf); } @@ -517,6 +534,8 @@ static ssize_t do_write_kmem(unsigned long p, const char __user *buf, p += sz; count -= sz; written += sz; + if (should_stop_iteration()) + break; } *ppos += written; @@ -568,6 +587,8 @@ static ssize_t write_kmem(struct file *file, const char __user *buf, buf += sz; virtr += sz; p += sz; + if (should_stop_iteration()) + break; } free_page((unsigned long)kbuf); } -- cgit v1.2.3 From 39950e657d5e16328cc93ab6bfc7780ab8f70c2c Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 23 Aug 2019 22:38:00 -0400 Subject: ext4: fix punch hole for inline_data file systems commit c1e8220bd316d8ae8e524df39534b8a412a45d5e upstream. If a program attempts to punch a hole on an inline data file, we need to convert it to a normal file first. This was detected using ext4/032 using the adv configuration. Simple reproducer: mke2fs -Fq -t ext4 -O inline_data /dev/vdc mount /vdc echo "" > /vdc/testfile xfs_io -c 'truncate 33554432' /vdc/testfile xfs_io -c 'fpunch 0 1048576' /vdc/testfile umount /vdc e2fsck -fy /dev/vdc Cc: stable@vger.kernel.org Signed-off-by: Theodore Ts'o Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 063c5991f095..3557c5717c8d 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3705,6 +3705,15 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) trace_ext4_punch_hole(inode, offset, length, 0); + ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); + if (ext4_has_inline_data(inode)) { + down_write(&EXT4_I(inode)->i_mmap_sem); + ret = ext4_convert_inline_data(inode); + up_write(&EXT4_I(inode)->i_mmap_sem); + if (ret) + return ret; + } + /* * Write out all dirty pages to avoid race conditions * Then release them. -- cgit v1.2.3 From 70a2b17f151e28ce659782ae9751b54ca9b6563b Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 11 Sep 2019 17:36:50 +0800 Subject: quota: fix wrong condition in is_quota_modification() commit 6565c182094f69e4ffdece337d395eb7ec760efc upstream. Quoted from commit 3da40c7b0898 ("ext4: only call ext4_truncate when size <= isize") " At LSF we decided that if we truncate up from isize we shouldn't trim fallocated blocks that were fallocated with KEEP_SIZE and are past the new i_size. This patch fixes ext4 to do this. " And generic/092 of fstest have covered this case for long time, however is_quota_modification() didn't adjust based on that rule, so that in below condition, we will lose to quota block change: - fallocate blocks beyond EOF - remount - truncate(file_path, file_size) Fix it. Link: https://lore.kernel.org/r/20190911093650.35329-1-yuchao0@huawei.com Fixes: 3da40c7b0898 ("ext4: only call ext4_truncate when size <= isize") CC: stable@vger.kernel.org Signed-off-by: Chao Yu Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- include/linux/quotaops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index 7a57c28eb5e7..1f350238445c 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -21,7 +21,7 @@ static inline struct quota_info *sb_dqopt(struct super_block *sb) /* i_mutex must being held */ static inline bool is_quota_modification(struct inode *inode, struct iattr *ia) { - return (ia->ia_valid & ATTR_SIZE && ia->ia_size != inode->i_size) || + return (ia->ia_valid & ATTR_SIZE) || (ia->ia_valid & ATTR_UID && !uid_eq(ia->ia_uid, inode->i_uid)) || (ia->ia_valid & ATTR_GID && !gid_eq(ia->ia_gid, inode->i_gid)); } -- cgit v1.2.3 From c648d4350015ab238c0b1ba35616adfb72f5d76b Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 17 Sep 2019 11:54:50 +0200 Subject: hwrng: core - don't wait on add_early_randomness() commit 78887832e76541f77169a24ac238fccb51059b63 upstream. add_early_randomness() is called by hwrng_register() when the hardware is added. If this hardware and its module are present at boot, and if there is no data available the boot hangs until data are available and can't be interrupted. For instance, in the case of virtio-rng, in some cases the host can be not able to provide enough entropy for all the guests. We can have two easy ways to reproduce the problem but they rely on misconfiguration of the hypervisor or the egd daemon: - if virtio-rng device is configured to connect to the egd daemon of the host but when the virtio-rng driver asks for data the daemon is not connected, - if virtio-rng device is configured to connect to the egd daemon of the host but the egd daemon doesn't provide data. The guest kernel will hang at boot until the virtio-rng driver provides enough data. To avoid that, call rng_get_data() in non-blocking mode (wait=0) from add_early_randomness(). Signed-off-by: Laurent Vivier Fixes: d9e797261933 ("hwrng: add randomness to system from rng...") Cc: Reviewed-by: Theodore Ts'o Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/char/hw_random/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 340f96e44642..bba54422d2ca 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -88,7 +88,7 @@ static void add_early_randomness(struct hwrng *rng) size_t size = min_t(size_t, 16, rng_buffer_size()); mutex_lock(&reading_mutex); - bytes_read = rng_get_data(rng, rng_buffer, size, 1); + bytes_read = rng_get_data(rng, rng_buffer, size, 0); mutex_unlock(&reading_mutex); if (bytes_read > 0) add_device_randomness(rng_buffer, bytes_read); -- cgit v1.2.3 From ba8d9cdbe5a2174187a8b9694bb3c9e4862c1936 Mon Sep 17 00:00:00 2001 From: Chris Brandt Date: Thu, 26 Sep 2019 07:19:09 -0500 Subject: i2c: riic: Clear NACK in tend isr commit a71e2ac1f32097fbb2beab098687a7a95c84543e upstream. The NACKF flag should be cleared in INTRIICNAKI interrupt processing as description in HW manual. This issue shows up quickly when PREEMPT_RT is applied and a device is probed that is not plugged in (like a touchscreen controller). The result is endless interrupts that halt system boot. Fixes: 310c18a41450 ("i2c: riic: add driver") Cc: stable@vger.kernel.org Reported-by: Chien Nguyen Signed-off-by: Chris Brandt Signed-off-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-riic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 16833365475f..a4eceb994f7e 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -212,6 +212,7 @@ static irqreturn_t riic_tend_isr(int irq, void *data) if (readb(riic->base + RIIC_ICSR2) & ICSR2_NACKF) { /* We got a NACKIE */ readb(riic->base + RIIC_ICDRR); /* dummy read */ + riic_clear_set_bit(riic, ICSR2_NACKF, 0, RIIC_ICSR2); riic->err = -ENXIO; } else if (riic->bytes_left) { return IRQ_NONE; -- cgit v1.2.3 From 0d9cc53fde529a8ab037d1cd8052daacf7573fb5 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Thu, 26 Sep 2019 12:31:20 -0700 Subject: CIFS: Fix oplock handling for SMB 2.1+ protocols commit a016e2794fc3a245a91946038dd8f34d65e53cc3 upstream. There may be situations when a server negotiates SMB 2.1 protocol version or higher but responds to a CREATE request with an oplock rather than a lease. Currently the client doesn't handle such a case correctly: when another CREATE comes in the server sends an oplock break to the initial CREATE and the client doesn't send an ack back due to a wrong caching level being set (READ instead of RWH). Missing an oplock break ack makes the server wait until the break times out which dramatically increases the latency of the second CREATE. Fix this by properly detecting oplocks when using SMB 2.1 protocol version and higher. Cc: Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg Signed-off-by: Greg Kroah-Hartman --- fs/cifs/smb2ops.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 591c93de8c20..0fcf42401a5d 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1335,6 +1335,11 @@ smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE) return; + /* Check if the server granted an oplock rather than a lease */ + if (oplock & SMB2_OPLOCK_LEVEL_EXCLUSIVE) + return smb2_set_oplock_level(cinode, oplock, epoch, + purge_cache); + if (oplock & SMB2_LEASE_READ_CACHING_HE) { new_oplock |= CIFS_CACHE_READ_FLG; strcat(message, "R"); -- cgit v1.2.3 From 05f4bc30f5a0f3f0f56e87de3a2d6dfcc280b769 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Thu, 29 Aug 2019 11:30:14 -0700 Subject: ovl: filter of trusted xattr results in audit commit 5c2e9f346b815841f9bed6029ebcb06415caf640 upstream. When filtering xattr list for reading, presence of trusted xattr results in a security audit log. However, if there is other content no errno will be set, and if there isn't, the errno will be -ENODATA and not -EPERM as is usually associated with a lack of capability. The check does not block the request to list the xattrs present. Switch to ns_capable_noaudit to reflect a more appropriate check. Signed-off-by: Mark Salyzyn Cc: linux-security-module@vger.kernel.org Cc: kernel-team@android.com Cc: stable@vger.kernel.org # v3.18+ Fixes: a082c6f680da ("ovl: filter trusted xattr for non-admin") Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/overlayfs/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 9aff8178aa8c..060482e349ef 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -292,7 +292,8 @@ static bool ovl_can_list(const char *s) return true; /* Never list trusted.overlay, list other trusted for superuser only */ - return !ovl_is_private_xattr(s) && capable(CAP_SYS_ADMIN); + return !ovl_is_private_xattr(s) && + ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN); } ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) -- cgit v1.2.3 From 2cd8f741aa121a647b9f2a184edd1720111b9821 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Mon, 12 Aug 2019 19:14:29 +0100 Subject: Btrfs: fix use-after-free when using the tree modification log commit efad8a853ad2057f96664328a0d327a05ce39c76 upstream. At ctree.c:get_old_root(), we are accessing a root's header owner field after we have freed the respective extent buffer. This results in an use-after-free that can lead to crashes, and when CONFIG_DEBUG_PAGEALLOC is set, results in a stack trace like the following: [ 3876.799331] stack segment: 0000 [#1] SMP DEBUG_PAGEALLOC PTI [ 3876.799363] CPU: 0 PID: 15436 Comm: pool Not tainted 5.3.0-rc3-btrfs-next-54 #1 [ 3876.799385] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-0-ga698c8995f-prebuilt.qemu.org 04/01/2014 [ 3876.799433] RIP: 0010:btrfs_search_old_slot+0x652/0xd80 [btrfs] (...) [ 3876.799502] RSP: 0018:ffff9f08c1a2f9f0 EFLAGS: 00010286 [ 3876.799518] RAX: ffff8dd300000000 RBX: ffff8dd85a7a9348 RCX: 000000038da26000 [ 3876.799538] RDX: 0000000000000000 RSI: ffffe522ce368980 RDI: 0000000000000246 [ 3876.799559] RBP: dae1922adadad000 R08: 0000000008020000 R09: ffffe522c0000000 [ 3876.799579] R10: ffff8dd57fd788c8 R11: 000000007511b030 R12: ffff8dd781ddc000 [ 3876.799599] R13: ffff8dd9e6240578 R14: ffff8dd6896f7a88 R15: ffff8dd688cf90b8 [ 3876.799620] FS: 00007f23ddd97700(0000) GS:ffff8dda20200000(0000) knlGS:0000000000000000 [ 3876.799643] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 3876.799660] CR2: 00007f23d4024000 CR3: 0000000710bb0005 CR4: 00000000003606f0 [ 3876.799682] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 3876.799703] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 3876.799723] Call Trace: [ 3876.799735] ? do_raw_spin_unlock+0x49/0xc0 [ 3876.799749] ? _raw_spin_unlock+0x24/0x30 [ 3876.799779] resolve_indirect_refs+0x1eb/0xc80 [btrfs] [ 3876.799810] find_parent_nodes+0x38d/0x1180 [btrfs] [ 3876.799841] btrfs_check_shared+0x11a/0x1d0 [btrfs] [ 3876.799870] ? extent_fiemap+0x598/0x6e0 [btrfs] [ 3876.799895] extent_fiemap+0x598/0x6e0 [btrfs] [ 3876.799913] do_vfs_ioctl+0x45a/0x700 [ 3876.799926] ksys_ioctl+0x70/0x80 [ 3876.799938] ? trace_hardirqs_off_thunk+0x1a/0x20 [ 3876.799953] __x64_sys_ioctl+0x16/0x20 [ 3876.799965] do_syscall_64+0x62/0x220 [ 3876.799977] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 3876.799993] RIP: 0033:0x7f23e0013dd7 (...) [ 3876.800056] RSP: 002b:00007f23ddd96ca8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 [ 3876.800078] RAX: ffffffffffffffda RBX: 00007f23d80210f8 RCX: 00007f23e0013dd7 [ 3876.800099] RDX: 00007f23d80210f8 RSI: 00000000c020660b RDI: 0000000000000003 [ 3876.800626] RBP: 000055fa2a2a2440 R08: 0000000000000000 R09: 00007f23ddd96d7c [ 3876.801143] R10: 00007f23d8022000 R11: 0000000000000246 R12: 00007f23ddd96d80 [ 3876.801662] R13: 00007f23ddd96d78 R14: 00007f23d80210f0 R15: 00007f23ddd96d80 (...) [ 3876.805107] ---[ end trace e53161e179ef04f9 ]--- Fix that by saving the root's header owner field into a local variable before freeing the root's extent buffer, and then use that local variable when needed. Fixes: 30b0463a9394d9 ("Btrfs: fix accessing the root pointer in tree mod log functions") CC: stable@vger.kernel.org # 3.10+ Reviewed-by: Nikolay Borisov Reviewed-by: Anand Jain Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/ctree.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 8f4baa3cb992..5ed4350f5c81 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -1418,6 +1418,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq) struct tree_mod_elem *tm; struct extent_buffer *eb = NULL; struct extent_buffer *eb_root; + u64 eb_root_owner = 0; struct extent_buffer *old; struct tree_mod_root *old_root = NULL; u64 old_generation = 0; @@ -1451,6 +1452,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq) free_extent_buffer(old); } } else if (old_root) { + eb_root_owner = btrfs_header_owner(eb_root); btrfs_tree_read_unlock(eb_root); free_extent_buffer(eb_root); eb = alloc_dummy_extent_buffer(root->fs_info, logical); @@ -1468,7 +1470,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq) if (old_root) { btrfs_set_header_bytenr(eb, eb->start); btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(eb, btrfs_header_owner(eb_root)); + btrfs_set_header_owner(eb, eb_root_owner); btrfs_set_header_level(eb, old_root->level); btrfs_set_header_generation(eb, old_generation); } -- cgit v1.2.3 From 87bd41e20d9f5fb9bad7eb989050b72946f28d07 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Wed, 4 Sep 2019 19:33:58 +0300 Subject: btrfs: Relinquish CPUs in btrfs_compare_trees commit 6af112b11a4bc1b560f60a618ac9c1dcefe9836e upstream. When doing any form of incremental send the parent and the child trees need to be compared via btrfs_compare_trees. This can result in long loop chains without ever relinquishing the CPU. This causes softlockup detector to trigger when comparing trees with a lot of items. Example report: watchdog: BUG: soft lockup - CPU#0 stuck for 24s! [snapperd:16153] CPU: 0 PID: 16153 Comm: snapperd Not tainted 5.2.9-1-default #1 openSUSE Tumbleweed (unreleased) Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015 pstate: 40000005 (nZcv daif -PAN -UAO) pc : __ll_sc_arch_atomic_sub_return+0x14/0x20 lr : btrfs_release_extent_buffer_pages+0xe0/0x1e8 [btrfs] sp : ffff00001273b7e0 Call trace: __ll_sc_arch_atomic_sub_return+0x14/0x20 release_extent_buffer+0xdc/0x120 [btrfs] free_extent_buffer.part.0+0xb0/0x118 [btrfs] free_extent_buffer+0x24/0x30 [btrfs] btrfs_release_path+0x4c/0xa0 [btrfs] btrfs_free_path.part.0+0x20/0x40 [btrfs] btrfs_free_path+0x24/0x30 [btrfs] get_inode_info+0xa8/0xf8 [btrfs] finish_inode_if_needed+0xe0/0x6d8 [btrfs] changed_cb+0x9c/0x410 [btrfs] btrfs_compare_trees+0x284/0x648 [btrfs] send_subvol+0x33c/0x520 [btrfs] btrfs_ioctl_send+0x8a0/0xaf0 [btrfs] btrfs_ioctl+0x199c/0x2288 [btrfs] do_vfs_ioctl+0x4b0/0x820 ksys_ioctl+0x84/0xb8 __arm64_sys_ioctl+0x28/0x38 el0_svc_common.constprop.0+0x7c/0x188 el0_svc_handler+0x34/0x90 el0_svc+0x8/0xc Fix this by adding a call to cond_resched at the beginning of the main loop in btrfs_compare_trees. Fixes: 7069830a9e38 ("Btrfs: add btrfs_compare_trees function") CC: stable@vger.kernel.org # 4.4+ Reviewed-by: Johannes Thumshirn Signed-off-by: Nikolay Borisov Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/ctree.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 5ed4350f5c81..51a0409e1b84 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -5435,6 +5435,7 @@ int btrfs_compare_trees(struct btrfs_root *left_root, advance_left = advance_right = 0; while (1) { + cond_resched(); if (advance_left && !left_end_reached) { ret = tree_advance(left_root, left_path, &left_level, left_root_level, -- cgit v1.2.3 From ec9a11a0b2f87b80c4882901bbc3f8e8636ec662 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Tue, 24 Sep 2019 10:49:54 +0100 Subject: Btrfs: fix race setting up and completing qgroup rescan workers [ Upstream commit 13fc1d271a2e3ab8a02071e711add01fab9271f6 ] There is a race between setting up a qgroup rescan worker and completing a qgroup rescan worker that can lead to callers of the qgroup rescan wait ioctl to either not wait for the rescan worker to complete or to hang forever due to missing wake ups. The following diagram shows a sequence of steps that illustrates the race. CPU 1 CPU 2 CPU 3 btrfs_ioctl_quota_rescan() btrfs_qgroup_rescan() qgroup_rescan_init() mutex_lock(&fs_info->qgroup_rescan_lock) spin_lock(&fs_info->qgroup_lock) fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_RESCAN init_completion( &fs_info->qgroup_rescan_completion) fs_info->qgroup_rescan_running = true mutex_unlock(&fs_info->qgroup_rescan_lock) spin_unlock(&fs_info->qgroup_lock) btrfs_init_work() --> starts the worker btrfs_qgroup_rescan_worker() mutex_lock(&fs_info->qgroup_rescan_lock) fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN mutex_unlock(&fs_info->qgroup_rescan_lock) starts transaction, updates qgroup status item, etc btrfs_ioctl_quota_rescan() btrfs_qgroup_rescan() qgroup_rescan_init() mutex_lock(&fs_info->qgroup_rescan_lock) spin_lock(&fs_info->qgroup_lock) fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_RESCAN init_completion( &fs_info->qgroup_rescan_completion) fs_info->qgroup_rescan_running = true mutex_unlock(&fs_info->qgroup_rescan_lock) spin_unlock(&fs_info->qgroup_lock) btrfs_init_work() --> starts another worker mutex_lock(&fs_info->qgroup_rescan_lock) fs_info->qgroup_rescan_running = false mutex_unlock(&fs_info->qgroup_rescan_lock) complete_all(&fs_info->qgroup_rescan_completion) Before the rescan worker started by the task at CPU 3 completes, if another task calls btrfs_ioctl_quota_rescan(), it will get -EINPROGRESS because the flag BTRFS_QGROUP_STATUS_FLAG_RESCAN is set at fs_info->qgroup_flags, which is expected and correct behaviour. However if other task calls btrfs_ioctl_quota_rescan_wait() before the rescan worker started by the task at CPU 3 completes, it will return immediately without waiting for the new rescan worker to complete, because fs_info->qgroup_rescan_running is set to false by CPU 2. This race is making test case btrfs/171 (from fstests) to fail often: btrfs/171 9s ... - output mismatch (see /home/fdmanana/git/hub/xfstests/results//btrfs/171.out.bad) # --- tests/btrfs/171.out 2018-09-16 21:30:48.505104287 +0100 # +++ /home/fdmanana/git/hub/xfstests/results//btrfs/171.out.bad 2019-09-19 02:01:36.938486039 +0100 # @@ -1,2 +1,3 @@ # QA output created by 171 # +ERROR: quota rescan failed: Operation now in progress # Silence is golden # ... # (Run 'diff -u /home/fdmanana/git/hub/xfstests/tests/btrfs/171.out /home/fdmanana/git/hub/xfstests/results//btrfs/171.out.bad' to see the entire diff) That is because the test calls the btrfs-progs commands "qgroup quota rescan -w", "qgroup assign" and "qgroup remove" in a sequence that makes calls to the rescan start ioctl fail with -EINPROGRESS (note the "btrfs" commands 'qgroup assign' and 'qgroup remove' often call the rescan start ioctl after calling the qgroup assign ioctl, btrfs_ioctl_qgroup_assign()), since previous waits didn't actually wait for a rescan worker to complete. Another problem the race can cause is missing wake ups for waiters, since the call to complete_all() happens outside a critical section and after clearing the flag BTRFS_QGROUP_STATUS_FLAG_RESCAN. In the sequence diagram above, if we have a waiter for the first rescan task (executed by CPU 2), then fs_info->qgroup_rescan_completion.wait is not empty, and if after the rescan worker clears BTRFS_QGROUP_STATUS_FLAG_RESCAN and before it calls complete_all() against fs_info->qgroup_rescan_completion, the task at CPU 3 calls init_completion() against fs_info->qgroup_rescan_completion which re-initilizes its wait queue to an empty queue, therefore causing the rescan worker at CPU 2 to call complete_all() against an empty queue, never waking up the task waiting for that rescan worker. Fix this by clearing BTRFS_QGROUP_STATUS_FLAG_RESCAN and setting fs_info->qgroup_rescan_running to false in the same critical section, delimited by the mutex fs_info->qgroup_rescan_lock, as well as doing the call to complete_all() in that same critical section. This gives the protection needed to avoid rescan wait ioctl callers not waiting for a running rescan worker and the lost wake ups problem, since setting that rescan flag and boolean as well as initializing the wait queue is done already in a critical section delimited by that mutex (at qgroup_rescan_init()). Fixes: 57254b6ebce4ce ("Btrfs: add ioctl to wait for qgroup rescan completion") Fixes: d2c609b834d62f ("btrfs: properly track when rescan worker is running") CC: stable@vger.kernel.org # 4.4+ Reviewed-by: Josef Bacik Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/qgroup.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 90e29d40aa82..734babb6626c 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -2328,9 +2328,6 @@ out: btrfs_free_path(path); mutex_lock(&fs_info->qgroup_rescan_lock); - if (!btrfs_fs_closing(fs_info)) - fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; - if (err > 0 && fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) { fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; @@ -2346,16 +2343,30 @@ out: trans = btrfs_start_transaction(fs_info->quota_root, 1); if (IS_ERR(trans)) { err = PTR_ERR(trans); + trans = NULL; btrfs_err(fs_info, "fail to start transaction for status update: %d\n", err); - goto done; } - ret = update_qgroup_status_item(trans, fs_info, fs_info->quota_root); - if (ret < 0) { - err = ret; - btrfs_err(fs_info, "fail to update qgroup status: %d\n", err); + + mutex_lock(&fs_info->qgroup_rescan_lock); + if (!btrfs_fs_closing(fs_info)) + fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; + if (trans) { + ret = update_qgroup_status_item(trans, fs_info, fs_info->quota_root); + if (ret < 0) { + err = ret; + btrfs_err(fs_info, "fail to update qgroup status: %d", + err); + } } + fs_info->qgroup_rescan_running = false; + complete_all(&fs_info->qgroup_rescan_completion); + mutex_unlock(&fs_info->qgroup_rescan_lock); + + if (!trans) + return; + btrfs_end_transaction(trans, fs_info->quota_root); if (btrfs_fs_closing(fs_info)) { @@ -2366,12 +2377,6 @@ out: } else { btrfs_err(fs_info, "qgroup scan failed with %d", err); } - -done: - mutex_lock(&fs_info->qgroup_rescan_lock); - fs_info->qgroup_rescan_running = false; - mutex_unlock(&fs_info->qgroup_rescan_lock); - complete_all(&fs_info->qgroup_rescan_completion); } /* -- cgit v1.2.3 From 5164f0c3740d357ba460b44222bedfa2475ca794 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 5 Oct 2019 12:27:56 +0200 Subject: Linux 4.4.195 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bea8f3f591c4..721fa569a680 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 194 +SUBLEVEL = 195 EXTRAVERSION = NAME = Blurry Fish Butt -- cgit v1.2.3 From 512013196156b47397eac3b4c1a046898629be40 Mon Sep 17 00:00:00 2001 From: Marko Kohtala Date: Tue, 18 Jun 2019 10:41:08 +0300 Subject: video: ssd1307fb: Start page range at page_offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit dd9782834dd9dde3624ff1acea8859f3d3e792d4 ] The page_offset was only applied to the end of the page range. This caused the display updates to cause a scrolling effect on the display because the amount of data written to the display did not match the range display expected. Fixes: 301bc0675b67 ("video: ssd1307fb: Make use of horizontal addressing mode") Signed-off-by: Marko Kohtala Cc: Mark Rutland Cc: Rob Herring Cc: Daniel Vetter Cc: David Airlie Cc: Michal Vokáč Signed-off-by: Bartlomiej Zolnierkiewicz Link: https://patchwork.freedesktop.org/patch/msgid/20190618074111.9309-4-marko.kohtala@okoko.fi Signed-off-by: Sasha Levin --- drivers/video/fbdev/ssd1307fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index fa3480815cdb..88e0763edcc7 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -421,7 +421,7 @@ static int ssd1307fb_init(struct ssd1307fb_par *par) if (ret < 0) return ret; - ret = ssd1307fb_write_cmd(par->client, 0x0); + ret = ssd1307fb_write_cmd(par->client, par->page_offset); if (ret < 0) return ret; -- cgit v1.2.3 From 3c803c1552920d689177874bb49c7610fd7fdc9b Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Mon, 29 Jul 2019 16:36:44 +0800 Subject: gpu: drm: radeon: Fix a possible null-pointer dereference in radeon_connector_set_property() [ Upstream commit f3eb9b8f67bc28783eddc142ad805ebdc53d6339 ] In radeon_connector_set_property(), there is an if statement on line 743 to check whether connector->encoder is NULL: if (connector->encoder) When connector->encoder is NULL, it is used on line 755: if (connector->encoder->crtc) Thus, a possible null-pointer dereference may occur. To fix this bug, connector->encoder is checked before being used. This bug is found by a static analysis tool STCheck written by us. Signed-off-by: Jia-Ju Bai Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/radeon/radeon_connectors.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index c6bf378534f8..bebcef2ce6b8 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -758,7 +758,7 @@ static int radeon_connector_set_property(struct drm_connector *connector, struct radeon_encoder->output_csc = val; - if (connector->encoder->crtc) { + if (connector->encoder && connector->encoder->crtc) { struct drm_crtc *crtc = connector->encoder->crtc; const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); -- cgit v1.2.3 From d9e87b4415c7a81986f440e32f628325f79ae533 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 2 Aug 2019 07:31:36 -0500 Subject: ipmi_si: Only schedule continuously in the thread in maintenance mode [ Upstream commit 340ff31ab00bca5c15915e70ad9ada3030c98cf8 ] ipmi_thread() uses back-to-back schedule() to poll for command completion which, on some machines, can push up CPU consumption and heavily tax the scheduler locks leading to noticeable overall performance degradation. This was originally added so firmware updates through IPMI would complete in a timely manner. But we can't kill the scheduler locks for that one use case. Instead, only run schedule() continuously in maintenance mode, where firmware updates should run. Signed-off-by: Corey Minyard Signed-off-by: Sasha Levin --- drivers/char/ipmi/ipmi_si_intf.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 2f9abe0d04dc..2f8ff63bbbe4 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -281,6 +281,9 @@ struct smi_info { */ bool irq_enable_broken; + /* Is the driver in maintenance mode? */ + bool in_maintenance_mode; + /* * Did we get an attention that we did not handle? */ @@ -1091,11 +1094,20 @@ static int ipmi_thread(void *data) spin_unlock_irqrestore(&(smi_info->si_lock), flags); busy_wait = ipmi_thread_busy_wait(smi_result, smi_info, &busy_until); - if (smi_result == SI_SM_CALL_WITHOUT_DELAY) + if (smi_result == SI_SM_CALL_WITHOUT_DELAY) { ; /* do nothing */ - else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait) - schedule(); - else if (smi_result == SI_SM_IDLE) { + } else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait) { + /* + * In maintenance mode we run as fast as + * possible to allow firmware updates to + * complete as fast as possible, but normally + * don't bang on the scheduler. + */ + if (smi_info->in_maintenance_mode) + schedule(); + else + usleep_range(100, 200); + } else if (smi_result == SI_SM_IDLE) { if (atomic_read(&smi_info->need_watch)) { schedule_timeout_interruptible(100); } else { @@ -1103,8 +1115,9 @@ static int ipmi_thread(void *data) __set_current_state(TASK_INTERRUPTIBLE); schedule(); } - } else + } else { schedule_timeout_interruptible(1); + } } return 0; } @@ -1283,6 +1296,7 @@ static void set_maintenance_mode(void *send_info, bool enable) if (!enable) atomic_set(&smi_info->req_events, 0); + smi_info->in_maintenance_mode = enable; } static const struct ipmi_smi_handlers handlers = { -- cgit v1.2.3 From 41a943ca1fb49be31db727b2977008b1c127a949 Mon Sep 17 00:00:00 2001 From: Nathan Huckleberry Date: Thu, 27 Jun 2019 15:06:42 -0700 Subject: clk: qoriq: Fix -Wunused-const-variable [ Upstream commit a95fb581b144b5e73da382eaedb2e32027610597 ] drivers/clk/clk-qoriq.c:138:38: warning: unused variable 'p5020_cmux_grp1' [-Wunused-const-variable] static const struct clockgen_muxinfo p5020_cmux_grp1 drivers/clk/clk-qoriq.c:146:38: warning: unused variable 'p5020_cmux_grp2' [-Wunused-const-variable] static const struct clockgen_muxinfo p5020_cmux_grp2 In the definition of the p5020 chip, the p2041 chip's info was used instead. The p5020 and p2041 chips have different info. This is most likely a typo. Link: https://github.com/ClangBuiltLinux/linux/issues/525 Cc: clang-built-linux@googlegroups.com Signed-off-by: Nathan Huckleberry Link: https://lkml.kernel.org/r/20190627220642.78575-1-nhuck@google.com Reviewed-by: Nick Desaulniers Acked-by: Scott Wood Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/clk-qoriq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index a5070f9cb0d4..7244a621c61b 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -540,7 +540,7 @@ static const struct clockgen_chipinfo chipinfo[] = { .guts_compat = "fsl,qoriq-device-config-1.0", .init_periph = p5020_init_periph, .cmux_groups = { - &p2041_cmux_grp1, &p2041_cmux_grp2 + &p5020_cmux_grp1, &p5020_cmux_grp2 }, .cmux_to_group = { 0, 1, -1 -- cgit v1.2.3 From dde75090314d42b88942da32be722207958de075 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 31 Jul 2019 12:35:13 -0700 Subject: clk: sirf: Don't reference clk_init_data after registration [ Upstream commit af55dadfbce35b4f4c6247244ce3e44b2e242b84 ] A future patch is going to change semantics of clk_register() so that clk_hw::init is guaranteed to be NULL after a clk is registered. Avoid referencing this member here so that we don't run into NULL pointer exceptions. Cc: Guo Zeng Cc: Barry Song Signed-off-by: Stephen Boyd Link: https://lkml.kernel.org/r/20190731193517.237136-6-sboyd@kernel.org Signed-off-by: Sasha Levin --- drivers/clk/sirf/clk-common.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/clk/sirf/clk-common.c b/drivers/clk/sirf/clk-common.c index 77e1e2491689..edb7197cc4b4 100644 --- a/drivers/clk/sirf/clk-common.c +++ b/drivers/clk/sirf/clk-common.c @@ -298,9 +298,10 @@ static u8 dmn_clk_get_parent(struct clk_hw *hw) { struct clk_dmn *clk = to_dmnclk(hw); u32 cfg = clkc_readl(clk->regofs); + const char *name = clk_hw_get_name(hw); /* parent of io domain can only be pll3 */ - if (strcmp(hw->init->name, "io") == 0) + if (strcmp(name, "io") == 0) return 4; WARN_ON((cfg & (BIT(3) - 1)) > 4); @@ -312,9 +313,10 @@ static int dmn_clk_set_parent(struct clk_hw *hw, u8 parent) { struct clk_dmn *clk = to_dmnclk(hw); u32 cfg = clkc_readl(clk->regofs); + const char *name = clk_hw_get_name(hw); /* parent of io domain can only be pll3 */ - if (strcmp(hw->init->name, "io") == 0) + if (strcmp(name, "io") == 0) return -EINVAL; cfg &= ~(BIT(3) - 1); @@ -354,7 +356,8 @@ static long dmn_clk_round_rate(struct clk_hw *hw, unsigned long rate, { unsigned long fin; unsigned ratio, wait, hold; - unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4; + const char *name = clk_hw_get_name(hw); + unsigned bits = (strcmp(name, "mem") == 0) ? 3 : 4; fin = *parent_rate; ratio = fin / rate; @@ -376,7 +379,8 @@ static int dmn_clk_set_rate(struct clk_hw *hw, unsigned long rate, struct clk_dmn *clk = to_dmnclk(hw); unsigned long fin; unsigned ratio, wait, hold, reg; - unsigned bits = (strcmp(hw->init->name, "mem") == 0) ? 3 : 4; + const char *name = clk_hw_get_name(hw); + unsigned bits = (strcmp(name, "mem") == 0) ? 3 : 4; fin = parent_rate; ratio = fin / rate; -- cgit v1.2.3 From f8e62b01bb983903ff129cec53cce26231ad609f Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 2 Aug 2019 14:29:24 -0500 Subject: powerpc/rtas: use device model APIs and serialization during LPM [ Upstream commit a6717c01ddc259f6f73364779df058e2c67309f8 ] The LPAR migration implementation and userspace-initiated cpu hotplug can interleave their executions like so: 1. Set cpu 7 offline via sysfs. 2. Begin a partition migration, whose implementation requires the OS to ensure all present cpus are online; cpu 7 is onlined: rtas_ibm_suspend_me -> rtas_online_cpus_mask -> cpu_up This sets cpu 7 online in all respects except for the cpu's corresponding struct device; dev->offline remains true. 3. Set cpu 7 online via sysfs. _cpu_up() determines that cpu 7 is already online and returns success. The driver core (device_online) sets dev->offline = false. 4. The migration completes and restores cpu 7 to offline state: rtas_ibm_suspend_me -> rtas_offline_cpus_mask -> cpu_down This leaves cpu7 in a state where the driver core considers the cpu device online, but in all other respects it is offline and unused. Attempts to online the cpu via sysfs appear to succeed but the driver core actually does not pass the request to the lower-level cpuhp support code. This makes the cpu unusable until the cpu device is manually set offline and then online again via sysfs. Instead of directly calling cpu_up/cpu_down, the migration code should use the higher-level device core APIs to maintain consistent state and serialize operations. Fixes: 120496ac2d2d ("powerpc: Bring all threads online prior to migration/hibernation") Signed-off-by: Nathan Lynch Reviewed-by: Gautham R. Shenoy Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20190802192926.19277-2-nathanl@linux.ibm.com Signed-off-by: Sasha Levin --- arch/powerpc/kernel/rtas.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 5a753fae8265..0c42e872d548 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -857,15 +857,17 @@ static int rtas_cpu_state_change_mask(enum rtas_cpu_state state, return 0; for_each_cpu(cpu, cpus) { + struct device *dev = get_cpu_device(cpu); + switch (state) { case DOWN: - cpuret = cpu_down(cpu); + cpuret = device_offline(dev); break; case UP: - cpuret = cpu_up(cpu); + cpuret = device_online(dev); break; } - if (cpuret) { + if (cpuret < 0) { pr_debug("%s: cpu_%s for cpu#%d returned %d.\n", __func__, ((state == UP) ? "up" : "down"), @@ -954,6 +956,8 @@ int rtas_ibm_suspend_me(u64 handle) data.token = rtas_token("ibm,suspend-me"); data.complete = &done; + lock_device_hotplug(); + /* All present CPUs must be online */ cpumask_andnot(offline_mask, cpu_present_mask, cpu_online_mask); cpuret = rtas_online_cpus_mask(offline_mask); @@ -985,6 +989,7 @@ int rtas_ibm_suspend_me(u64 handle) __func__); out: + unlock_device_hotplug(); free_cpumask_var(offline_mask); return atomic_read(&data.error); } -- cgit v1.2.3 From 45dc36ca54ea99e33feb09093419bfddf8ee5c7a Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Wed, 14 Aug 2019 09:25:52 +0000 Subject: powerpc/futex: Fix warning: 'oldval' may be used uninitialized in this function [ Upstream commit 38a0d0cdb46d3f91534e5b9839ec2d67be14c59d ] We see warnings such as: kernel/futex.c: In function 'do_futex': kernel/futex.c:1676:17: warning: 'oldval' may be used uninitialized in this function [-Wmaybe-uninitialized] return oldval == cmparg; ^ kernel/futex.c:1651:6: note: 'oldval' was declared here int oldval, ret; ^ This is because arch_futex_atomic_op_inuser() only sets *oval if ret is 0 and GCC doesn't see that it will only use it when ret is 0. Anyway, the non-zero ret path is an error path that won't suffer from setting *oval, and as *oval is a local var in futex_atomic_op_inuser() it will have no impact. Signed-off-by: Christophe Leroy [mpe: reword change log slightly] Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/86b72f0c134367b214910b27b9a6dd3321af93bb.1565774657.git.christophe.leroy@c-s.fr Signed-off-by: Sasha Levin --- arch/powerpc/include/asm/futex.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h index f4c7467f7465..b73ab8a7ebc3 100644 --- a/arch/powerpc/include/asm/futex.h +++ b/arch/powerpc/include/asm/futex.h @@ -60,8 +60,7 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, pagefault_enable(); - if (!ret) - *oval = oldval; + *oval = oldval; return ret; } -- cgit v1.2.3 From a7a59733e741e398fdb787cbad4329069f9a23f5 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Fri, 2 Aug 2019 14:29:26 -0500 Subject: powerpc/pseries/mobility: use cond_resched when updating device tree [ Upstream commit ccfb5bd71d3d1228090a8633800ae7cdf42a94ac ] After a partition migration, pseries_devicetree_update() processes changes to the device tree communicated from the platform to Linux. This is a relatively heavyweight operation, with multiple device tree searches, memory allocations, and conversations with partition firmware. There's a few levels of nested loops which are bounded only by decisions made by the platform, outside of Linux's control, and indeed we have seen RCU stalls on large systems while executing this call graph. Use cond_resched() in these loops so that the cpu is yielded when needed. Signed-off-by: Nathan Lynch Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20190802192926.19277-4-nathanl@linux.ibm.com Signed-off-by: Sasha Levin --- arch/powerpc/platforms/pseries/mobility.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index c773396d0969..8d30a425a88a 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -206,7 +207,11 @@ static int update_dt_node(__be32 phandle, s32 scope) prop_data += vd; } + + cond_resched(); } + + cond_resched(); } while (rtas_rc == 1); of_node_put(dn); @@ -282,8 +287,12 @@ int pseries_devicetree_update(s32 scope) add_dt_node(phandle, drc_index); break; } + + cond_resched(); } } + + cond_resched(); } while (rc == 1); kfree(rtas_buf); -- cgit v1.2.3 From 4e197fe0406077bc3a0f9ae2021961071ae8d1f0 Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Fri, 16 Aug 2019 12:41:46 -0700 Subject: pinctrl: tegra: Fix write barrier placement in pmx_writel [ Upstream commit c2cf351eba2ff6002ce8eb178452219d2521e38e ] pmx_writel uses writel which inserts write barrier before the register write. This patch has fix to replace writel with writel_relaxed followed by a readback and memory barrier to ensure write operation is completed for successful pinctrl change. Acked-by: Thierry Reding Reviewed-by: Dmitry Osipenko Signed-off-by: Sowjanya Komatineni Link: https://lore.kernel.org/r/1565984527-5272-2-git-send-email-skomatineni@nvidia.com Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin --- drivers/pinctrl/pinctrl-tegra.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c index 0fd7fd2b0f72..a30e967d75c2 100644 --- a/drivers/pinctrl/pinctrl-tegra.c +++ b/drivers/pinctrl/pinctrl-tegra.c @@ -52,7 +52,9 @@ static inline u32 pmx_readl(struct tegra_pmx *pmx, u32 bank, u32 reg) static inline void pmx_writel(struct tegra_pmx *pmx, u32 val, u32 bank, u32 reg) { - writel(val, pmx->regs[bank] + reg); + writel_relaxed(val, pmx->regs[bank] + reg); + /* make sure pinmux register write completed */ + pmx_readl(pmx, bank, reg); } static int tegra_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) -- cgit v1.2.3 From 95fed5c9b1cebc3a82095253a7b4fed6939b165c Mon Sep 17 00:00:00 2001 From: hexin Date: Thu, 22 Aug 2019 11:35:19 +0800 Subject: vfio_pci: Restore original state on release [ Upstream commit 92c8026854c25093946e0d7fe536fd9eac440f06 ] vfio_pci_enable() saves the device's initial configuration information with the intent that it is restored in vfio_pci_disable(). However, the commit referenced in Fixes: below replaced the call to __pci_reset_function_locked(), which is not wrapped in a state save and restore, with pci_try_reset_function(), which overwrites the restored device state with the current state before applying it to the device. Reinstate use of __pci_reset_function_locked() to return to the desired behavior. Fixes: 890ed578df82 ("vfio-pci: Use pci "try" reset interface") Signed-off-by: hexin Signed-off-by: Liu Qi Signed-off-by: Zhang Yu Signed-off-by: Alex Williamson Signed-off-by: Sasha Levin --- drivers/vfio/pci/vfio_pci.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 47b229fa5e8e..4b62eb3b5923 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -221,11 +221,20 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev) pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); /* - * Try to reset the device. The success of this is dependent on - * being able to lock the device, which is not always possible. + * Try to get the locks ourselves to prevent a deadlock. The + * success of this is dependent on being able to lock the device, + * which is not always possible. + * We can not use the "try" reset interface here, which will + * overwrite the previously restored configuration information. */ - if (vdev->reset_works && !pci_try_reset_function(pdev)) - vdev->needs_reset = false; + if (vdev->reset_works && pci_cfg_access_trylock(pdev)) { + if (device_trylock(&pdev->dev)) { + if (!__pci_reset_function_locked(pdev)) + vdev->needs_reset = false; + device_unlock(&pdev->dev); + } + pci_cfg_access_unlock(pdev); + } pci_restore_state(pdev); out: -- cgit v1.2.3 From 90666ada1a8148ebe4a6ebef1e3a57f3607c1479 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 2 Aug 2019 20:56:32 +1000 Subject: powerpc/64s/exception: machine check use correct cfar for late handler [ Upstream commit 0b66370c61fcf5fcc1d6901013e110284da6e2bb ] Bare metal machine checks run an "early" handler in real mode before running the main handler which reports the event. The main handler runs exactly as a normal interrupt handler, after the "windup" which sets registers back as they were at interrupt entry. CFAR does not get restored by the windup code, so that will be wrong when the handler is run. Restore the CFAR to the saved value before running the late handler. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20190802105709.27696-8-npiggin@gmail.com Signed-off-by: Sasha Levin --- arch/powerpc/kernel/exceptions-64s.S | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index a44f1755dc4b..536718ed033f 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -1465,6 +1465,10 @@ machine_check_handle_early: RFI_TO_USER_OR_KERNEL 9: /* Deliver the machine check to host kernel in V mode. */ +BEGIN_FTR_SECTION + ld r10,ORIG_GPR3(r1) + mtspr SPRN_CFAR,r10 +END_FTR_SECTION_IFSET(CPU_FTR_CFAR) MACHINE_CHECK_HANDLER_WINDUP b machine_check_pSeries -- cgit v1.2.3 From e0fe918193a2f230b3295275fbd9ab21b2e84759 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Tue, 10 Sep 2019 17:52:44 -0500 Subject: powerpc/pseries: correctly track irq state in default idle [ Upstream commit 92c94dfb69e350471473fd3075c74bc68150879e ] prep_irq_for_idle() is intended to be called before entering H_CEDE (and it is used by the pseries cpuidle driver). However the default pseries idle routine does not call it, leading to mismanaged lazy irq state when the cpuidle driver isn't in use. Manifestations of this include: * Dropped IPIs in the time immediately after a cpu comes online (before it has installed the cpuidle handler), making the online operation block indefinitely waiting for the new cpu to respond. * Hitting this WARN_ON in arch_local_irq_restore(): /* * We should already be hard disabled here. We had bugs * where that wasn't the case so let's dbl check it and * warn if we are wrong. Only do that when IRQ tracing * is enabled as mfmsr() can be costly. */ if (WARN_ON_ONCE(mfmsr() & MSR_EE)) __hard_irq_disable(); Call prep_irq_for_idle() from pseries_lpar_idle() and honor its result. Fixes: 363edbe2614a ("powerpc: Default arch idle could cede processor on pseries") Signed-off-by: Nathan Lynch Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20190910225244.25056-1-nathanl@linux.ibm.com Signed-off-by: Sasha Levin --- arch/powerpc/platforms/pseries/setup.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 9cc976ff7fec..88fcf6a95fa6 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -369,6 +369,9 @@ static void pseries_lpar_idle(void) * low power mode by cedeing processor to hypervisor */ + if (!prep_irq_for_idle()) + return; + /* Indicate to hypervisor that we are idle. */ get_lppaca()->idle = 1; -- cgit v1.2.3 From 764029c0aaa6c84fb2420cefb15eed7845b411fa Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 1 Aug 2019 15:38:14 -0700 Subject: scsi: core: Reduce memory required for SCSI logging [ Upstream commit dccc96abfb21dc19d69e707c38c8ba439bba7160 ] The data structure used for log messages is so large that it can cause a boot failure. Since allocations from that data structure can fail anyway, use kmalloc() / kfree() instead of that data structure. See also https://bugzilla.kernel.org/show_bug.cgi?id=204119. See also commit ded85c193a39 ("scsi: Implement per-cpu logging buffer") # v4.0. Reported-by: Jan Palus Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Johannes Thumshirn Cc: Ming Lei Cc: Jan Palus Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/scsi_logging.c | 48 +++------------------------------------------ include/scsi/scsi_dbg.h | 2 -- 2 files changed, 3 insertions(+), 47 deletions(-) diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c index bd70339c1242..03d9855a6afd 100644 --- a/drivers/scsi/scsi_logging.c +++ b/drivers/scsi/scsi_logging.c @@ -16,57 +16,15 @@ #include #include -#define SCSI_LOG_SPOOLSIZE 4096 - -#if (SCSI_LOG_SPOOLSIZE / SCSI_LOG_BUFSIZE) > BITS_PER_LONG -#warning SCSI logging bitmask too large -#endif - -struct scsi_log_buf { - char buffer[SCSI_LOG_SPOOLSIZE]; - unsigned long map; -}; - -static DEFINE_PER_CPU(struct scsi_log_buf, scsi_format_log); - static char *scsi_log_reserve_buffer(size_t *len) { - struct scsi_log_buf *buf; - unsigned long map_bits = sizeof(buf->buffer) / SCSI_LOG_BUFSIZE; - unsigned long idx = 0; - - preempt_disable(); - buf = this_cpu_ptr(&scsi_format_log); - idx = find_first_zero_bit(&buf->map, map_bits); - if (likely(idx < map_bits)) { - while (test_and_set_bit(idx, &buf->map)) { - idx = find_next_zero_bit(&buf->map, map_bits, idx); - if (idx >= map_bits) - break; - } - } - if (WARN_ON(idx >= map_bits)) { - preempt_enable(); - return NULL; - } - *len = SCSI_LOG_BUFSIZE; - return buf->buffer + idx * SCSI_LOG_BUFSIZE; + *len = 128; + return kmalloc(*len, GFP_ATOMIC); } static void scsi_log_release_buffer(char *bufptr) { - struct scsi_log_buf *buf; - unsigned long idx; - int ret; - - buf = this_cpu_ptr(&scsi_format_log); - if (bufptr >= buf->buffer && - bufptr < buf->buffer + SCSI_LOG_SPOOLSIZE) { - idx = (bufptr - buf->buffer) / SCSI_LOG_BUFSIZE; - ret = test_and_clear_bit(idx, &buf->map); - WARN_ON(!ret); - } - preempt_enable(); + kfree(bufptr); } static inline const char *scmd_name(const struct scsi_cmnd *scmd) diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h index f8170e90b49d..bbe71a6361db 100644 --- a/include/scsi/scsi_dbg.h +++ b/include/scsi/scsi_dbg.h @@ -5,8 +5,6 @@ struct scsi_cmnd; struct scsi_device; struct scsi_sense_hdr; -#define SCSI_LOG_BUFSIZE 128 - extern void scsi_print_command(struct scsi_cmnd *); extern size_t __scsi_format_command(char *, size_t, const unsigned char *, size_t); -- cgit v1.2.3 From 59610f8b04ef23b7c1f95309d32df6154f7c8671 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Fri, 5 Jul 2019 12:55:03 +0800 Subject: mfd: intel-lpss: Remove D3cold delay [ Upstream commit 76380a607ba0b28627c9b4b55cd47a079a59624b ] Goodix touchpad may drop its first couple input events when i2c-designware-platdrv and intel-lpss it connects to took too long to runtime resume from runtime suspended state. This issue happens becuase the touchpad has a rather small buffer to store up to 13 input events, so if the host doesn't read those events in time (i.e. runtime resume takes too long), events are dropped from the touchpad's buffer. The bottleneck is D3cold delay it waits when transitioning from D3cold to D0, hence remove the delay to make the resume faster. I've tested some systems with intel-lpss and haven't seen any regression. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=202683 Signed-off-by: Kai-Heng Feng Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/mfd/intel-lpss-pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 5bfdfccbb9a1..032c95157497 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -38,6 +38,8 @@ static int intel_lpss_pci_probe(struct pci_dev *pdev, info->mem = &pdev->resource[0]; info->irq = pdev->irq; + pdev->d3cold_delay = 0; + /* Probably it is enough to set this for iDMA capable devices only */ pci_set_master(pdev); -- cgit v1.2.3 From 29f62e3db89f559e2adbb4819abd7d8f82c3c734 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 8 Aug 2019 16:51:00 +0100 Subject: ARM: 8898/1: mm: Don't treat faults reported from cache maintenance as writes [ Upstream commit 834020366da9ab3fb87d1eb9a3160eb22dbed63a ] Translation faults arising from cache maintenance instructions are rather unhelpfully reported with an FSR value where the WnR field is set to 1, indicating that the faulting access was a write. Since cache maintenance instructions on 32-bit ARM do not require any particular permissions, this can cause our private 'cacheflush' system call to fail spuriously if a translation fault is generated due to page aging when targetting a read-only VMA. In this situation, we will return -EFAULT to userspace, although this is unfortunately suppressed by the popular '__builtin___clear_cache()' intrinsic provided by GCC, which returns void. Although it's tempting to write this off as a userspace issue, we can actually do a little bit better on CPUs that support LPAE, even if the short-descriptor format is in use. On these CPUs, cache maintenance faults additionally set the CM field in the FSR, which we can use to suppress the write permission checks in the page fault handler and succeed in performing cache maintenance to read-only areas even in the presence of a translation fault. Reported-by: Orion Hodson Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Sasha Levin --- arch/arm/mm/fault.c | 4 ++-- arch/arm/mm/fault.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 0d20cd594017..702a5542b11a 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -211,7 +211,7 @@ static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma) { unsigned int mask = VM_READ | VM_WRITE | VM_EXEC; - if (fsr & FSR_WRITE) + if ((fsr & FSR_WRITE) && !(fsr & FSR_CM)) mask = VM_WRITE; if (fsr & FSR_LNX_PF) mask = VM_EXEC; @@ -281,7 +281,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) if (user_mode(regs)) flags |= FAULT_FLAG_USER; - if (fsr & FSR_WRITE) + if ((fsr & FSR_WRITE) && !(fsr & FSR_CM)) flags |= FAULT_FLAG_WRITE; /* diff --git a/arch/arm/mm/fault.h b/arch/arm/mm/fault.h index 78830657cab3..b014e5724804 100644 --- a/arch/arm/mm/fault.h +++ b/arch/arm/mm/fault.h @@ -5,6 +5,7 @@ * Fault status register encodings. We steal bit 31 for our own purposes. */ #define FSR_LNX_PF (1 << 31) +#define FSR_CM (1 << 13) #define FSR_WRITE (1 << 11) #define FSR_FS4 (1 << 10) #define FSR_FS3_0 (15) -- cgit v1.2.3 From 9b3458c19b1a74e3e70d8ae1acc86f77fd1ef624 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Tue, 3 Sep 2019 16:46:32 +0200 Subject: HID: apple: Fix stuck function keys when using FN [ Upstream commit aec256d0ecd561036f188dbc8fa7924c47a9edfd ] This fixes an issue in which key down events for function keys would be repeatedly emitted even after the user has raised the physical key. For example, the driver fails to emit the F5 key up event when going through the following steps: - fnmode=1: hold FN, hold F5, release FN, release F5 - fnmode=2: hold F5, hold FN, release F5, release FN The repeated F5 key down events can be easily verified using xev. Signed-off-by: Joao Moreno Co-developed-by: Benjamin Tissoires Signed-off-by: Benjamin Tissoires Signed-off-by: Sasha Levin --- drivers/hid/hid-apple.c | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 884d82f9190e..8af87dc05f2a 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -55,7 +55,6 @@ MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\") struct apple_sc { unsigned long quirks; unsigned int fn_on; - DECLARE_BITMAP(pressed_fn, KEY_CNT); DECLARE_BITMAP(pressed_numlock, KEY_CNT); }; @@ -182,6 +181,8 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, { struct apple_sc *asc = hid_get_drvdata(hid); const struct apple_key_translation *trans, *table; + bool do_translate; + u16 code = 0; if (usage->code == KEY_FN) { asc->fn_on = !!value; @@ -190,8 +191,6 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, } if (fnmode) { - int do_translate; - if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) table = macbookair_fn_keys; @@ -203,25 +202,33 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, trans = apple_find_translation (table, usage->code); if (trans) { - if (test_bit(usage->code, asc->pressed_fn)) - do_translate = 1; - else if (trans->flags & APPLE_FLAG_FKEY) - do_translate = (fnmode == 2 && asc->fn_on) || - (fnmode == 1 && !asc->fn_on); - else - do_translate = asc->fn_on; - - if (do_translate) { - if (value) - set_bit(usage->code, asc->pressed_fn); - else - clear_bit(usage->code, asc->pressed_fn); - - input_event(input, usage->type, trans->to, - value); - - return 1; + if (test_bit(trans->from, input->key)) + code = trans->from; + else if (test_bit(trans->to, input->key)) + code = trans->to; + + if (!code) { + if (trans->flags & APPLE_FLAG_FKEY) { + switch (fnmode) { + case 1: + do_translate = !asc->fn_on; + break; + case 2: + do_translate = asc->fn_on; + break; + default: + /* should never happen */ + do_translate = false; + } + } else { + do_translate = asc->fn_on; + } + + code = do_translate ? trans->to : trans->from; } + + input_event(input, usage->type, code, value); + return 1; } if (asc->quirks & APPLE_NUMLOCK_EMULATION && -- cgit v1.2.3 From 2c84c48466b906c7ce02dabb61fc0f4067604894 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Tue, 23 Jul 2019 18:00:15 +0800 Subject: security: smack: Fix possible null-pointer dereferences in smack_socket_sock_rcv_skb() [ Upstream commit 3f4287e7d98a2954f20bf96c567fdffcd2b63eb9 ] In smack_socket_sock_rcv_skb(), there is an if statement on line 3920 to check whether skb is NULL: if (skb && skb->secmark != 0) This check indicates skb can be NULL in some cases. But on lines 3931 and 3932, skb is used: ad.a.u.net->netif = skb->skb_iif; ipv6_skb_to_auditdata(skb, &ad.a, NULL); Thus, possible null-pointer dereferences may occur when skb is NULL. To fix these possible bugs, an if statement is added to check skb. These bugs are found by a static analysis tool STCheck written by us. Signed-off-by: Jia-Ju Bai Signed-off-by: Casey Schaufler Signed-off-by: Sasha Levin --- security/smack/smack_lsm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 9db7c80a74aa..b76075dbd6fc 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3986,6 +3986,8 @@ access_check: skp = smack_ipv6host_label(&sadd); if (skp == NULL) skp = smack_net_ambient; + if (skb == NULL) + break; #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); ad.a.u.net->family = sk->sk_family; -- cgit v1.2.3 From 5ba8ad0cc3a4f36ac711a08f98c39a6e1c72dfed Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Mon, 23 Sep 2019 15:32:53 -0700 Subject: fat: work around race with userspace's read via blockdev while mounting [ Upstream commit 07bfa4415ab607e459b69bd86aa7e7602ce10b4f ] If userspace reads the buffer via blockdev while mounting, sb_getblk()+modify can race with buffer read via blockdev. For example, FS userspace bh = sb_getblk() modify bh->b_data read ll_rw_block(bh) fill bh->b_data by on-disk data /* lost modified data by FS */ set_buffer_uptodate(bh) set_buffer_uptodate(bh) Userspace should not use the blockdev while mounting though, the udev seems to be already doing this. Although I think the udev should try to avoid this, workaround the race by small overhead. Link: http://lkml.kernel.org/r/87pnk7l3sw.fsf_-_@mail.parknet.co.jp Signed-off-by: OGAWA Hirofumi Reported-by: Jan Stancek Tested-by: Jan Stancek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- fs/fat/dir.c | 13 +++++++++++-- fs/fat/fatent.c | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 8b2127ffb226..9b77e2ad2b59 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -1097,8 +1097,11 @@ static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used, err = -ENOMEM; goto error; } + /* Avoid race with userspace read via bdev */ + lock_buffer(bhs[n]); memset(bhs[n]->b_data, 0, sb->s_blocksize); set_buffer_uptodate(bhs[n]); + unlock_buffer(bhs[n]); mark_buffer_dirty_inode(bhs[n], dir); n++; @@ -1155,6 +1158,8 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts) fat_time_unix2fat(sbi, ts, &time, &date, &time_cs); de = (struct msdos_dir_entry *)bhs[0]->b_data; + /* Avoid race with userspace read via bdev */ + lock_buffer(bhs[0]); /* filling the new directory slots ("." and ".." entries) */ memcpy(de[0].name, MSDOS_DOT, MSDOS_NAME); memcpy(de[1].name, MSDOS_DOTDOT, MSDOS_NAME); @@ -1177,6 +1182,7 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts) de[0].size = de[1].size = 0; memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de)); set_buffer_uptodate(bhs[0]); + unlock_buffer(bhs[0]); mark_buffer_dirty_inode(bhs[0], dir); err = fat_zeroed_cluster(dir, blknr, 1, bhs, MAX_BUF_PER_PAGE); @@ -1234,11 +1240,14 @@ static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots, /* fill the directory entry */ copy = min(size, sb->s_blocksize); + /* Avoid race with userspace read via bdev */ + lock_buffer(bhs[n]); memcpy(bhs[n]->b_data, slots, copy); - slots += copy; - size -= copy; set_buffer_uptodate(bhs[n]); + unlock_buffer(bhs[n]); mark_buffer_dirty_inode(bhs[n], dir); + slots += copy; + size -= copy; if (!size) break; n++; diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index e3fc477728b3..be8529739d23 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c @@ -389,8 +389,11 @@ static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs, err = -ENOMEM; goto error; } + /* Avoid race with userspace read via bdev */ + lock_buffer(c_bh); memcpy(c_bh->b_data, bhs[n]->b_data, sb->s_blocksize); set_buffer_uptodate(c_bh); + unlock_buffer(c_bh); mark_buffer_dirty_inode(c_bh, sbi->fat_inode); if (sb->s_flags & MS_SYNCHRONOUS) err = sync_dirty_buffer(c_bh); -- cgit v1.2.3 From fe276165b08188616fca013b3df0f7373e8d51dd Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 21 Mar 2019 10:08:08 +0000 Subject: hypfs: Fix error number left in struct pointer member [ Upstream commit b54c64f7adeb241423cd46598f458b5486b0375e ] In hypfs_fill_super(), if hypfs_create_update_file() fails, sbi->update_file is left holding an error number. This is passed to hypfs_kill_super() which doesn't check for this. Fix this by not setting sbi->update_value until after we've checked for error. Fixes: 24bbb1faf3f0 ("[PATCH] s390_hypfs filesystem") Signed-off-by: David Howells cc: Martin Schwidefsky cc: Heiko Carstens cc: linux-s390@vger.kernel.org Signed-off-by: Al Viro Signed-off-by: Sasha Levin --- arch/s390/hypfs/inode.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index c670279b33f0..1de3fdfc3537 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -267,7 +267,7 @@ static int hypfs_show_options(struct seq_file *s, struct dentry *root) static int hypfs_fill_super(struct super_block *sb, void *data, int silent) { struct inode *root_inode; - struct dentry *root_dentry; + struct dentry *root_dentry, *update_file; int rc = 0; struct hypfs_sb_info *sbi; @@ -298,9 +298,10 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent) rc = hypfs_diag_create_files(root_dentry); if (rc) return rc; - sbi->update_file = hypfs_create_update_file(root_dentry); - if (IS_ERR(sbi->update_file)) - return PTR_ERR(sbi->update_file); + update_file = hypfs_create_update_file(root_dentry); + if (IS_ERR(update_file)) + return PTR_ERR(update_file); + sbi->update_file = update_file; hypfs_update_update(sb); pr_info("Hypervisor filesystem mounted\n"); return 0; -- cgit v1.2.3 From 68fb386f396a1d48847b9afd5b936016ee797c3c Mon Sep 17 00:00:00 2001 From: Changwei Ge Date: Mon, 23 Sep 2019 15:33:37 -0700 Subject: ocfs2: wait for recovering done after direct unlock request [ Upstream commit 0a3775e4f883912944481cf2ef36eb6383a9cc74 ] There is a scenario causing ocfs2 umount hang when multiple hosts are rebooting at the same time. NODE1 NODE2 NODE3 send unlock requset to NODE2 dies become recovery master recover NODE2 find NODE2 dead mark resource RECOVERING directly remove lock from grant list calculate usage but RECOVERING marked **miss the window of purging clear RECOVERING To reproduce this issue, crash a host and then umount ocfs2 from another node. To solve this, just let unlock progress wait for recovery done. Link: http://lkml.kernel.org/r/1550124866-20367-1-git-send-email-gechangwei@live.cn Signed-off-by: Changwei Ge Reviewed-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Cc: Changwei Ge Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- fs/ocfs2/dlm/dlmunlock.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/fs/ocfs2/dlm/dlmunlock.c b/fs/ocfs2/dlm/dlmunlock.c index 2e3c9dbab68c..d137d4692b91 100644 --- a/fs/ocfs2/dlm/dlmunlock.c +++ b/fs/ocfs2/dlm/dlmunlock.c @@ -105,7 +105,8 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm, enum dlm_status status; int actions = 0; int in_use; - u8 owner; + u8 owner; + int recovery_wait = 0; mlog(0, "master_node = %d, valblk = %d\n", master_node, flags & LKM_VALBLK); @@ -208,9 +209,12 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm, } if (flags & LKM_CANCEL) lock->cancel_pending = 0; - else - lock->unlock_pending = 0; - + else { + if (!lock->unlock_pending) + recovery_wait = 1; + else + lock->unlock_pending = 0; + } } /* get an extra ref on lock. if we are just switching @@ -244,6 +248,17 @@ leave: spin_unlock(&res->spinlock); wake_up(&res->wq); + if (recovery_wait) { + spin_lock(&res->spinlock); + /* Unlock request will directly succeed after owner dies, + * and the lock is already removed from grant list. We have to + * wait for RECOVERING done or we miss the chance to purge it + * since the removement is much faster than RECOVERING proc. + */ + __dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_RECOVERING); + spin_unlock(&res->spinlock); + } + /* let the caller's final dlm_lock_put handle the actual kfree */ if (actions & DLM_UNLOCK_FREE_LOCK) { /* this should always be coupled with list removal */ -- cgit v1.2.3 From 9add3e08a8fd21429643796e5b989da20e7acf66 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Mon, 23 Sep 2019 15:33:55 -0700 Subject: kmemleak: increase DEBUG_KMEMLEAK_EARLY_LOG_SIZE default to 16K [ Upstream commit b751c52bb587ae66f773b15204ef7a147467f4c7 ] The current default value (400) is too low on many systems (e.g. some ARM64 platform takes up 1000+ entries). syzbot uses 16000 as default value, and has proved to be enough on beefy configurations, so let's pick that value. This consumes more RAM on boot (each entry is 160 bytes, so in total ~2.5MB of RAM), but the memory would later be freed (early_log is __initdata). Link: http://lkml.kernel.org/r/20190730154027.101525-1-drinkcat@chromium.org Signed-off-by: Nicolas Boichat Suggested-by: Dmitry Vyukov Acked-by: Catalin Marinas Acked-by: Dmitry Vyukov Cc: Masahiro Yamada Cc: Kees Cook Cc: Petr Mladek Cc: Thomas Gleixner Cc: Tetsuo Handa Cc: Joe Lawrence Cc: Uladzislau Rezki Cc: Andy Shevchenko Cc: Stephen Rothwell Cc: Andrey Ryabinin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- lib/Kconfig.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index fd1205a3dbdb..7b9d7328f189 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -521,7 +521,7 @@ config DEBUG_KMEMLEAK_EARLY_LOG_SIZE int "Maximum kmemleak early log entries" depends on DEBUG_KMEMLEAK range 200 40000 - default 400 + default 16000 help Kmemleak must track all the memory allocations to avoid reporting false positives. Since memory may be allocated or -- cgit v1.2.3 From 80eb98a4ee70428d5b4b7202195a916385a76809 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 5 Jan 2018 11:27:07 +0100 Subject: ANDROID: binder: remove waitqueue when thread exits. commit f5cb779ba16334b45ba8946d6bfa6d9834d1527f upstream. binder_poll() passes the thread->wait waitqueue that can be slept on for work. When a thread that uses epoll explicitly exits using BINDER_THREAD_EXIT, the waitqueue is freed, but it is never removed from the corresponding epoll data structure. When the process subsequently exits, the epoll cleanup code tries to access the waitlist, which results in a use-after-free. Prevent this by using POLLFREE when the thread exits. Signed-off-by: Martijn Coenen Reported-by: syzbot Cc: stable # 4.14 [backport BINDER_LOOPER_STATE_POLL logic as well] Signed-off-by: Mattias Nissler Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 01eb2a2a3746..5c13a6eb4fea 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -334,7 +334,8 @@ enum { BINDER_LOOPER_STATE_EXITED = 0x04, BINDER_LOOPER_STATE_INVALID = 0x08, BINDER_LOOPER_STATE_WAITING = 0x10, - BINDER_LOOPER_STATE_NEED_RETURN = 0x20 + BINDER_LOOPER_STATE_NEED_RETURN = 0x20, + BINDER_LOOPER_STATE_POLL = 0x40, }; struct binder_thread { @@ -2610,6 +2611,18 @@ static int binder_free_thread(struct binder_proc *proc, } else BUG(); } + + /* + * If this thread used poll, make sure we remove the waitqueue + * from any epoll data structures holding it with POLLFREE. + * waitqueue_active() is safe to use here because we're holding + * the global lock. + */ + if ((thread->looper & BINDER_LOOPER_STATE_POLL) && + waitqueue_active(&thread->wait)) { + wake_up_poll(&thread->wait, POLLHUP | POLLFREE); + } + if (send_reply) binder_send_failed_reply(send_reply, BR_DEAD_REPLY); binder_release_work(&thread->todo); @@ -2633,6 +2646,8 @@ static unsigned int binder_poll(struct file *filp, return POLLERR; } + thread->looper |= BINDER_LOOPER_STATE_POLL; + wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo) && thread->return_error == BR_OK; -- cgit v1.2.3 From fcf46dcedbc419633771e16bfdf97a528f4d7dab Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 16 Feb 2018 09:47:15 +0100 Subject: ANDROID: binder: synchronize_rcu() when using POLLFREE. commit 5eeb2ca02a2f6084fc57ae5c244a38baab07033a upstream. To prevent races with ep_remove_waitqueue() removing the waitqueue at the same time. Reported-by: syzbot+a2a3c4909716e271487e@syzkaller.appspotmail.com Signed-off-by: Martijn Coenen Cc: stable # 4.14+ Signed-off-by: Mattias Nissler Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 5c13a6eb4fea..39e458b3c532 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2623,6 +2623,15 @@ static int binder_free_thread(struct binder_proc *proc, wake_up_poll(&thread->wait, POLLHUP | POLLFREE); } + /* + * This is needed to avoid races between wake_up_poll() above and + * and ep_remove_waitqueue() called for other reasons (eg the epoll file + * descriptor being closed); ep_remove_waitqueue() holds an RCU read + * lock, so we can be sure it's done after calling synchronize_rcu(). + */ + if (thread->looper & BINDER_LOOPER_STATE_POLL) + synchronize_rcu(); + if (send_reply) binder_send_failed_reply(send_reply, BR_DEAD_REPLY); binder_release_work(&thread->todo); -- cgit v1.2.3 From 8e3dadbf40d6819597ce6a91289dcceca2a7e416 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 30 Sep 2019 17:12:41 +0200 Subject: hso: fix NULL-deref on tty open [ Upstream commit 8353da9fa69722b54cba82b2ec740afd3d438748 ] Fix NULL-pointer dereference on tty open due to a failure to handle a missing interrupt-in endpoint when probing modem ports: BUG: kernel NULL pointer dereference, address: 0000000000000006 ... RIP: 0010:tiocmget_submit_urb+0x1c/0xe0 [hso] ... Call Trace: hso_start_serial_device+0xdc/0x140 [hso] hso_serial_open+0x118/0x1b0 [hso] tty_open+0xf1/0x490 Fixes: 542f54823614 ("tty: Modem functions for the HSO driver") Signed-off-by: Johan Hovold Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/hso.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 79cede19e0c4..cbbff16d438f 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2650,14 +2650,18 @@ static struct hso_device *hso_create_bulk_serial_device( */ if (serial->tiocmget) { tiocmget = serial->tiocmget; + tiocmget->endp = hso_get_ep(interface, + USB_ENDPOINT_XFER_INT, + USB_DIR_IN); + if (!tiocmget->endp) { + dev_err(&interface->dev, "Failed to find INT IN ep\n"); + goto exit; + } + tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL); if (tiocmget->urb) { mutex_init(&tiocmget->mutex); init_waitqueue_head(&tiocmget->waitq); - tiocmget->endp = hso_get_ep( - interface, - USB_ENDPOINT_XFER_INT, - USB_DIR_IN); } else hso_free_tiomget(serial); } -- cgit v1.2.3 From 31849614f85e7603f64d533b164d94c92e48e7c2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Oct 2019 09:38:55 -0700 Subject: ipv6: drop incoming packets having a v4mapped source address [ Upstream commit 6af1799aaf3f1bc8defedddfa00df3192445bbf3 ] This began with a syzbot report. syzkaller was injecting IPv6 TCP SYN packets having a v4mapped source address. After an unsuccessful 4-tuple lookup, TCP creates a request socket (SYN_RECV) and calls reqsk_queue_hash_req() reqsk_queue_hash_req() calls sk_ehashfn(sk) At this point we have AF_INET6 sockets, and the heuristic used by sk_ehashfn() to either hash the IPv4 or IPv6 addresses is to use ipv6_addr_v4mapped(&sk->sk_v6_daddr) For the particular spoofed packet, we end up hashing V4 addresses which were not initialized by the TCP IPv6 stack, so KMSAN fired a warning. I first fixed sk_ehashfn() to test both source and destination addresses, but then faced various problems, including user-space programs like packetdrill that had similar assumptions. Instead of trying to fix the whole ecosystem, it is better to admit that we have a dual stack behavior, and that we can not build linux kernels without V4 stack anyway. The dual stack API automatically forces the traffic to be IPv4 if v4mapped addresses are used at bind() or connect(), so it makes no sense to allow IPv6 traffic to use the same v4mapped class. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Cc: Florian Westphal Cc: Hannes Frederic Sowa Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_input.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 9075acf081dd..c83c0faf5ae9 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -151,6 +151,16 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt if (ipv6_addr_is_multicast(&hdr->saddr)) goto err; + /* While RFC4291 is not explicit about v4mapped addresses + * in IPv6 headers, it seems clear linux dual-stack + * model can not deal properly with these. + * Security models could be fooled by ::ffff:127.0.0.1 for example. + * + * https://tools.ietf.org/html/draft-itojun-v6ops-v4mapped-harmful-02 + */ + if (ipv6_addr_v4mapped(&hdr->saddr)) + goto err; + skb->transport_header = skb->network_header + sizeof(*hdr); IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); -- cgit v1.2.3 From 7b1341b8e51120cb2f64292ce7a48bf413698401 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 4 Oct 2019 15:11:17 +0200 Subject: net: ipv4: avoid mixed n_redirects and rate_tokens usage [ Upstream commit b406472b5ad79ede8d10077f0c8f05505ace8b6d ] Since commit c09551c6ff7f ("net: ipv4: use a dedicated counter for icmp_v4 redirect packets") we use 'n_redirects' to account for redirect packets, but we still use 'rate_tokens' to compute the redirect packets exponential backoff. If the device sent to the relevant peer any ICMP error packet after sending a redirect, it will also update 'rate_token' according to the leaking bucket schema; typically 'rate_token' will raise above BITS_PER_LONG and the redirect packets backoff algorithm will produce undefined behavior. Fix the issue using 'n_redirects' to compute the exponential backoff in ip_rt_send_redirect(). Note that we still clear rate_tokens after a redirect silence period, to avoid changing an established behaviour. The root cause predates git history; before the mentioned commit in the critical scenario, the kernel stopped sending redirects, after the mentioned commit the behavior more randomic. Reported-by: Xiumei Mu Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Fixes: c09551c6ff7f ("net: ipv4: use a dedicated counter for icmp_v4 redirect packets") Signed-off-by: Paolo Abeni Acked-by: Lorenzo Bianconi Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/route.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 3c605a788ba1..a60078de1191 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -897,16 +897,15 @@ void ip_rt_send_redirect(struct sk_buff *skb) if (peer->rate_tokens == 0 || time_after(jiffies, (peer->rate_last + - (ip_rt_redirect_load << peer->rate_tokens)))) { + (ip_rt_redirect_load << peer->n_redirects)))) { __be32 gw = rt_nexthop(rt, ip_hdr(skb)->daddr); icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, gw); peer->rate_last = jiffies; - ++peer->rate_tokens; ++peer->n_redirects; #ifdef CONFIG_IP_ROUTE_VERBOSE if (log_martians && - peer->rate_tokens == ip_rt_redirect_number) + peer->n_redirects == ip_rt_redirect_number) net_warn_ratelimited("host %pI4/if%d ignores redirects for %pI4 to %pI4\n", &ip_hdr(skb)->saddr, inet_iif(skb), &ip_hdr(skb)->daddr, &gw); -- cgit v1.2.3 From a35f1bb8c300a46c194bb5154ee8fc040c5ae392 Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Fri, 4 Oct 2019 15:24:39 -0500 Subject: net: qlogic: Fix memory leak in ql_alloc_large_buffers [ Upstream commit 1acb8f2a7a9f10543868ddd737e37424d5c36cf4 ] In ql_alloc_large_buffers, a new skb is allocated via netdev_alloc_skb. This skb should be released if pci_dma_mapping_error fails. Fixes: 0f8ab89e825f ("qla3xxx: Check return code from pci_map_single() in ql_release_to_lrg_buf_free_list(), ql_populate_free_queue(), ql_alloc_large_buffers(), and ql3xxx_send()") Signed-off-by: Navid Emamdoost Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qla3xxx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c index 355c5fb802cd..c653b97d84d5 100644 --- a/drivers/net/ethernet/qlogic/qla3xxx.c +++ b/drivers/net/ethernet/qlogic/qla3xxx.c @@ -2783,6 +2783,7 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev) netdev_err(qdev->ndev, "PCI mapping failed with error: %d\n", err); + dev_kfree_skb_irq(skb); ql_free_large_buffers(qdev); return -ENOMEM; } -- cgit v1.2.3 From 031183e85d5f7639bacd408052c2bd4643952b10 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 4 Oct 2019 11:08:34 -0700 Subject: nfc: fix memory leak in llcp_sock_bind() [ Upstream commit a0c2dc1fe63e2869b74c1c7f6a81d1745c8a695d ] sysbot reported a memory leak after a bind() has failed. While we are at it, abort the operation if kmemdup() has failed. BUG: memory leak unreferenced object 0xffff888105d83ec0 (size 32): comm "syz-executor067", pid 7207, jiffies 4294956228 (age 19.430s) hex dump (first 32 bytes): 00 69 6c 65 20 72 65 61 64 00 6e 65 74 3a 5b 34 .ile read.net:[4 30 32 36 35 33 33 30 39 37 5d 00 00 00 00 00 00 026533097]...... backtrace: [<0000000036bac473>] kmemleak_alloc_recursive /./include/linux/kmemleak.h:43 [inline] [<0000000036bac473>] slab_post_alloc_hook /mm/slab.h:522 [inline] [<0000000036bac473>] slab_alloc /mm/slab.c:3319 [inline] [<0000000036bac473>] __do_kmalloc /mm/slab.c:3653 [inline] [<0000000036bac473>] __kmalloc_track_caller+0x169/0x2d0 /mm/slab.c:3670 [<000000000cd39d07>] kmemdup+0x27/0x60 /mm/util.c:120 [<000000008e57e5fc>] kmemdup /./include/linux/string.h:432 [inline] [<000000008e57e5fc>] llcp_sock_bind+0x1b3/0x230 /net/nfc/llcp_sock.c:107 [<000000009cb0b5d3>] __sys_bind+0x11c/0x140 /net/socket.c:1647 [<00000000492c3bbc>] __do_sys_bind /net/socket.c:1658 [inline] [<00000000492c3bbc>] __se_sys_bind /net/socket.c:1656 [inline] [<00000000492c3bbc>] __x64_sys_bind+0x1e/0x30 /net/socket.c:1656 [<0000000008704b2a>] do_syscall_64+0x76/0x1a0 /arch/x86/entry/common.c:296 [<000000009f4c57a4>] entry_SYSCALL_64_after_hwframe+0x44/0xa9 Fixes: 30cc4587659e ("NFC: Move LLCP code to the NFC top level diirectory") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/nfc/llcp_sock.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c index 2dfd1c815203..44d6b8355eab 100644 --- a/net/nfc/llcp_sock.c +++ b/net/nfc/llcp_sock.c @@ -118,9 +118,14 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) llcp_sock->service_name = kmemdup(llcp_addr.service_name, llcp_sock->service_name_len, GFP_KERNEL); - + if (!llcp_sock->service_name) { + ret = -ENOMEM; + goto put_dev; + } llcp_sock->ssap = nfc_llcp_get_sdp_ssap(local, llcp_sock); if (llcp_sock->ssap == LLCP_SAP_MAX) { + kfree(llcp_sock->service_name); + llcp_sock->service_name = NULL; ret = -EADDRINUSE; goto put_dev; } -- cgit v1.2.3 From f411ce0169132c21c89e0546ea8be469808724d9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 4 Oct 2019 10:34:45 -0700 Subject: sch_dsmark: fix potential NULL deref in dsmark_init() [ Upstream commit 474f0813a3002cb299bb73a5a93aa1f537a80ca8 ] Make sure TCA_DSMARK_INDICES was provided by the user. syzbot reported : kasan: CONFIG_KASAN_INLINE enabled kasan: GPF could be caused by NULL-ptr deref or user memory access general protection fault: 0000 [#1] PREEMPT SMP KASAN CPU: 1 PID: 8799 Comm: syz-executor235 Not tainted 5.3.0+ #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:nla_get_u16 include/net/netlink.h:1501 [inline] RIP: 0010:dsmark_init net/sched/sch_dsmark.c:364 [inline] RIP: 0010:dsmark_init+0x193/0x640 net/sched/sch_dsmark.c:339 Code: 85 db 58 0f 88 7d 03 00 00 e8 e9 1a ac fb 48 8b 9d 70 ff ff ff 48 b8 00 00 00 00 00 fc ff df 48 8d 7b 04 48 89 fa 48 c1 ea 03 <0f> b6 14 02 48 89 f8 83 e0 07 83 c0 01 38 d0 7c 08 84 d2 0f 85 ca RSP: 0018:ffff88809426f3b8 EFLAGS: 00010247 RAX: dffffc0000000000 RBX: 0000000000000000 RCX: ffffffff85c6eb09 RDX: 0000000000000000 RSI: ffffffff85c6eb17 RDI: 0000000000000004 RBP: ffff88809426f4b0 R08: ffff88808c4085c0 R09: ffffed1015d26159 R10: ffffed1015d26158 R11: ffff8880ae930ac7 R12: ffff8880a7e96940 R13: dffffc0000000000 R14: ffff88809426f8c0 R15: 0000000000000000 FS: 0000000001292880(0000) GS:ffff8880ae900000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000020000080 CR3: 000000008ca1b000 CR4: 00000000001406e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: qdisc_create+0x4ee/0x1210 net/sched/sch_api.c:1237 tc_modify_qdisc+0x524/0x1c50 net/sched/sch_api.c:1653 rtnetlink_rcv_msg+0x463/0xb00 net/core/rtnetlink.c:5223 netlink_rcv_skb+0x177/0x450 net/netlink/af_netlink.c:2477 rtnetlink_rcv+0x1d/0x30 net/core/rtnetlink.c:5241 netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline] netlink_unicast+0x531/0x710 net/netlink/af_netlink.c:1328 netlink_sendmsg+0x8a5/0xd60 net/netlink/af_netlink.c:1917 sock_sendmsg_nosec net/socket.c:637 [inline] sock_sendmsg+0xd7/0x130 net/socket.c:657 ___sys_sendmsg+0x803/0x920 net/socket.c:2311 __sys_sendmsg+0x105/0x1d0 net/socket.c:2356 __do_sys_sendmsg net/socket.c:2365 [inline] __se_sys_sendmsg net/socket.c:2363 [inline] __x64_sys_sendmsg+0x78/0xb0 net/socket.c:2363 do_syscall_64+0xfa/0x760 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x440369 Fixes: 758cc43c6d73 ("[PKT_SCHED]: Fix dsmark to apply changes consistent") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_dsmark.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index cce4e6ada7fa..5f8f6d94336c 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -362,6 +362,8 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt) goto errout; err = -EINVAL; + if (!tb[TCA_DSMARK_INDICES]) + goto errout; indices = nla_get_u16(tb[TCA_DSMARK_INDICES]); if (hweight32(indices) != 1) -- cgit v1.2.3 From ac37c4e04728a947e40f499fc648af16ea3c5bab Mon Sep 17 00:00:00 2001 From: Dongli Zhang Date: Tue, 1 Oct 2019 21:56:41 +0800 Subject: xen-netfront: do not use ~0U as error return value for xennet_fill_frags() [ Upstream commit a761129e3625688310aecf26e1be9e98e85f8eb5 ] xennet_fill_frags() uses ~0U as return value when the sk_buff is not able to cache extra fragments. This is incorrect because the return type of xennet_fill_frags() is RING_IDX and 0xffffffff is an expected value for ring buffer index. In the situation when the rsp_cons is approaching 0xffffffff, the return value of xennet_fill_frags() may become 0xffffffff which xennet_poll() (the caller) would regard as error. As a result, queue->rx.rsp_cons is set incorrectly because it is updated only when there is error. If there is no error, xennet_poll() would be responsible to update queue->rx.rsp_cons. Finally, queue->rx.rsp_cons would point to the rx ring buffer entries whose queue->rx_skbs[i] and queue->grant_rx_ref[i] are already cleared to NULL. This leads to NULL pointer access in the next iteration to process rx ring buffer entries. The symptom is similar to the one fixed in commit 00b368502d18 ("xen-netfront: do not assume sk_buff_head list is empty in error handling"). This patch changes the return type of xennet_fill_frags() to indicate whether it is successful or failed. The queue->rx.rsp_cons will be always updated inside this function. Fixes: ad4f15dc2c70 ("xen/netfront: don't bug in case of too many frags") Signed-off-by: Dongli Zhang Reviewed-by: Juergen Gross Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netfront.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 574c93a24180..89eec6fead75 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -874,9 +874,9 @@ static int xennet_set_skb_gso(struct sk_buff *skb, return 0; } -static RING_IDX xennet_fill_frags(struct netfront_queue *queue, - struct sk_buff *skb, - struct sk_buff_head *list) +static int xennet_fill_frags(struct netfront_queue *queue, + struct sk_buff *skb, + struct sk_buff_head *list) { RING_IDX cons = queue->rx.rsp_cons; struct sk_buff *nskb; @@ -895,7 +895,7 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue, if (unlikely(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) { queue->rx.rsp_cons = ++cons + skb_queue_len(list); kfree_skb(nskb); - return ~0U; + return -ENOENT; } skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, @@ -906,7 +906,9 @@ static RING_IDX xennet_fill_frags(struct netfront_queue *queue, kfree_skb(nskb); } - return cons; + queue->rx.rsp_cons = cons; + + return 0; } static int checksum_setup(struct net_device *dev, struct sk_buff *skb) @@ -1032,8 +1034,7 @@ err: skb->data_len = rx->status; skb->len += rx->status; - i = xennet_fill_frags(queue, skb, &tmpq); - if (unlikely(i == ~0U)) + if (unlikely(xennet_fill_frags(queue, skb, &tmpq))) goto err; if (rx->flags & XEN_NETRXF_csum_blank) @@ -1043,7 +1044,7 @@ err: __skb_queue_tail(&rxq, skb); - queue->rx.rsp_cons = ++i; + i = ++queue->rx.rsp_cons; work_done++; } -- cgit v1.2.3 From fc9752bceab7c82eedda865f71bca220498294cb Mon Sep 17 00:00:00 2001 From: Dotan Barak Date: Tue, 1 Oct 2019 10:21:02 -0700 Subject: net/rds: Fix error handling in rds_ib_add_one() [ Upstream commit d64bf89a75b65f83f06be9fb8f978e60d53752db ] rds_ibdev:ipaddr_list and rds_ibdev:conn_list are initialized after allocation some resources such as protection domain. If allocation of such resources fail, then these uninitialized variables are accessed in rds_ib_dev_free() in failure path. This can potentially crash the system. The code has been updated to initialize these variables very early in the function. Signed-off-by: Dotan Barak Signed-off-by: Sudhakar Dindukurti Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/rds/ib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/rds/ib.c b/net/rds/ib.c index ed51ccc84b3a..aa5f75d4880c 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c @@ -146,6 +146,9 @@ static void rds_ib_add_one(struct ib_device *device) atomic_set(&rds_ibdev->refcount, 1); INIT_WORK(&rds_ibdev->free_work, rds_ib_dev_free); + INIT_LIST_HEAD(&rds_ibdev->ipaddr_list); + INIT_LIST_HEAD(&rds_ibdev->conn_list); + rds_ibdev->max_wrs = dev_attr->max_qp_wr; rds_ibdev->max_sge = min(dev_attr->max_sge, RDS_IB_MAX_SGE); @@ -187,9 +190,6 @@ static void rds_ib_add_one(struct ib_device *device) rds_ibdev->fmr_max_remaps, rds_ibdev->max_1m_fmrs, rds_ibdev->max_8k_fmrs); - INIT_LIST_HEAD(&rds_ibdev->ipaddr_list); - INIT_LIST_HEAD(&rds_ibdev->conn_list); - down_write(&rds_ib_devices_lock); list_add_tail_rcu(&rds_ibdev->list, &rds_ib_devices); up_write(&rds_ib_devices_lock); -- cgit v1.2.3 From 3aa452bf9baa11cf99a8913eaf0ed98a06cf6493 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 26 Sep 2019 18:24:43 -0700 Subject: sch_cbq: validate TCA_CBQ_WRROPT to avoid crash [ Upstream commit e9789c7cc182484fc031fd88097eb14cb26c4596 ] syzbot reported a crash in cbq_normalize_quanta() caused by an out of range cl->priority. iproute2 enforces this check, but malicious users do not. kasan: CONFIG_KASAN_INLINE enabled kasan: GPF could be caused by NULL-ptr deref or user memory access general protection fault: 0000 [#1] SMP KASAN PTI Modules linked in: CPU: 1 PID: 26447 Comm: syz-executor.1 Not tainted 5.3+ #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:cbq_normalize_quanta.part.0+0x1fd/0x430 net/sched/sch_cbq.c:902 RSP: 0018:ffff8801a5c333b0 EFLAGS: 00010206 RAX: 0000000020000003 RBX: 00000000fffffff8 RCX: ffffc9000712f000 RDX: 00000000000043bf RSI: ffffffff83be8962 RDI: 0000000100000018 RBP: ffff8801a5c33420 R08: 000000000000003a R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: 00000000000002ef R13: ffff88018da95188 R14: dffffc0000000000 R15: 0000000000000015 FS: 00007f37d26b1700(0000) GS:ffff8801dad00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000004c7cec CR3: 00000001bcd0a006 CR4: 00000000001626f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: [] cbq_normalize_quanta include/net/pkt_sched.h:27 [inline] [] cbq_addprio net/sched/sch_cbq.c:1097 [inline] [] cbq_set_wrr+0x2d7/0x450 net/sched/sch_cbq.c:1115 [] cbq_change_class+0x987/0x225b net/sched/sch_cbq.c:1537 [] tc_ctl_tclass+0x555/0xcd0 net/sched/sch_api.c:2329 [] rtnetlink_rcv_msg+0x485/0xc10 net/core/rtnetlink.c:5248 [] netlink_rcv_skb+0x17a/0x460 net/netlink/af_netlink.c:2510 [] rtnetlink_rcv+0x1d/0x30 net/core/rtnetlink.c:5266 [] netlink_unicast_kernel net/netlink/af_netlink.c:1324 [inline] [] netlink_unicast+0x536/0x720 net/netlink/af_netlink.c:1350 [] netlink_sendmsg+0x89a/0xd50 net/netlink/af_netlink.c:1939 [] sock_sendmsg_nosec net/socket.c:673 [inline] [] sock_sendmsg+0x12e/0x170 net/socket.c:684 [] ___sys_sendmsg+0x81d/0x960 net/socket.c:2359 [] __sys_sendmsg+0x105/0x1d0 net/socket.c:2397 [] SYSC_sendmsg net/socket.c:2406 [inline] [] SyS_sendmsg+0x29/0x30 net/socket.c:2404 [] do_syscall_64+0x528/0x770 arch/x86/entry/common.c:305 [] entry_SYSCALL_64_after_hwframe+0x42/0xb7 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_cbq.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index baafddf229ce..8182f9bc197c 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1340,6 +1340,26 @@ static const struct nla_policy cbq_policy[TCA_CBQ_MAX + 1] = { [TCA_CBQ_POLICE] = { .len = sizeof(struct tc_cbq_police) }, }; +static int cbq_opt_parse(struct nlattr *tb[TCA_CBQ_MAX + 1], struct nlattr *opt) +{ + int err; + + if (!opt) + return -EINVAL; + + err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy); + if (err < 0) + return err; + + if (tb[TCA_CBQ_WRROPT]) { + const struct tc_cbq_wrropt *wrr = nla_data(tb[TCA_CBQ_WRROPT]); + + if (wrr->priority > TC_CBQ_MAXPRIO) + err = -EINVAL; + } + return err; +} + static int cbq_init(struct Qdisc *sch, struct nlattr *opt) { struct cbq_sched_data *q = qdisc_priv(sch); @@ -1347,7 +1367,7 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt) struct tc_ratespec *r; int err; - err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy); + err = cbq_opt_parse(tb, opt); if (err < 0) return err; @@ -1728,10 +1748,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t struct cbq_class *parent; struct qdisc_rate_table *rtab = NULL; - if (opt == NULL) - return -EINVAL; - - err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy); + err = cbq_opt_parse(tb, opt); if (err < 0) return err; -- cgit v1.2.3 From cfaf71c99319a0ebec6f736ac5b400099257ae1b Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Thu, 4 Jul 2019 20:44:44 +0200 Subject: Smack: Don't ignore other bprm->unsafe flags if LSM_UNSAFE_PTRACE is set commit 3675f052b43ba51b99b85b073c7070e083f3e6fb upstream. There is a logic bug in the current smack_bprm_set_creds(): If LSM_UNSAFE_PTRACE is set, but the ptrace state is deemed to be acceptable (e.g. because the ptracer detached in the meantime), the other ->unsafe flags aren't checked. As far as I can tell, this means that something like the following could work (but I haven't tested it): - task A: create task B with fork() - task B: set NO_NEW_PRIVS - task B: install a seccomp filter that makes open() return 0 under some conditions - task B: replace fd 0 with a malicious library - task A: attach to task B with PTRACE_ATTACH - task B: execve() a file with an SMACK64EXEC extended attribute - task A: while task B is still in the middle of execve(), exit (which destroys the ptrace relationship) Make sure that if any flags other than LSM_UNSAFE_PTRACE are set in bprm->unsafe, we reject the execve(). Cc: stable@vger.kernel.org Fixes: 5663884caab1 ("Smack: unify all ptrace accesses in the smack") Signed-off-by: Jann Horn Signed-off-by: Casey Schaufler Signed-off-by: Greg Kroah-Hartman --- security/smack/smack_lsm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index b76075dbd6fc..3055188729e6 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -932,7 +932,8 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) if (rc != 0) return rc; - } else if (bprm->unsafe) + } + if (bprm->unsafe & ~LSM_UNSAFE_PTRACE) return -EPERM; bsp->smk_task = isp->smk_task; -- cgit v1.2.3 From ac375073bb395750edd1652e420131acfc5b08d5 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 21 Aug 2019 22:54:41 -0700 Subject: smack: use GFP_NOFS while holding inode_smack::smk_lock commit e5bfad3d7acc5702f32aafeb388362994f4d7bd0 upstream. inode_smack::smk_lock is taken during smack_d_instantiate(), which is called during a filesystem transaction when creating a file on ext4. Therefore to avoid a deadlock, all code that takes this lock must use GFP_NOFS, to prevent memory reclaim from waiting for the filesystem transaction to complete. Reported-by: syzbot+0eefc1e06a77d327a056@syzkaller.appspotmail.com Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Signed-off-by: Casey Schaufler Signed-off-by: Greg Kroah-Hartman --- security/smack/smack_access.c | 4 ++-- security/smack/smack_lsm.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index a283f9e796c1..0df316c62005 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -474,7 +474,7 @@ char *smk_parse_smack(const char *string, int len) if (i == 0 || i >= SMK_LONGLABEL) return ERR_PTR(-EINVAL); - smack = kzalloc(i + 1, GFP_KERNEL); + smack = kzalloc(i + 1, GFP_NOFS); if (smack == NULL) return ERR_PTR(-ENOMEM); @@ -545,7 +545,7 @@ struct smack_known *smk_import_entry(const char *string, int len) if (skp != NULL) goto freeout; - skp = kzalloc(sizeof(*skp), GFP_KERNEL); + skp = kzalloc(sizeof(*skp), GFP_NOFS); if (skp == NULL) { skp = ERR_PTR(-ENOMEM); goto freeout; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 3055188729e6..716433e63052 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -268,7 +268,7 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip, if (ip->i_op->getxattr == NULL) return ERR_PTR(-EOPNOTSUPP); - buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL); + buffer = kzalloc(SMK_LONGLABEL, GFP_NOFS); if (buffer == NULL) return ERR_PTR(-ENOMEM); -- cgit v1.2.3 From 2e486758901d321f2412a928a7383d099119837c Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Mon, 29 Jul 2019 16:35:01 +0300 Subject: NFC: fix attrs checks in netlink interface commit 18917d51472fe3b126a3a8f756c6b18085eb8130 upstream. nfc_genl_deactivate_target() relies on the NFC_ATTR_TARGET_INDEX attribute being present, but doesn't check whether it is actually provided by the user. Same goes for nfc_genl_fw_download() and NFC_ATTR_FIRMWARE_NAME. This patch adds appropriate checks. Found with syzkaller. Signed-off-by: Andrey Konovalov Signed-off-by: Andy Shevchenko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/nfc/netlink.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 32cb0c87e852..80def98c9dba 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -936,7 +936,8 @@ static int nfc_genl_dep_link_down(struct sk_buff *skb, struct genl_info *info) int rc; u32 idx; - if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) + if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || + !info->attrs[NFC_ATTR_TARGET_INDEX]) return -EINVAL; idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); @@ -985,7 +986,8 @@ static int nfc_genl_llc_get_params(struct sk_buff *skb, struct genl_info *info) struct sk_buff *msg = NULL; u32 idx; - if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) + if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || + !info->attrs[NFC_ATTR_FIRMWARE_NAME]) return -EINVAL; idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); -- cgit v1.2.3 From c61ebb668f2ce3c22d1cfe6df28bd3198eabbdd7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 7 Oct 2019 21:01:07 +0200 Subject: Linux 4.4.196 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 721fa569a680..9eaf50527883 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 195 +SUBLEVEL = 196 EXTRAVERSION = NAME = Blurry Fish Butt -- cgit v1.2.3 From e935115d05f7169b6e63df5dac501c71674d231e Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Tue, 24 Sep 2019 14:54:33 +0530 Subject: diag: Validate msg source length to prevent out of bound access Place check for mask size and validate source length against sum of header length and mask size to prevent out of bound access. Change-Id: I8ac089202b6e3007773b92be8cfdc52fcb30ec3c Signed-off-by: Manoj Prabhu B --- drivers/char/diag/diag_masks.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index ec3013c5fd85..775a66db30f7 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -901,7 +901,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, goto end; if (mask_size + write_len > dest_len) mask_size = dest_len - write_len; - memcpy(dest_buf + write_len, src_buf + header_len, mask_size); + if (mask_size && src_len >= header_len + mask_size) + memcpy(dest_buf + write_len, src_buf + header_len, mask_size); write_len += mask_size; for (i = 0; i < NUM_PERIPHERALS; i++) { if (!diag_check_update(i, pid)) -- cgit v1.2.3 From 4bcdd835f025b141fe0d89dfda1fc61de48eaacb Mon Sep 17 00:00:00 2001 From: Arjun Sreenath Date: Thu, 10 Oct 2019 16:22:49 +0530 Subject: ARM: dts: msm: Removed IOMMU test device node for MSM8996 Removed IOMMU test device node for MSM8996 only. Change-Id: I3197da05da1096cd485b0464fb6ccf87513d927e Signed-off-by: Arjun Sreenath --- arch/arm/boot/dts/qcom/msm-arm-smmu-8996.dtsi | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-8996.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-8996.dtsi index cbe65e266968..527765d34821 100644 --- a/arch/arm/boot/dts/qcom/msm-arm-smmu-8996.dtsi +++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-8996.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -251,16 +251,3 @@ "gcc_mmss_bimc_gfx_clk", "gcc_bimc_gfx_clk"; #clock-cells = <1>; }; - -&soc { - iommu_test_device { - compatible = "iommu-debug-test"; - /* - * 42 shouldn't be used by anyone on the cpp_fd_smmu. We just - * need _something_ here to get this node recognized by the - * SMMU driver. Our test uses ATOS, which doesn't use SIDs - * anyways, so using a dummy value is ok. - */ - iommus = <&cpp_fd_smmu 42>; - }; -}; -- cgit v1.2.3 From e5b2b112b3d9bc67afc37d1dd70d9bb0ac1b8b01 Mon Sep 17 00:00:00 2001 From: Jayachandran Sreekumaran Date: Mon, 3 Sep 2018 17:47:39 +0530 Subject: cnss2: Add support for genoa sdio Add support for genoa sdio Change-Id: Icf004d954ca0b508830412da6a381a7844f66efe Signed-off-by: Jayachandran Sreekumaran --- drivers/net/wireless/cnss2/Makefile | 1 + drivers/net/wireless/cnss2/bus.c | 39 +++- drivers/net/wireless/cnss2/bus.h | 3 +- drivers/net/wireless/cnss2/main.c | 38 +++- drivers/net/wireless/cnss2/main.h | 1 + drivers/net/wireless/cnss2/qmi.c | 3 +- drivers/net/wireless/cnss2/sdio.c | 410 ++++++++++++++++++++++++++++++++++++ drivers/net/wireless/cnss2/sdio.h | 86 ++++++++ include/net/cnss2.h | 56 +++++ 9 files changed, 620 insertions(+), 17 deletions(-) create mode 100644 drivers/net/wireless/cnss2/sdio.c create mode 100644 drivers/net/wireless/cnss2/sdio.h diff --git a/drivers/net/wireless/cnss2/Makefile b/drivers/net/wireless/cnss2/Makefile index a4b177e7a981..b1c8c5e6461e 100644 --- a/drivers/net/wireless/cnss2/Makefile +++ b/drivers/net/wireless/cnss2/Makefile @@ -5,6 +5,7 @@ cnss2-y += bus.o cnss2-y += debug.o cnss2-y += pci.o cnss2-y += usb.o +cnss2-$(CONFIG_SDIO_QCN) += sdio.o cnss2-y += power.o cnss2-y += qmi.o cnss2-y += wlan_firmware_service_v01.o diff --git a/drivers/net/wireless/cnss2/bus.c b/drivers/net/wireless/cnss2/bus.c index 088593f9ae1c..e33eb647d9bb 100644 --- a/drivers/net/wireless/cnss2/bus.c +++ b/drivers/net/wireless/cnss2/bus.c @@ -14,6 +14,7 @@ #include "debug.h" #include "pci.h" #include "usb.h" +#include "sdio.h" enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev) { @@ -27,6 +28,8 @@ enum cnss_dev_bus_type cnss_get_dev_bus_type(struct device *dev) return CNSS_BUS_PCI; else if (memcmp(dev->bus->name, "usb", 3) == 0) return CNSS_BUS_USB; + else if (memcmp(dev->bus->name, "sdio", 4) == 0) + return CNSS_BUS_SDIO; else return CNSS_BUS_NONE; } @@ -44,20 +47,14 @@ enum cnss_dev_bus_type cnss_get_bus_type(unsigned long device_id) case QCN7605_VER20_STANDALONE_DEVICE_ID: case QCN7605_VER20_COMPOSITE_DEVICE_ID: return CNSS_BUS_USB; + case QCN7605_SDIO_DEVICE_ID: + return CNSS_BUS_SDIO; default: cnss_pr_err("Unknown device_id: 0x%lx\n", device_id); return CNSS_BUS_NONE; } } -bool cnss_bus_req_mem_ind_valid(struct cnss_plat_data *plat_priv) -{ - if (cnss_get_bus_type(plat_priv->device_id) == CNSS_BUS_USB) - return false; - else - return true; -} - void *cnss_bus_dev_to_bus_priv(struct device *dev) { if (!dev) @@ -89,6 +86,8 @@ struct cnss_plat_data *cnss_bus_dev_to_plat_priv(struct device *dev) return cnss_pci_priv_to_plat_priv(bus_priv); case CNSS_BUS_USB: return cnss_usb_priv_to_plat_priv(bus_priv); + case CNSS_BUS_SDIO: + return cnss_get_plat_priv(NULL); default: return NULL; } @@ -104,6 +103,8 @@ int cnss_bus_init(struct cnss_plat_data *plat_priv) return cnss_pci_init(plat_priv); case CNSS_BUS_USB: return cnss_usb_init(plat_priv); + case CNSS_BUS_SDIO: + return cnss_sdio_init(plat_priv); default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); @@ -119,13 +120,18 @@ void cnss_bus_deinit(struct cnss_plat_data *plat_priv) switch (plat_priv->bus_type) { case CNSS_BUS_PCI: cnss_pci_deinit(plat_priv); + break; case CNSS_BUS_USB: cnss_usb_deinit(plat_priv); + break; + case CNSS_BUS_SDIO: + cnss_sdio_deinit(plat_priv); + break; default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); - return; } + return; } int cnss_bus_load_m3(struct cnss_plat_data *plat_priv) @@ -200,6 +206,8 @@ void cnss_bus_fw_boot_timeout_hdlr(unsigned long data) return cnss_pci_fw_boot_timeout_hdlr(plat_priv->bus_priv); case CNSS_BUS_USB: return cnss_usb_fw_boot_timeout_hdlr(plat_priv->bus_priv); + case CNSS_BUS_SDIO: + return cnss_sdio_fw_boot_timeout_hdlr(plat_priv->bus_priv); default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); @@ -240,6 +248,8 @@ int cnss_bus_call_driver_probe(struct cnss_plat_data *plat_priv) return cnss_pci_call_driver_probe(plat_priv->bus_priv); case CNSS_BUS_USB: return cnss_usb_call_driver_probe(plat_priv->bus_priv); + case CNSS_BUS_SDIO: + return cnss_sdio_call_driver_probe(plat_priv->bus_priv); default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); @@ -257,6 +267,8 @@ int cnss_bus_call_driver_remove(struct cnss_plat_data *plat_priv) return cnss_pci_call_driver_remove(plat_priv->bus_priv); case CNSS_BUS_USB: return cnss_usb_call_driver_remove(plat_priv->bus_priv); + case CNSS_BUS_SDIO: + return cnss_sdio_call_driver_remove(plat_priv->bus_priv); default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); @@ -274,6 +286,8 @@ int cnss_bus_dev_powerup(struct cnss_plat_data *plat_priv) return cnss_pci_dev_powerup(plat_priv->bus_priv); case CNSS_BUS_USB: return cnss_usb_dev_powerup(plat_priv); + case CNSS_BUS_SDIO: + return cnss_sdio_dev_powerup(plat_priv->bus_priv); default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); @@ -291,6 +305,8 @@ int cnss_bus_dev_shutdown(struct cnss_plat_data *plat_priv) return cnss_pci_dev_shutdown(plat_priv->bus_priv); case CNSS_BUS_USB: return 0; + case CNSS_BUS_SDIO: + return cnss_sdio_dev_shutdown(plat_priv->bus_priv); default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); @@ -338,6 +354,9 @@ int cnss_bus_register_driver_hdlr(struct cnss_plat_data *plat_priv, void *data) return cnss_pci_register_driver_hdlr(plat_priv->bus_priv, data); case CNSS_BUS_USB: return cnss_usb_register_driver_hdlr(plat_priv->bus_priv, data); + case CNSS_BUS_SDIO: + return cnss_sdio_register_driver_hdlr(plat_priv->bus_priv, + data); default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); @@ -355,6 +374,8 @@ int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv) return cnss_pci_unregister_driver_hdlr(plat_priv->bus_priv); case CNSS_BUS_USB: return cnss_usb_unregister_driver_hdlr(plat_priv->bus_priv); + case CNSS_BUS_SDIO: + return cnss_sdio_unregister_driver_hdlr(plat_priv->bus_priv); default: cnss_pr_err("Unsupported bus type: %d\n", plat_priv->bus_type); diff --git a/drivers/net/wireless/cnss2/bus.h b/drivers/net/wireless/cnss2/bus.h index 1100fd66482a..30a93a06549f 100644 --- a/drivers/net/wireless/cnss2/bus.h +++ b/drivers/net/wireless/cnss2/bus.h @@ -26,6 +26,8 @@ #define QCA6290_EMULATION_DEVICE_ID 0xABCD #define QCN7605_VENDOR_ID 0x17CB #define QCN7605_DEVICE_ID 0x1102 +#define QCN7605_SDIO_VENDOR_ID 0x70 +#define QCN7605_SDIO_DEVICE_ID 0x400B #define QCN7605_USB_VENDOR_ID 0x05C6 #define QCN7605_COMPOSITE_DEVICE_ID QCN7605_COMPOSITE_PRODUCT_ID @@ -62,5 +64,4 @@ int cnss_bus_unregister_driver_hdlr(struct cnss_plat_data *plat_priv); int cnss_bus_call_driver_modem_status(struct cnss_plat_data *plat_priv, int modem_current_status); int cnss_bus_recovery_update_status(struct cnss_plat_data *plat_priv); -bool cnss_bus_req_mem_ind_valid(struct cnss_plat_data *plat_priv); #endif /* _CNSS_BUS_H */ diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 1da33c258d4a..f70dfaa45c0f 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -248,7 +248,7 @@ int cnss_wlan_enable(struct device *dev, enum cnss_driver_mode mode, const char *host_version) { - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); struct wlfw_wlan_cfg_req_msg_v01 req; u32 i, ce_id, num_vectors, user_base_data, base_vector; int ret = 0; @@ -259,7 +259,8 @@ int cnss_wlan_enable(struct device *dev, if (qmi_bypass) return 0; - if (cnss_get_bus_type(plat_priv->device_id) == CNSS_BUS_USB) + if (plat_priv->bus_type == CNSS_BUS_USB || + plat_priv->bus_type == CNSS_BUS_SDIO) goto skip_cfg; if (!config || !host_version) { @@ -364,7 +365,7 @@ EXPORT_SYMBOL(cnss_wlan_enable); int cnss_wlan_disable(struct device *dev, enum cnss_driver_mode mode) { - struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); if (plat_priv->device_id == QCA6174_DEVICE_ID) return 0; @@ -1234,7 +1235,8 @@ static int cnss_wlfw_server_arrive_hdlr(struct cnss_plat_data *plat_priv) if (ret) goto out; - if (!cnss_bus_req_mem_ind_valid(plat_priv)) { + if (plat_priv->bus_type == CNSS_BUS_USB || + plat_priv->bus_type == CNSS_BUS_SDIO) { ret = cnss_wlfw_tgt_cap_send_sync(plat_priv); if (ret) goto out; @@ -1254,7 +1256,7 @@ static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv) if (test_bit(CNSS_DEV_REMOVED, &plat_priv->driver_state)) pwr_up_reqd = true; - if (pwr_up_reqd || plat_priv->bus_type != CNSS_BUS_USB) + if (pwr_up_reqd || plat_priv->bus_type == CNSS_BUS_PCI) ret = cnss_bus_dev_powerup(plat_priv); if (ret) @@ -1413,6 +1415,7 @@ int cnss_register_subsys(struct cnss_plat_data *plat_priv) case QCN7605_COMPOSITE_DEVICE_ID: case QCN7605_VER20_STANDALONE_DEVICE_ID: case QCN7605_VER20_COMPOSITE_DEVICE_ID: + case QCN7605_SDIO_DEVICE_ID: subsys_info->subsys_desc.name = "QCN7605"; break; default: @@ -1749,6 +1752,18 @@ static ssize_t cnss_fs_ready_store(struct device *dev, return count; } +#ifdef CONFIG_SDIO_QCN +static void cnss_set_card_state(bool state) +{ + qcn_sdio_card_state(state); +} +#else +static void cnss_set_card_state(bool state) +{ + /* no op */ +} +#endif + static DEVICE_ATTR(fs_ready, 0220, NULL, cnss_fs_ready_store); static ssize_t cnss_wl_pwr_on(struct device *dev, @@ -1769,12 +1784,14 @@ static ssize_t cnss_wl_pwr_on(struct device *dev, timeout = cnss_get_qmi_timeout(); if (pwr_state) { cnss_power_on_device(plat_priv); + cnss_set_card_state(true); if (timeout) { mod_timer(&plat_priv->fw_boot_timer, jiffies + msecs_to_jiffies(timeout)); } } else { cnss_power_off_device(plat_priv); + cnss_set_card_state(false); del_timer(&plat_priv->fw_boot_timer); } return count; @@ -1867,6 +1884,7 @@ static const struct platform_device_id cnss_platform_id_table[] = { { .name = "qca6174", .driver_data = QCA6174_DEVICE_ID, }, { .name = "qca6290", .driver_data = QCA6290_DEVICE_ID, }, { .name = "qcn7605", .driver_data = QCN7605_DEVICE_ID, }, + { .name = "qcn7605_sdio", .driver_data = QCN7605_SDIO_DEVICE_ID, }, }; static const struct of_device_id cnss_of_match_table[] = { @@ -1876,6 +1894,12 @@ static const struct of_device_id cnss_of_match_table[] = { { .compatible = "qcom,cnss-qca6290", .data = (void *)&cnss_platform_id_table[1]}, + { + .compatible = "qcom,cnss", + .data = (void *)&cnss_platform_id_table[2]}, + { + .compatible = "qcom,cnss-sdio", + .data = (void *)&cnss_platform_id_table[3]}, { }, }; MODULE_DEVICE_TABLE(of, cnss_of_match_table); @@ -1926,7 +1950,9 @@ static int cnss_probe(struct platform_device *plat_dev) goto free_res; ret = cnss_bus_init(plat_priv); - if (ret) + if (ret == -EPROBE_DEFER) + goto free_res; + else if (ret) goto power_off; } diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index 1b7c67b90795..aa197f0684d5 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -36,6 +36,7 @@ enum cnss_dev_bus_type { CNSS_BUS_NONE = -1, CNSS_BUS_PCI, CNSS_BUS_USB, + CNSS_BUS_SDIO, }; struct cnss_vreg_info { diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 7945f59439f7..489a28e478bd 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -797,7 +797,8 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv) plat_priv->device_id == QCN7605_COMPOSITE_DEVICE_ID || plat_priv->device_id == QCN7605_STANDALONE_DEVICE_ID || plat_priv->device_id == QCN7605_VER20_STANDALONE_DEVICE_ID || - plat_priv->device_id == QCN7605_VER20_COMPOSITE_DEVICE_ID) + plat_priv->device_id == QCN7605_VER20_COMPOSITE_DEVICE_ID || + plat_priv->device_id == QCN7605_SDIO_DEVICE_ID) bdf_type = CNSS_BDF_BIN; if (plat_priv->board_info.board_id == 0xFF) { diff --git a/drivers/net/wireless/cnss2/sdio.c b/drivers/net/wireless/cnss2/sdio.c new file mode 100644 index 000000000000..f25a2b0aaaa8 --- /dev/null +++ b/drivers/net/wireless/cnss2/sdio.c @@ -0,0 +1,410 @@ +/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "main.h" +#include "sdio.h" +#include "debug.h" +#include "bus.h" + +int cnss_sdio_call_driver_probe(struct cnss_sdio_data *sdio_priv) +{ + int ret = 0; + struct cnss_plat_data *plat_priv = sdio_priv->plat_priv; + + if ((!sdio_priv->al_client_handle) || + (!sdio_priv->al_client_handle->func)) { + ret = -ENODEV; + goto out; + } + + if (!sdio_priv->ops) { + cnss_pr_err("driver_ops is NULL\n"); + ret = -EINVAL; + goto out; + } + + if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) && + test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) { + ret = sdio_priv->ops->reinit(sdio_priv->al_client_handle->func, + sdio_priv->device_id); + if (ret) { + cnss_pr_err("Failed to reinit host driver, err = %d\n", + ret); + goto out; + } + clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); + } else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) { + ret = sdio_priv->ops->probe(sdio_priv->al_client_handle->func, + sdio_priv->device_id); + if (ret) { + cnss_pr_err("Failed to probe host driver, err = %d\n", + ret); + goto out; + } + clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); + clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state); + set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state); + } + + return 0; + +out: + return ret; +} + +int cnss_sdio_call_driver_remove(struct cnss_sdio_data *sdio_priv) +{ + struct cnss_plat_data *plat_priv = sdio_priv->plat_priv; + + if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state) || + test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state) || + test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) { + cnss_pr_dbg("Skip driver remove\n"); + return 0; + } + + if (!sdio_priv->ops) { + cnss_pr_err("driver_ops is NULL\n"); + return -EINVAL; + } + + if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) && + test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) { + cnss_pr_dbg("Recovery set after driver probed.Call shutdown\n"); + sdio_priv->ops->shutdown(sdio_priv->al_client_handle->func); + } else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) { + cnss_pr_dbg("driver_ops->remove\n"); + sdio_priv->ops->remove(sdio_priv->al_client_handle->func); + clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state); + } + return 0; +} + +/** + * cnss_sdio_wlan_register_driver() - cnss wlan register API + * @driver: sdio wlan driver interface from wlan driver. + * + * wlan sdio function driver uses this API to register callback + * functions to cnss_sido platform driver. The callback will + * be invoked by corresponding wrapper function of this cnss + * platform driver. + */ +int cnss_sdio_wlan_register_driver(struct cnss_sdio_wlan_driver *driver_ops) +{ + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + struct cnss_sdio_data *cnss_info; + int ret = 0; + + if (!plat_priv) { + cnss_pr_err("plat_priv is NULL\n"); + return -ENODEV; + } + + cnss_info = plat_priv->bus_priv; + if ((!cnss_info) || + (!cnss_info->al_client_handle) || + (!cnss_info->al_client_handle->func)) { + cnss_pr_err("cnss_info is NULL\n"); + return -ENODEV; + } + + if (cnss_info->ops) { + cnss_pr_err("Driver has already registered\n"); + return -EEXIST; + } + cnss_info->ops = driver_ops; + + ret = cnss_driver_event_post(plat_priv, + CNSS_DRIVER_EVENT_REGISTER_DRIVER, + CNSS_EVENT_SYNC_UNINTERRUPTIBLE, + driver_ops); + return ret; +} +EXPORT_SYMBOL(cnss_sdio_wlan_register_driver); + +/** + * cnss_sdio_wlan_unregister_driver() - cnss wlan unregister API + * @driver: sdio wlan driver interface from wlan driver. + * + * wlan sdio function driver uses this API to detach it from cnss_sido + * platform driver. + */ +void cnss_sdio_wlan_unregister_driver(struct cnss_sdio_wlan_driver *driver_ops) +{ + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + + if (!plat_priv) { + cnss_pr_err("plat_priv is NULL\n"); + return; + } + + cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_UNREGISTER_DRIVER, + CNSS_EVENT_SYNC_UNINTERRUPTIBLE, NULL); +} +EXPORT_SYMBOL(cnss_sdio_wlan_unregister_driver); + +struct sdio_al_client_handle *cnss_sdio_wlan_get_sdio_al_client_handle( + struct sdio_func *func) +{ + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + struct cnss_sdio_data *cnss_info = plat_priv->bus_priv; + + return cnss_info->al_client_handle; +} +EXPORT_SYMBOL(cnss_sdio_wlan_get_sdio_al_client_handle); + +struct sdio_al_channel_handle *cnss_sdio_wlan_register_sdio_al_channel( + struct sdio_al_channel_data *channel_data) +{ + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + struct cnss_sdio_data *cnss_info = plat_priv->bus_priv; + + return sdio_al_register_channel(cnss_info->al_client_handle, + channel_data); +} +EXPORT_SYMBOL(cnss_sdio_wlan_register_sdio_al_channel); + +void cnss_sdio_wlan_unregister_sdio_al_channel( + struct sdio_al_channel_handle *ch_handle) +{ + sdio_al_deregister_channel(ch_handle); +} +EXPORT_SYMBOL(cnss_sdio_wlan_unregister_sdio_al_channel); + +int cnss_sdio_register_driver_hdlr(struct cnss_sdio_data *cnss_info, + void *data) +{ + struct cnss_plat_data *plat_priv = cnss_info->plat_priv; + int ret = 0; + unsigned int timeout; + + set_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state); + if (test_bit(CNSS_FW_READY, &plat_priv->driver_state)) { + cnss_pr_info("CNSS SDIO driver register in FW_Ready state"); + cnss_sdio_call_driver_probe(cnss_info); + } else if ((*cnss_get_qmi_bypass()) && + (cnss_info->al_client_handle->func)) { + cnss_pr_info("qmi bypass enabled"); + cnss_sdio_call_driver_probe(cnss_info); + } else { + cnss_pr_info("Wait for FW_Ready"); + ret = cnss_power_on_device(plat_priv); + if (ret) { + cnss_pr_err("Failed to power on device, err = %d\n", + ret); + return ret; + } + + qcn_sdio_card_state(true); + timeout = cnss_get_qmi_timeout(); + if (timeout) { + mod_timer(&plat_priv->fw_boot_timer, + jiffies + msecs_to_jiffies(timeout << 1)); + } + } + return 0; +} + +int cnss_sdio_unregister_driver_hdlr(struct cnss_sdio_data *cnss_info) +{ + struct cnss_plat_data *plat_priv = cnss_info->plat_priv; + + set_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state); + cnss_sdio_call_driver_remove(cnss_info); + cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev, + CNSS_BUS_WIDTH_NONE); + qcn_sdio_card_state(false); + cnss_power_off_device(plat_priv); + clear_bit(CNSS_FW_READY, &plat_priv->driver_state); + clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state); + + cnss_info->ops = NULL; + return 0; +} + +int cnss_sdio_dev_powerup(struct cnss_sdio_data *cnss_info) +{ + struct cnss_plat_data *plat_priv = cnss_info->plat_priv; + int ret = 0; + unsigned int timeout; + + switch (plat_priv->device_id) { + case QCN7605_SDIO_DEVICE_ID: + ret = cnss_power_on_device(plat_priv); + if (ret) { + cnss_pr_err("Failed to power on device, err = %d\n", + ret); + goto out; + } + + qcn_sdio_card_state(true); + timeout = cnss_get_qmi_timeout(); + mod_timer(&plat_priv->fw_boot_timer, + jiffies + msecs_to_jiffies(timeout >> 1)); + cnss_set_pin_connect_status(plat_priv); + break; + default: + cnss_pr_err("Unknown device_id found: 0x%lx\n", + plat_priv->device_id); + ret = -ENODEV; + } +out: + return ret; +} + +int cnss_sdio_dev_shutdown(struct cnss_sdio_data *cnss_info) +{ + struct cnss_plat_data *plat_priv = cnss_info->plat_priv; + + cnss_sdio_call_driver_remove(cnss_info); + cnss_request_bus_bandwidth(&plat_priv->plat_dev->dev, + CNSS_BUS_WIDTH_NONE); + /*qcn_sdio_card_state(false);*/ + cnss_power_off_device(plat_priv); + clear_bit(CNSS_FW_READY, &plat_priv->driver_state); + clear_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state); + + return 0; +} + +void cnss_sdio_fw_boot_timeout_hdlr(void *bus_priv) +{ + cnss_pr_err("Timeout waiting for FW ready indication\n"); +} + +static int cnss_sdio_probe(struct sdio_al_client_handle *pal_cli_handle) +{ + struct cnss_sdio_data *sdio_info = pal_cli_handle->client_priv; + struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL); + struct sdio_device_id *device_id; + + device_id = devm_kzalloc(&plat_priv->plat_dev->dev, + sizeof(struct sdio_device_id), + GFP_KERNEL); + device_id->class = pal_cli_handle->func->class; + device_id->vendor = pal_cli_handle->func->vendor; + device_id->device = pal_cli_handle->func->device; + sdio_info->device_id = device_id; + + if (pal_cli_handle->func) + cnss_pr_info("CNSS SDIO AL Probe for device Id: 0x%x\n", + pal_cli_handle->func->device); + clear_bit(CNSS_DEV_REMOVED, &plat_priv->driver_state); + plat_priv->device_id = pal_cli_handle->func->device; + cnss_register_subsys(sdio_info->plat_priv); + return 0; +} + +static int cnss_sdio_remove(struct sdio_al_client_handle *pal_cli_handle) +{ + struct cnss_sdio_data *sdio_info = pal_cli_handle->client_priv; + struct cnss_plat_data *plat_priv = sdio_info->plat_priv; + + if (pal_cli_handle->func) + cnss_pr_err( + "SDIO AL remove for device Id: 0x%x in driver state %lu\n", + pal_cli_handle->func->device, + plat_priv->driver_state); + + clear_bit(CNSS_FW_READY, &plat_priv->driver_state); + set_bit(CNSS_DEV_REMOVED, &plat_priv->driver_state); + if (sdio_info->ops && + test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) { + cnss_pr_err("Triggering driver_ops remove\n"); + sdio_info->ops->update_status( + sdio_info->al_client_handle->func, + CNSS_FW_DOWN); + sdio_info->ops->remove(sdio_info->al_client_handle->func); + clear_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state); + } + + cnss_unregister_subsys(plat_priv); + devm_kfree(&plat_priv->plat_dev->dev, (void *)sdio_info->device_id); + + return 0; +} + +static void cnss_sdio_pm(struct sdio_al_client_handle *pal_cli_handle, + enum sdio_al_lpm_event event) +{ + struct cnss_sdio_data *sdio_info = pal_cli_handle->client_priv; + struct sdio_func *func = sdio_info->al_client_handle->func; + + if (!sdio_info->ops) { + cnss_pr_err("Ignore LPM event\n"); + return; + } + + if (event == LPM_ENTER) { + cnss_pr_info("Entering LPM\n"); + sdio_info->ops->suspend(&func->dev); + } else { + cnss_pr_info("Exiting LPM\n"); + sdio_info->ops->resume(&func->dev); + } +} + +struct sdio_al_client_data al_cli_data = { + .name = "SDIO_AL_CLIENT_WLAN", + .probe = cnss_sdio_probe, + .remove = cnss_sdio_remove, + .lpm_notify_cb = cnss_sdio_pm, +}; + +int cnss_sdio_init(struct cnss_plat_data *plat_priv) +{ + struct cnss_sdio_data *sdio_info; + struct sdio_al_client_handle *al_client_handle; + int ret = 0; + + if (sdio_al_is_ready()) { + cnss_pr_err("sdio_al not ready, defer probe\n"); + ret = -EPROBE_DEFER; + goto out; + } + + al_client_handle = sdio_al_register_client(&al_cli_data); + if (!al_client_handle) { + cnss_pr_err("sdio al registration failed!\n"); + ret = -ENODEV; + goto out; + } + sdio_info = devm_kzalloc(&plat_priv->plat_dev->dev, sizeof(*sdio_info), + GFP_KERNEL); + if (!sdio_info) { + ret = -ENOMEM; + goto out; + } + al_client_handle->client_priv = sdio_info; + sdio_info->al_client_handle = al_client_handle; + sdio_info->plat_priv = plat_priv; + plat_priv->bus_priv = sdio_info; + +out: + return ret; +} + +int cnss_sdio_deinit(struct cnss_plat_data *plat_priv) +{ + struct cnss_sdio_data *sdio_info = plat_priv->bus_priv; + + sdio_al_deregister_client(sdio_info->al_client_handle); + return 0; +} diff --git a/drivers/net/wireless/cnss2/sdio.h b/drivers/net/wireless/cnss2/sdio.h new file mode 100644 index 000000000000..1f782fa61f79 --- /dev/null +++ b/drivers/net/wireless/cnss2/sdio.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CNSS_SDIO_H +#define _CNSS_SDIO_H + +#include "main.h" +#ifdef CONFIG_SDIO_QCN +#include + +struct cnss_sdio_data { + struct cnss_plat_data *plat_priv; + struct sdio_al_client_handle *al_client_handle; + struct cnss_sdio_wlan_driver *ops; + struct sdio_device_id *device_id; + void *client_priv; +}; + +int cnss_sdio_init(struct cnss_plat_data *plat_priv); +int cnss_sdio_deinit(struct cnss_plat_data *plat_priv); +int cnss_sdio_register_driver_hdlr(struct cnss_sdio_data *sdio_info, + void *data); +int cnss_sdio_unregister_driver_hdlr(struct cnss_sdio_data *sdio_info); +int cnss_sdio_dev_powerup(struct cnss_sdio_data *cnss_info); +int cnss_sdio_dev_shutdown(struct cnss_sdio_data *cnss_info); +int cnss_sdio_call_driver_probe(struct cnss_sdio_data *sdio_priv); +int cnss_sdio_call_driver_remove(struct cnss_sdio_data *sdio_priv); +void cnss_sdio_fw_boot_timeout_hdlr(void *bus_priv); +#else +inline int cnss_sdio_init(void *plat_priv) +{ + return -EINVAL; +} + +inline int cnss_sdio_deinit(void *plat_priv) +{ + return -EINVAL; +} + +inline int cnss_sdio_register_driver_hdlr(void *sdio_info, + void *data) +{ + return -EINVAL; +} + +inline int cnss_sdio_unregister_driver_hdlr(void *sdio_info) +{ + return -EINVAL; +} + +inline int cnss_sdio_dev_powerup(void *cnss_info) +{ + return -EINVAL; +} + +inline int cnss_sdio_dev_shutdown(void *cnss_info) +{ + return -EINVAL; +} + +inline int cnss_sdio_call_driver_probe(void *sdio_priv) +{ + return -EINVAL; +} + +inline int cnss_sdio_call_driver_remove(void *sdio_priv) +{ + return -EINVAL; +} + +inline void cnss_sdio_fw_boot_timeout_hdlr(void *bus_priv) +{ + /* no op */ +} +#endif + +#endif diff --git a/include/net/cnss2.h b/include/net/cnss2.h index eb6908feb7ef..e57b65f97f0f 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -15,6 +15,10 @@ #include #include +#include +#ifdef CONFIG_SDIO_QCN +#include +#endif #define CNSS_MAX_FILE_NAME 20 #define CNSS_MAX_TIMESTAMP_LEN 32 @@ -111,6 +115,21 @@ struct cnss_usb_wlan_driver { const struct usb_device_id *id_table; }; +#ifdef CONFIG_SDIO_QCN +struct cnss_sdio_wlan_driver { + const char *name; + const struct sdio_device_id *id_table; + int (*probe)(struct sdio_func *, const struct sdio_device_id *); + void (*remove)(struct sdio_func *); + int (*reinit)(struct sdio_func *, const struct sdio_device_id *); + void (*shutdown)(struct sdio_func *); + void (*crash_shutdown)(struct sdio_func *); + int (*suspend)(struct device *); + int (*resume)(struct device *); + void (*update_status)(struct sdio_func *, uint32_t status); +}; +#endif + enum cnss_driver_status { CNSS_UNINITIALIZED, CNSS_INITIALIZED, @@ -251,5 +270,42 @@ extern int cnss_usb_wlan_register_driver(struct cnss_usb_wlan_driver *driver); extern void cnss_usb_wlan_unregister_driver(struct cnss_usb_wlan_driver * driver); extern int cnss_usb_is_device_down(struct device *dev); +#ifdef CONFIG_SDIO_QCN +extern int cnss_sdio_wlan_register_driver(struct cnss_sdio_wlan_driver * + driver_ops); +extern void cnss_sdio_wlan_unregister_driver(struct cnss_sdio_wlan_driver * + driver_ops); +extern struct sdio_al_client_handle *cnss_sdio_wlan_get_sdio_al_client_handle( + struct sdio_func *func); +extern struct sdio_al_channel_handle *cnss_sdio_wlan_register_sdio_al_channel( + struct sdio_al_channel_data *channel_data); +extern void cnss_sdio_wlan_unregister_sdio_al_channel( + struct sdio_al_channel_handle *ch_handle); +#else +extern inline int cnss_sdio_wlan_register_driver(void *driver_ops) +{ + return 0; +} + +extern inline void cnss_sdio_wlan_unregister_driver(void *driver_ops) +{ + +} + +extern inline void *cnss_sdio_wlan_get_sdio_al_client_handle(void *func) +{ + return NULL; +} + +extern inline void *cnss_sdio_wlan_register_sdio_al_channel(void *channel_data) +{ + return NULL; +} + +extern inline void cnss_sdio_wlan_unregister_sdio_al_channel(void *ch_handle) +{ + +} +#endif #endif /* _NET_CNSS2_H */ -- cgit v1.2.3 From 666e83125bd5bcd60f63ee0038587ba7a3d87887 Mon Sep 17 00:00:00 2001 From: Umang Chheda Date: Tue, 1 Oct 2019 16:03:39 +0530 Subject: power: battery: Initialize work struct before cancelling work Votable callback accesses work structure as part of their callback, initialize work before creation of votables. Change-Id: I91741b3d54c73aab5c695a31292a32752edc77cd Signed-off-by: Umang Chheda --- drivers/power/supply/qcom/battery.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 6d5308b3dd0b..c19abd4075a3 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2017,2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1345,6 +1345,12 @@ int qcom_batt_init(void) if (!chip->pl_ws) goto cleanup; + INIT_DELAYED_WORK(&chip->status_change_work, status_change_work); + INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work); + INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work); + INIT_DELAYED_WORK(&chip->pl_awake_work, pl_awake_work); + INIT_DELAYED_WORK(&chip->fcc_step_update_work, fcc_step_update_work); + chip->fcc_votable = create_votable("FCC", VOTE_MIN, pl_fcc_vote_callback, chip); @@ -1399,12 +1405,6 @@ int qcom_batt_init(void) vote(chip->pl_disable_votable, PL_INDIRECT_VOTER, true, 0); - INIT_DELAYED_WORK(&chip->status_change_work, status_change_work); - INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work); - INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work); - INIT_DELAYED_WORK(&chip->pl_awake_work, pl_awake_work); - INIT_DELAYED_WORK(&chip->fcc_step_update_work, fcc_step_update_work); - rc = pl_register_notifier(chip); if (rc < 0) { pr_err("Couldn't register psy notifier rc = %d\n", rc); -- cgit v1.2.3 From 6dec23e2d32dd103cb6ece90a831f3bb224a8f4f Mon Sep 17 00:00:00 2001 From: Nirmal Abraham Date: Fri, 16 Aug 2019 16:39:17 +0530 Subject: fbdev: msm: Avoid UAF in mdss_dsi_cmd_write In mdss_dsi_cmd_write, a failure in copying the cmds to 'string_buf' can cause an early return. In this case, the 'pcmds->string_buf' won't be pointing to a valid buffer. This can lead to use-after-free and memory leak. To avoid this, assign the newly allocated buffer to 'pcmds->string_buf' after returning from krealloc call. Change-Id: I286f12c86078d1989cb09453c8a395a4ad94b324 Signed-off-by: Nirmal Abraham --- drivers/video/fbdev/msm/mdss_dsi.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 419991a98d4e..c2cfc8e0532e 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -888,7 +888,7 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p, { struct buf_data *pcmds = file->private_data; ssize_t ret = 0; - int blen = 0; + unsigned int blen = 0; char *string_buf; mutex_lock(&pcmds->dbg_mutex); @@ -900,6 +900,11 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p, /* Allocate memory for the received string */ blen = count + (pcmds->sblen); + if (blen > U32_MAX - 1) { + mutex_unlock(&pcmds->dbg_mutex); + return -EINVAL; + } + string_buf = krealloc(pcmds->string_buf, blen + 1, GFP_KERNEL); if (!string_buf) { pr_err("%s: Failed to allocate memory\n", __func__); @@ -907,6 +912,7 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p, return -ENOMEM; } + pcmds->string_buf = string_buf; /* Writing in batches is possible */ ret = simple_write_to_buffer(string_buf, blen, ppos, p, count); if (ret < 0) { @@ -916,7 +922,6 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p, } string_buf[ret] = '\0'; - pcmds->string_buf = string_buf; pcmds->sblen = count; mutex_unlock(&pcmds->dbg_mutex); return ret; -- cgit v1.2.3 From c2877a4eb89ef4ab586d47cbfdeea24f8283ceb7 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Thu, 10 Oct 2019 11:21:15 +0530 Subject: msm: ekms: Remove the wait for completion of eDRM probe Main DRM & eDRM driver has asynchronous probes. In order to ensure that both the driver's probe has completed there is a wait for completion for respective driver is executed. There is an issue where the wait for the eDRM driver blocks the eDRM driver deferred probe call. This change remove wait in the eDRM driver for completion of its probe as eDRM driver is always initialized after main DRM and necessary clock voting would also be done in main DRM. Change-Id: I422419d381ad3d0361fb80f3b2b9d176203a9342 Signed-off-by: Rahul Sharma --- drivers/gpu/drm/msm/ekms/edrm_drv.c | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/drivers/gpu/drm/msm/ekms/edrm_drv.c b/drivers/gpu/drm/msm/ekms/edrm_drv.c index 144dd231e428..69b8c01e59d4 100644 --- a/drivers/gpu/drm/msm/ekms/edrm_drv.c +++ b/drivers/gpu/drm/msm/ekms/edrm_drv.c @@ -23,9 +23,6 @@ #include "msm_mmu.h" #include "edrm_kms.h" -static struct completion wait_display_completion; -static bool msm_edrm_probed; - static int msm_edrm_unload(struct drm_device *dev) { struct msm_drm_private *priv = dev->dev_private; @@ -331,8 +328,6 @@ static int msm_pdev_edrm_probe(struct platform_device *pdev) struct msm_drm_private *master_priv; struct msm_kms *master_kms; - msm_edrm_probed = true; - /* main DRM's minor ID is zero */ minor = drm_minor_acquire(0); if (IS_ERR(minor)) { @@ -372,7 +367,6 @@ static int msm_pdev_edrm_probe(struct platform_device *pdev) if (ret) DRM_ERROR("drm_platform_init failed: %d\n", ret); - complete(&wait_display_completion); return ret; } @@ -414,20 +408,6 @@ static const struct of_device_id dt_match[] = { }; MODULE_DEVICE_TABLE(of, dt_match); -static int find_match(struct device *dev, void *data) -{ - struct device_driver *drv = data; - - return drv->bus->match(dev, drv); -} - -static bool find_device(struct platform_driver *pdrv) -{ - struct device_driver *drv = &pdrv->driver; - - return bus_for_each_dev(drv->bus, NULL, drv, find_match); -} - static struct platform_driver msm_platform_driver = { .probe = msm_pdev_edrm_probe, .remove = msm_pdev_edrm_remove, @@ -443,7 +423,6 @@ static struct platform_driver msm_platform_driver = { static int __init msm_edrm_register(void) { DBG("init"); - init_completion(&wait_display_completion); return platform_driver_register(&msm_platform_driver); } @@ -453,22 +432,8 @@ static void __exit msm_edrm_unregister(void) platform_driver_unregister(&msm_platform_driver); } -static int __init msm_edrm_late_register(void) -{ - struct platform_driver *pdrv; - - pdrv = &msm_platform_driver; - if (msm_edrm_probed || find_device(pdrv)) { - pr_debug("wait for eDRM display probe completion\n"); - wait_for_completion(&wait_display_completion); - } - return 0; -} - module_init(msm_edrm_register); module_exit(msm_edrm_unregister); -/* init level 7 */ -late_initcall(msm_edrm_late_register); MODULE_DESCRIPTION("MSM EARLY DRM Driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From a19e5e98f426fcff126a3b9aa30ef0fa483387fe Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Tue, 5 Sep 2017 17:43:35 +0530 Subject: soc: qcom: Reorganize PIL code for reclaiming MSS mem during SSR This change ask hypervisor to remove memory mapping for MSS from IOMMU second stage table and assign the ownership back to HLOS just after MBA is booted. Presently this is being done only after MBA is booted and MDT is authenticated. Change-Id: I724c1bcc664827e666612dd34cd078f3f044498a Signed-off-by: Avaneesh Kumar Dwivedi --- drivers/soc/qcom/peripheral-loader.c | 20 ++++---------------- drivers/soc/qcom/peripheral-loader.h | 4 ++-- drivers/soc/qcom/pil-msa.c | 23 +++++++++++++++++++---- drivers/soc/qcom/subsys-pil-tz.c | 5 +++-- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c index 32a457730869..2a3b2a313c69 100644 --- a/drivers/soc/qcom/peripheral-loader.c +++ b/drivers/soc/qcom/peripheral-loader.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -980,7 +980,9 @@ int pil_boot(struct pil_desc *desc) trace_pil_event("before_init_image", desc); if (desc->ops->init_image) - ret = desc->ops->init_image(desc, fw->data, fw->size); + ret = desc->ops->init_image(desc, fw->data, fw->size, + priv->region_start, + priv->region_end - priv->region_start); if (ret) { pil_err(desc, "Initializing image failed(rc:%d)\n", ret); subsys_set_error(desc->subsys_dev, firmware_error_msg); @@ -997,20 +999,6 @@ int pil_boot(struct pil_desc *desc) } if (desc->subsys_vmid > 0) { - /** - * In case of modem ssr, we need to assign memory back to linux. - * This is not true after cold boot since linux already owns it. - * Also for secure boot devices, modem memory has to be released - * after MBA is booted - */ - trace_pil_event("before_assign_mem", desc); - if (desc->modem_ssr) { - ret = pil_assign_mem_to_linux(desc, priv->region_start, - (priv->region_end - priv->region_start)); - if (ret) - pil_err(desc, "Failed to assign to linux, ret- %d\n", - ret); - } ret = pil_assign_mem_to_subsys_and_linux(desc, priv->region_start, (priv->region_end - priv->region_start)); diff --git a/drivers/soc/qcom/peripheral-loader.h b/drivers/soc/qcom/peripheral-loader.h index 6e74743c8c21..6800fd83944a 100644 --- a/drivers/soc/qcom/peripheral-loader.h +++ b/drivers/soc/qcom/peripheral-loader.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, 2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -116,7 +116,7 @@ struct md_ssr_toc /* Shared IMEM ToC struct */ */ struct pil_reset_ops { int (*init_image)(struct pil_desc *pil, const u8 *metadata, - size_t size); + size_t size, phys_addr_t addr, size_t sz); int (*mem_setup)(struct pil_desc *pil, phys_addr_t addr, size_t size); int (*verify_blob)(struct pil_desc *pil, phys_addr_t phy_addr, size_t size); diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c index f7d183a7bbcc..b7f55bbfe267 100644 --- a/drivers/soc/qcom/pil-msa.c +++ b/drivers/soc/qcom/pil-msa.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -685,7 +685,7 @@ err_invalid_fw: } static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata, - size_t size) + size_t size, phys_addr_t phy_addr, size_t phy_sz) { struct modem_data *drv = dev_get_drvdata(pil->dev); void *mdata_virt; @@ -715,6 +715,19 @@ static int pil_msa_auth_modem_mdt(struct pil_desc *pil, const u8 *metadata, wmb(); if (pil->subsys_vmid > 0) { + /** + * In case of modem ssr,we need to assign memory back to linux. + * This is not true after cold boot since linux already owns + * it. Also for secure boot devices, modem memory has to be + * released after MBA is booted + */ + if (pil->modem_ssr) { + ret = pil_assign_mem_to_linux(pil, phy_addr, phy_sz); + if (ret) + dev_err(pil->dev, + "Failed to assign to linux, ret- %d\n", + ret); + } ret = pil_assign_mem_to_subsys(pil, mdata_phys, ALIGN(size, SZ_4K)); if (ret) { @@ -769,7 +782,8 @@ fail: } static int pil_msa_mss_reset_mba_load_auth_mdt(struct pil_desc *pil, - const u8 *metadata, size_t size) + const u8 *metadata, size_t size, + phys_addr_t modem_reg, size_t sz_modem_reg) { int ret; @@ -777,7 +791,8 @@ static int pil_msa_mss_reset_mba_load_auth_mdt(struct pil_desc *pil, if (ret) return ret; - return pil_msa_auth_modem_mdt(pil, metadata, size); + return pil_msa_auth_modem_mdt(pil, metadata, size, + modem_reg, sz_modem_reg); } static int pil_msa_mba_verify_blob(struct pil_desc *pil, phys_addr_t phy_addr, diff --git a/drivers/soc/qcom/subsys-pil-tz.c b/drivers/soc/qcom/subsys-pil-tz.c index b448f5297f95..c6dff952ff3a 100644 --- a/drivers/soc/qcom/subsys-pil-tz.c +++ b/drivers/soc/qcom/subsys-pil-tz.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2017, 2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -582,7 +582,8 @@ static void pil_remove_proxy_vote(struct pil_desc *pil) } static int pil_init_image_trusted(struct pil_desc *pil, - const u8 *metadata, size_t size) + const u8 *metadata, size_t size, + phys_addr_t addr, size_t sz) { struct pil_tz_data *d = desc_to_data(pil); struct pas_init_image_req { -- cgit v1.2.3 From 27c90ea8af60f48cf043686cbd7c20f403e2d7b0 Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Thu, 26 Sep 2019 18:28:33 +0530 Subject: ASoC: Fix possible overflow in routing driver The reg in soc_mixer_control is 32-bit. When using SOC_SINGLE_EXT, the value of FE DAI ID which is passed as shift(to be operated on the reg) may be more than 31, which may cause overflow. Use SOC_DOUBLE_EXT instead of SOC_SINGLE_EXT so that the reg field can be set to SOC_NO_PM to avoid any DAPM operation, while passing BE and FE IDs in shift and rshift fields. And these values can be retrieve in get/put functions and use them. This is to avoid any possible overflow in DAPM operation. Change-Id: I17fa4e059889ae725e6f015a779f518e6d0a813f Signed-off-by: Soumya Managoli --- sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c | 7668 ++++++++++++++++++---------- 1 file changed, 5087 insertions(+), 2581 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index a923faf11c84..965de5ca4f66 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -1962,13 +1962,13 @@ static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0])) + if (test_bit(mc->rshift, &msm_bedais[mc->shift].fe_sessions[0])) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; - pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift, - ucontrol->value.integer.value[0]); + pr_debug("%s: shift %x rshift %x val %ld\n", __func__, mc->shift, + mc->rshift, ucontrol->value.integer.value[0]); return 0; } @@ -1984,12 +1984,12 @@ static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_update *update = NULL; if (ucontrol->value.integer.value[0] && - msm_pcm_routing_route_is_set(mc->reg, mc->shift) == false) { - msm_pcm_routing_process_audio(mc->reg, mc->shift, 1); + msm_pcm_routing_route_is_set(mc->shift, mc->rshift) == false) { + msm_pcm_routing_process_audio(mc->shift, mc->rshift, 1); snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1, update); } else if (!ucontrol->value.integer.value[0] && - msm_pcm_routing_route_is_set(mc->reg, mc->shift) == true) { - msm_pcm_routing_process_audio(mc->reg, mc->shift, 0); + msm_pcm_routing_route_is_set(mc->shift, mc->rshift) == true) { + msm_pcm_routing_process_audio(mc->shift, mc->rshift, 0); snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0, update); } @@ -2002,13 +2002,13 @@ static int msm_routing_get_listen_mixer(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0])) + if (test_bit(mc->rshift, &msm_bedais[mc->shift].fe_sessions[0])) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; - pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift, - ucontrol->value.integer.value[0]); + pr_debug("%s: shift %x rshift %x val %ld\n", __func__, mc->shift, + mc->rshift, ucontrol->value.integer.value[0]); return 0; } @@ -2023,17 +2023,18 @@ static int msm_routing_put_listen_mixer(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct snd_soc_dapm_update *update = NULL; - pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift, - ucontrol->value.integer.value[0]); + pr_debug("%s: shift %x rshift %x val %ld\n", __func__, mc->shift, + mc->rshift, ucontrol->value.integer.value[0]); if (ucontrol->value.integer.value[0]) { - if (msm_pcm_routing_route_is_set(mc->reg, mc->shift) == false) - msm_pcm_routing_process_audio(mc->reg, mc->shift, 1); + if (msm_pcm_routing_route_is_set(mc->shift, mc->rshift) == + false) + msm_pcm_routing_process_audio(mc->shift, mc->rshift, 1); snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1, update); } else if (!ucontrol->value.integer.value[0]) { - if (msm_pcm_routing_route_is_set(mc->reg, mc->shift) == true) - msm_pcm_routing_process_audio(mc->reg, mc->shift, 0); + if (msm_pcm_routing_route_is_set(mc->shift, mc->rshift) == true) + msm_pcm_routing_process_audio(mc->shift, mc->rshift, 0); snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0, update); } @@ -2118,15 +2119,15 @@ static int msm_routing_get_voice_mixer(struct snd_kcontrol *kcontrol, mutex_lock(&routing_lock); - if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0])) + if (test_bit(mc->rshift, &msm_bedais[mc->shift].fe_sessions[0])) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; mutex_unlock(&routing_lock); - pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift, - ucontrol->value.integer.value[0]); + pr_debug("%s: shift %x rshift %x val %ld\n", __func__, mc->shift, + mc->rshift, ucontrol->value.integer.value[0]); return 0; } @@ -2142,10 +2143,10 @@ static int msm_routing_put_voice_mixer(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_update *update = NULL; if (ucontrol->value.integer.value[0]) { - msm_pcm_routing_process_voice(mc->reg, mc->shift, 1); + msm_pcm_routing_process_voice(mc->shift, mc->rshift, 1); snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1, update); } else { - msm_pcm_routing_process_voice(mc->reg, mc->shift, 0); + msm_pcm_routing_process_voice(mc->shift, mc->rshift, 0); snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0, update); } @@ -2160,15 +2161,15 @@ static int msm_routing_get_voice_stub_mixer(struct snd_kcontrol *kcontrol, mutex_lock(&routing_lock); - if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0])) + if (test_bit(mc->rshift, &msm_bedais[mc->shift].fe_sessions[0])) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; mutex_unlock(&routing_lock); - pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift, - ucontrol->value.integer.value[0]); + pr_debug("%s: shift %x rshift %x val %ld\n", __func__, mc->shift, + mc->rshift, ucontrol->value.integer.value[0]); return 0; } @@ -2185,20 +2186,20 @@ static int msm_routing_put_voice_stub_mixer(struct snd_kcontrol *kcontrol, if (ucontrol->value.integer.value[0]) { mutex_lock(&routing_lock); - set_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0]); + set_bit(mc->rshift, &msm_bedais[mc->shift].fe_sessions[0]); mutex_unlock(&routing_lock); snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 1, update); } else { mutex_lock(&routing_lock); - clear_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions[0]); + clear_bit(mc->rshift, &msm_bedais[mc->shift].fe_sessions[0]); mutex_unlock(&routing_lock); snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, 0, update); } - pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift, - ucontrol->value.integer.value[0]); + pr_debug("%s: shift %x rshift %x val %ld\n", __func__, mc->shift, + mc->rshift, ucontrol->value.integer.value[0]); return 1; } @@ -2850,8 +2851,8 @@ static int msm_routing_get_port_mixer(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - idx = mc->shift/(sizeof(msm_bedais[mc->reg].port_sessions[0]) * 8); - shift = mc->shift%(sizeof(msm_bedais[mc->reg].port_sessions[0]) * 8); + idx = mc->rshift/(sizeof(msm_bedais[mc->shift].port_sessions[0]) * 8); + shift = mc->rshift%(sizeof(msm_bedais[mc->shift].port_sessions[0]) * 8); if (idx >= BE_DAI_PORT_SESSIONS_IDX_MAX) { pr_err("%s: Invalid idx = %d\n", __func__, idx); @@ -2859,13 +2860,13 @@ static int msm_routing_get_port_mixer(struct snd_kcontrol *kcontrol, } if (test_bit(shift, - (unsigned long *)&msm_bedais[mc->reg].port_sessions[idx])) + (unsigned long *)&msm_bedais[mc->shift].port_sessions[idx])) ucontrol->value.integer.value[0] = 1; else ucontrol->value.integer.value[0] = 0; - pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift, - ucontrol->value.integer.value[0]); + pr_debug("%s: shift %x rshift %x val %ld\n", __func__, mc->shift, + mc->rshift, ucontrol->value.integer.value[0]); return 0; } @@ -2877,8 +2878,8 @@ static int msm_routing_put_port_mixer(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - idx = mc->shift/(sizeof(msm_bedais[mc->reg].port_sessions[0]) * 8); - shift = mc->shift%(sizeof(msm_bedais[mc->reg].port_sessions[0]) * 8); + idx = mc->rshift/(sizeof(msm_bedais[mc->shift].port_sessions[0]) * 8); + shift = mc->rshift%(sizeof(msm_bedais[mc->shift].port_sessions[0]) * 8); if (idx >= BE_DAI_PORT_SESSIONS_IDX_MAX) { pr_err("%s: Invalid idx = %d\n", __func__, idx); @@ -2886,19 +2887,19 @@ static int msm_routing_put_port_mixer(struct snd_kcontrol *kcontrol, } pr_debug("%s: reg 0x%x shift 0x%x val %ld idx %d reminder shift %d\n", - __func__, mc->reg, mc->shift, + __func__, mc->shift, mc->rshift, ucontrol->value.integer.value[0], idx, shift); if (ucontrol->value.integer.value[0]) { - afe_loopback(1, msm_bedais[mc->reg].port_id, - msm_bedais[mc->shift].port_id); + afe_loopback(1, msm_bedais[mc->shift].port_id, + msm_bedais[mc->rshift].port_id); set_bit(shift, - (unsigned long *)&msm_bedais[mc->reg].port_sessions[idx]); + (unsigned long *)&msm_bedais[mc->shift].port_sessions[idx]); } else { - afe_loopback(0, msm_bedais[mc->reg].port_id, - msm_bedais[mc->shift].port_id); + afe_loopback(0, msm_bedais[mc->shift].port_id, + msm_bedais[mc->rshift].port_id); clear_bit(shift, - (unsigned long *)&msm_bedais[mc->reg].port_sessions[idx]); + (unsigned long *)&msm_bedais[mc->shift].port_sessions[idx]); } return 1; @@ -4082,8370 +4083,10874 @@ static const struct snd_kcontrol_new voc_ext_ec_mux = static const struct snd_kcontrol_new pri_i2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_I2S_RX , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_I2S_RX , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SPDIF_RX , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_SPDIF_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_2_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_2_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_2_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_5_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_5_RX , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_SLIMBUS_5_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_0_RX , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia23", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia24", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia25", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_MI2S_RX , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUINARY_MI2S_RX , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERTIARY_MI2S_RX , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new secondary_mi2s_rx2_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_SD1, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_SD1, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new secondary_mi2s_rx_1_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new secondary_mi2s_rx_2_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new secondary_mi2s_rx_3_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new secondary_mi2s_rx_4_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tertiary_mi2s_rx_1_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tertiary_mi2s_rx_2_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tertiary_mi2s_rx_3_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tertiary_mi2s_rx_4_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quaternary_mi2s_rx_1_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quaternary_mi2s_rx_2_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quaternary_mi2s_rx_3_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quaternary_mi2s_rx_4_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SECONDARY_MI2S_RX , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_MI2S_RX , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int0_mi2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int4_mi2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new hdmi_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia23", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia24", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia25", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new display_port_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; /* incall music delivery mixer */ static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new incall_music2_delivery_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_4_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_4_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_4_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_4_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_4_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_4_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_4_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SLIMBUS_4_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_4_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_6_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia23", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia24", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia25", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new slimbus_7_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia23", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia23", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA23, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia24", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia24", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA24, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia25", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia25", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA25, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new usb_audio_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int_bt_sco_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int_bt_a2dp_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT_BT_A2DP_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_A2DP_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new int_fm_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_INT_FM_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new afe_pcm_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new auxpcm_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia17", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia18", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia19", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia28", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia29", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_auxpcm_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_auxpcm_rx_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_0_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_1_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_2_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_3_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_tdm_tx_0_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_0_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_1_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_2_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_3_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new sec_tdm_tx_0_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_0_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_0 , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_tx_0_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_1_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_1 , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_2_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_2 , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_3_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_3 , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_4_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_TERT_TDM_RX_4, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_4, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_0_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_RX_0 , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia20", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_tdm_tx_0_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_1_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_RX_1 , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia20", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_2_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_RX_2 , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia20", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_3_mixer_controls[] = { - SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_QUAT_TDM_RX_3 , + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia9", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia10", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia11", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia12", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia13", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia14", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia15", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia16", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia20", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia20", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia21", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia21", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia22", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia22", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA22, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MultiMedia26", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("MultiMedia26", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_FRONTEND_DAI_MULTIMEDIA26, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul1_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_TX", MSM_BACKEND_DAI_PRI_I2S_TX, + SOC_DOUBLE_EXT("PRI_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX, + SOC_DOUBLE_EXT("INT2_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT2_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_DOUBLE_EXT("TERT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + SOC_DOUBLE_EXT("VOC_REC_DL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + SOC_DOUBLE_EXT("VOC_REC_UL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX, + SOC_DOUBLE_EXT("SLIM_4_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_4_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX, + SOC_DOUBLE_EXT("SLIM_6_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUIN_MI2S_TX", MSM_BACKEND_DAI_QUINARY_MI2S_TX, + SOC_DOUBLE_EXT("QUIN_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX, + SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_8_TX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_1", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_1, + SOC_DOUBLE_EXT("SEC_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_2", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_2, + SOC_DOUBLE_EXT("SEC_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_3", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_3, + SOC_DOUBLE_EXT("SEC_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_4", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_4, + SOC_DOUBLE_EXT("SEC_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_1", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_1, + SOC_DOUBLE_EXT("TERT_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_2", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_2, + SOC_DOUBLE_EXT("TERT_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_3", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_3, + SOC_DOUBLE_EXT("TERT_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_4", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_4, + SOC_DOUBLE_EXT("TERT_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_1", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_1, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_2", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_2, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_3", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_3, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_4", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_4, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul2_mixer_controls[] = { - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX, + SOC_DOUBLE_EXT("INT2_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT2_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX, + SOC_DOUBLE_EXT("SLIM_6_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX, + SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUIN_MI2S_TX", MSM_BACKEND_DAI_QUINARY_MI2S_TX, + SOC_DOUBLE_EXT("QUIN_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_8_TX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_1", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_1, + SOC_DOUBLE_EXT("SEC_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_2", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_2, + SOC_DOUBLE_EXT("SEC_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_3", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_3, + SOC_DOUBLE_EXT("SEC_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_4", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_4, + SOC_DOUBLE_EXT("SEC_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_1", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_1, + SOC_DOUBLE_EXT("TERT_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_2", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_2, + SOC_DOUBLE_EXT("TERT_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_3", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_3, + SOC_DOUBLE_EXT("TERT_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_4", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_4, + SOC_DOUBLE_EXT("TERT_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_1", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_1, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_2", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_2, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_3", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_3, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_4", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_4, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul3_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AUX_PCM_TX", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_DOUBLE_EXT("TERT_AUX_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUX_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX, + SOC_DOUBLE_EXT("INT2_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT2_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_1", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_1, + SOC_DOUBLE_EXT("SEC_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_2", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_2, + SOC_DOUBLE_EXT("SEC_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_3", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_3, + SOC_DOUBLE_EXT("SEC_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_4", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_4, + SOC_DOUBLE_EXT("SEC_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_1", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_1, + SOC_DOUBLE_EXT("TERT_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_2", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_2, + SOC_DOUBLE_EXT("TERT_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_3", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_3, + SOC_DOUBLE_EXT("TERT_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_4", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_4, + SOC_DOUBLE_EXT("TERT_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_1", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_1, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_2", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_2, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_3", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_3, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_4", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_4, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul4_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + SOC_DOUBLE_EXT("VOC_REC_DL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + SOC_DOUBLE_EXT("VOC_REC_UL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_TX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX, + SOC_DOUBLE_EXT("INT2_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT2_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul5_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_DOUBLE_EXT("TERT_AUX_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUX_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX, + SOC_DOUBLE_EXT("INT2_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT2_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX, + SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_8_TX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_1", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_1, + SOC_DOUBLE_EXT("SEC_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_2", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_2, + SOC_DOUBLE_EXT("SEC_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_3", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_3, + SOC_DOUBLE_EXT("SEC_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_4", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_4, + SOC_DOUBLE_EXT("SEC_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_1", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_1, + SOC_DOUBLE_EXT("TERT_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_2", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_2, + SOC_DOUBLE_EXT("TERT_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_3", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_3, + SOC_DOUBLE_EXT("TERT_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_4", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_4, + SOC_DOUBLE_EXT("TERT_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_1", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_1, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_2", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_2, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_3", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_3, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_4", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_4, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul6_mixer_controls[] = { - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX, + SOC_DOUBLE_EXT("INT2_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT2_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_DOUBLE_EXT("TERT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul8_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX, + SOC_DOUBLE_EXT("INT2_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT2_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + SOC_DOUBLE_EXT("VOC_REC_DL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + SOC_DOUBLE_EXT("VOC_REC_UL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX, + SOC_DOUBLE_EXT("SLIM_6_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX, + SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul16_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT2_MI2S_TX", MSM_BACKEND_DAI_INT2_MI2S_TX, + SOC_DOUBLE_EXT("INT2_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT2_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + SOC_DOUBLE_EXT("VOC_REC_DL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + SOC_DOUBLE_EXT("VOC_REC_UL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX, + SOC_DOUBLE_EXT("SLIM_6_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX, + SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AUX_PCM_TX", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUX_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul9_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + SOC_DOUBLE_EXT("VOC_REC_DL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + SOC_DOUBLE_EXT("VOC_REC_UL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_TX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SLIM_6_TX", MSM_BACKEND_DAI_SLIMBUS_6_TX, + SOC_DOUBLE_EXT("SLIM_6_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_TX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_1", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_1, + SOC_DOUBLE_EXT("SEC_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_2", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_2, + SOC_DOUBLE_EXT("SEC_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_3", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_3, + SOC_DOUBLE_EXT("SEC_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_4", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_4, + SOC_DOUBLE_EXT("SEC_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_1", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_1, + SOC_DOUBLE_EXT("TERT_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_2", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_2, + SOC_DOUBLE_EXT("TERT_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_3", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_3, + SOC_DOUBLE_EXT("TERT_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_4", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_4, + SOC_DOUBLE_EXT("TERT_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_1", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_1, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_2", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_2, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_3", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_3, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_4", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_4, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul17_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + SOC_DOUBLE_EXT("VOC_REC_DL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + SOC_DOUBLE_EXT("VOC_REC_UL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_TX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul18_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + SOC_DOUBLE_EXT("VOC_REC_DL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + SOC_DOUBLE_EXT("VOC_REC_UL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_TX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul19_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + SOC_DOUBLE_EXT("VOC_REC_DL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + SOC_DOUBLE_EXT("VOC_REC_UL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_TX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul20_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_1", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_1, + SOC_DOUBLE_EXT("SEC_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_2", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_2, + SOC_DOUBLE_EXT("SEC_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_3", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_3, + SOC_DOUBLE_EXT("SEC_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_4", MSM_BACKEND_DAI_SECONDARY_MI2S_TX_4, + SOC_DOUBLE_EXT("SEC_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_1", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_1, + SOC_DOUBLE_EXT("TERT_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_2", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_2, + SOC_DOUBLE_EXT("TERT_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_3", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_3, + SOC_DOUBLE_EXT("TERT_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_4", MSM_BACKEND_DAI_TERTIARY_MI2S_TX_4, + SOC_DOUBLE_EXT("TERT_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_1", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_1, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_2", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_2, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_3", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_3, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX_4", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_4, + SOC_DOUBLE_EXT("QUAT_MI2S_TX_4", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX_4, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul21_mixer_controls[] = { - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_TX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_TX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_TX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_TX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_TX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_TX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_TX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_TX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_TX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_TX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_TX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_TX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_TX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_TX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_2, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_TX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_3, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA21, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul27_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA27, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA27, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA27, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul28_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + SOC_DOUBLE_EXT("VOC_REC_DL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + SOC_DOUBLE_EXT("VOC_REC_UL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_TX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul29_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT_FM_TX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_FM_TX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_DL", MSM_BACKEND_DAI_INCALL_RECORD_RX, + SOC_DOUBLE_EXT("VOC_REC_DL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), - SOC_SINGLE_EXT("VOC_REC_UL", MSM_BACKEND_DAI_INCALL_RECORD_TX, + SOC_DOUBLE_EXT("VOC_REC_UL", SND_SOC_NOPM, + MSM_BACKEND_DAI_INCALL_RECORD_TX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_PRI_I2S_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new sec_mi2s_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_0_RX , + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX , + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SLIMBUS_0_RX , + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_0_RX , + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SLIMBUS_0_RX , + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new slimbus_6_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_6_RX , + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_6_RX , + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SLIMBUS_6_RX , + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_6_RX , + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SLIMBUS_6_RX , + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new usb_audio_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT_BT_SCO_RX , + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX , + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_INT_BT_SCO_RX , + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT_BT_SCO_RX , + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_INT_BT_SCO_RX , + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new mi2s_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new pri_mi2s_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new int0_mi2s_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new int4_mi2s_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new tert_mi2s_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new quat_mi2s_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new quin_mi2s_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_QUINARY_MI2S_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new afe_pcm_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new aux_pcm_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new sec_aux_pcm_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new tert_aux_pcm_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new quat_aux_pcm_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new hdmi_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new slimbus_7_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_SLIMBUS_7_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new slimbus_8_rx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SLIMBUS_8_RX, + SOC_DOUBLE_EXT("CSVoice", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_RX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice2", MSM_BACKEND_DAI_SLIMBUS_8_RX, + SOC_DOUBLE_EXT("Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_RX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SLIMBUS_8_RX, + SOC_DOUBLE_EXT("Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_RX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_8_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_8_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_8_RX, + SOC_DOUBLE_EXT("VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_RX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_8_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoWLAN", MSM_BACKEND_DAI_SLIMBUS_8_RX, + SOC_DOUBLE_EXT("VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_RX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_SLIMBUS_8_RX, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_RX, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QCHAT", MSM_BACKEND_DAI_SLIMBUS_8_RX, + SOC_DOUBLE_EXT("QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_RX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_SLIMBUS_8_RX, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_RX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("VoiceMMode2", MSM_BACKEND_DAI_SLIMBUS_8_RX, + SOC_DOUBLE_EXT("VoiceMMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_RX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_2_voice_mixer_controls[] = { - SOC_SINGLE_EXT("VoiceMMode1", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("VoiceMMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("DTMF", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("DTMF", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_FRONTEND_DAI_DTMF_RX, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new stub_rx_mixer_controls[] = { - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_EXTPROC_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_EXTPROC_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_EXTPROC_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_EXTPROC_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_EXTPROC_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_EXTPROC_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), }; static const struct snd_kcontrol_new slimbus_1_rx_mixer_controls[] = { - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_1_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_1_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_1_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), }; static const struct snd_kcontrol_new slimbus_3_rx_mixer_controls[] = { - SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_3_RX, + SOC_DOUBLE_EXT("Voice Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_RX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("Voice2 Stub", MSM_BACKEND_DAI_SLIMBUS_3_RX, + SOC_DOUBLE_EXT("Voice2 Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_RX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("VoLTE Stub", MSM_BACKEND_DAI_SLIMBUS_3_RX, + SOC_DOUBLE_EXT("VoLTE Stub", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_RX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), }; static const struct snd_kcontrol_new tx_voice_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_TX_Voice", MSM_BACKEND_DAI_PRI_I2S_TX, + SOC_DOUBLE_EXT("PRI_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("MI2S_TX_Voice", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_0_TX_Voice", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voice", + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX_Voice", SND_SOC_NOPM, MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX_Voice", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AUX_PCM_TX_Voice", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voice", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_TX_Voice", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_DOUBLE_EXT("TERT_AUX_PCM_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_Voice", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUX_PCM_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX_Voice", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX_Voice", MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + SOC_DOUBLE_EXT("SEC_MI2S_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_Voice", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_7_TX_Voice", MSM_BACKEND_DAI_SLIMBUS_7_TX, + SOC_DOUBLE_EXT("SLIM_7_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_8_TX_Voice", MSM_BACKEND_DAI_SLIMBUS_8_TX, + SOC_DOUBLE_EXT("SLIM_8_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX_Voice", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX_Voice", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new tx_voice2_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_TX_Voice2", MSM_BACKEND_DAI_PRI_I2S_TX, + SOC_DOUBLE_EXT("PRI_TX_Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("MI2S_TX_Voice2", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX_Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_0_TX_Voice2", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX_Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voice2", + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX_Voice2", SND_SOC_NOPM, MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX_Voice2", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX_Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AUX_PCM_TX_Voice2", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_TX_Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voice2", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_TX_Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_TX_Voice2", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_DOUBLE_EXT("TERT_AUX_PCM_TX_Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_Voice2", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUX_PCM_TX_Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX_Voice2", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX_Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_Voice2", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX_Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_7_TX_Voice2", MSM_BACKEND_DAI_SLIMBUS_7_TX, + SOC_DOUBLE_EXT("SLIM_7_TX_Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_8_TX_Voice2", MSM_BACKEND_DAI_SLIMBUS_8_TX, + SOC_DOUBLE_EXT("SLIM_8_TX_Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX_Voice2", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX_Voice2", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_VOICE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new tx_volte_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_TX_VoLTE", MSM_BACKEND_DAI_PRI_I2S_TX, + SOC_DOUBLE_EXT("PRI_TX_VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_0_TX_VoLTE", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX_VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_VoLTE", + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX_VoLTE", SND_SOC_NOPM, MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX_VoLTE", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX_VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AUX_PCM_TX_VoLTE", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_TX_VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_TX_VoLTE", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_TX_VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_TX_VoLTE", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_DOUBLE_EXT("TERT_AUX_PCM_TX_VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_VoLTE", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUX_PCM_TX_VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("MI2S_TX_VoLTE", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX_VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX_VoLTE", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX_VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_VoLTE", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX_VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_7_TX_VoLTE", MSM_BACKEND_DAI_SLIMBUS_7_TX, + SOC_DOUBLE_EXT("SLIM_7_TX_VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_8_TX_VoLTE", MSM_BACKEND_DAI_SLIMBUS_8_TX, + SOC_DOUBLE_EXT("SLIM_8_TX_VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX_VoLTE", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX_VoLTE", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new tx_vowlan_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_TX_VoWLAN", MSM_BACKEND_DAI_PRI_I2S_TX, + SOC_DOUBLE_EXT("PRI_TX_VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_0_TX_VoWLAN", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX_VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_VoWLAN", + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX_VoWLAN", SND_SOC_NOPM, MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX_VoWLAN", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX_VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AUX_PCM_TX_VoWLAN", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_TX_VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_TX_VoWLAN", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_TX_VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_TX_VoWLAN", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_DOUBLE_EXT("TERT_AUX_PCM_TX_VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_VoWLAN", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUX_PCM_TX_VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("MI2S_TX_VoWLAN", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX_VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX_VoWLAN", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX_VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_VoWLAN", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX_VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_7_TX_VoWLAN", MSM_BACKEND_DAI_SLIMBUS_7_TX, + SOC_DOUBLE_EXT("SLIM_7_TX_VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_8_TX_VoWLAN", MSM_BACKEND_DAI_SLIMBUS_8_TX, + SOC_DOUBLE_EXT("SLIM_8_TX_VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX_VoWLAN", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX_VoWLAN", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_VOWLAN, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new tx_voicemmode1_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_TX_MMode1", MSM_BACKEND_DAI_PRI_I2S_TX, + SOC_DOUBLE_EXT("PRI_TX_MMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("MI2S_TX_MMode1", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX_MMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_0_TX_MMode1", + SOC_DOUBLE_EXT("SLIM_0_TX_MMode1", SND_SOC_NOPM, MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("INT_BT_SCO_TX_MMode1", + SOC_DOUBLE_EXT("INT_BT_SCO_TX_MMode1", SND_SOC_NOPM, MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX_MMode1", + SOC_DOUBLE_EXT("AFE_PCM_TX_MMode1", SND_SOC_NOPM, MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AUX_PCM_TX_MMode1", + SOC_DOUBLE_EXT("AUX_PCM_TX_MMode1", SND_SOC_NOPM, MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_TX_MMode1", + SOC_DOUBLE_EXT("SEC_AUX_PCM_TX_MMode1", SND_SOC_NOPM, MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_TX_MMode1", + SOC_DOUBLE_EXT("TERT_AUX_PCM_TX_MMode1", SND_SOC_NOPM, MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_MMode1", + SOC_DOUBLE_EXT("QUAT_AUX_PCM_TX_MMode1", SND_SOC_NOPM, MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX_MMode1", + SOC_DOUBLE_EXT("PRI_MI2S_TX_MMode1", SND_SOC_NOPM, MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_MMode1", + SOC_DOUBLE_EXT("TERT_MI2S_TX_MMode1", SND_SOC_NOPM, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX_MMode1", + SOC_DOUBLE_EXT("INT3_MI2S_TX_MMode1", SND_SOC_NOPM, MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_7_TX_MMode1", + SOC_DOUBLE_EXT("SLIM_7_TX_MMode1", SND_SOC_NOPM, MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_8_TX_MMode1", + SOC_DOUBLE_EXT("SLIM_8_TX_MMode1", SND_SOC_NOPM, MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX_MMode1", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX_MMode1", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0_MMode1", + SOC_DOUBLE_EXT("QUAT_TDM_TX_0_MMode1", SND_SOC_NOPM, MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_VOICEMMODE1, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new tx_voicemmode2_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_TX_MMode2", MSM_BACKEND_DAI_PRI_I2S_TX, + SOC_DOUBLE_EXT("PRI_TX_MMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("MI2S_TX_MMode2", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX_MMode2", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_0_TX_MMode2", + SOC_DOUBLE_EXT("SLIM_0_TX_MMode2", SND_SOC_NOPM, MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("INT_BT_SCO_TX_MMode2", + SOC_DOUBLE_EXT("INT_BT_SCO_TX_MMode2", SND_SOC_NOPM, MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX_MMode2", + SOC_DOUBLE_EXT("AFE_PCM_TX_MMode2", SND_SOC_NOPM, MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AUX_PCM_TX_MMode2", + SOC_DOUBLE_EXT("AUX_PCM_TX_MMode2", SND_SOC_NOPM, MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_TX_MMode2", + SOC_DOUBLE_EXT("SEC_AUX_PCM_TX_MMode2", SND_SOC_NOPM, MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_TX_MMode2", + SOC_DOUBLE_EXT("TERT_AUX_PCM_TX_MMode2", SND_SOC_NOPM, MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_MMode2", + SOC_DOUBLE_EXT("QUAT_AUX_PCM_TX_MMode2", SND_SOC_NOPM, MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX_MMode2", + SOC_DOUBLE_EXT("PRI_MI2S_TX_MMode2", SND_SOC_NOPM, MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_MMode2", + SOC_DOUBLE_EXT("TERT_MI2S_TX_MMode2", SND_SOC_NOPM, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX_MMode2", + SOC_DOUBLE_EXT("INT3_MI2S_TX_MMode2", SND_SOC_NOPM, MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_7_TX_MMode2", + SOC_DOUBLE_EXT("SLIM_7_TX_MMode2", SND_SOC_NOPM, MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_8_TX_MMode2", + SOC_DOUBLE_EXT("SLIM_8_TX_MMode2", SND_SOC_NOPM, MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX_MMode2", + SOC_DOUBLE_EXT("USB_AUDIO_TX_MMode2", SND_SOC_NOPM, MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_VOICEMMODE2, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new tx_voip_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_TX_Voip", MSM_BACKEND_DAI_PRI_I2S_TX, + SOC_DOUBLE_EXT("PRI_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("MI2S_TX_Voip", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_0_TX_Voip", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_Voip", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX_Voip", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AUX_PCM_TX_Voip", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voip", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_TX_Voip", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_DOUBLE_EXT("TERT_AUX_PCM_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_Voip", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUX_PCM_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX_Voip", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_Voip", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX_Voip", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_7_TX_Voip", MSM_BACKEND_DAI_SLIMBUS_7_TX, + SOC_DOUBLE_EXT("SLIM_7_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_8_TX_Voip", MSM_BACKEND_DAI_SLIMBUS_8_TX, + SOC_DOUBLE_EXT("SLIM_8_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX_Voip", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX_Voip", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = { - SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_EXTPROC_TX, + SOC_DOUBLE_EXT("STUB_TX_HL", SND_SOC_NOPM, + MSM_BACKEND_DAI_EXTPROC_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX, + SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("STUB_1_TX_HL", MSM_BACKEND_DAI_EXTPROC_EC_TX, + SOC_DOUBLE_EXT("STUB_1_TX_HL", SND_SOC_NOPM, + MSM_BACKEND_DAI_EXTPROC_EC_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_DOUBLE_EXT("TERT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX, + SOC_DOUBLE_EXT("SLIM_3_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX, + SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_8_TX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), }; static const struct snd_kcontrol_new tx_voice2_stub_mixer_controls[] = { - SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_EXTPROC_TX, + SOC_DOUBLE_EXT("STUB_TX_HL", SND_SOC_NOPM, + MSM_BACKEND_DAI_EXTPROC_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX, + SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("STUB_1_TX_HL", MSM_BACKEND_DAI_EXTPROC_EC_TX, + SOC_DOUBLE_EXT("STUB_1_TX_HL", SND_SOC_NOPM, + MSM_BACKEND_DAI_EXTPROC_EC_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_DOUBLE_EXT("TERT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX, + SOC_DOUBLE_EXT("SLIM_3_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX, + SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_8_TX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_VOICE2_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), }; static const struct snd_kcontrol_new tx_volte_stub_mixer_controls[] = { - SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_EXTPROC_TX, + SOC_DOUBLE_EXT("STUB_TX_HL", SND_SOC_NOPM, + MSM_BACKEND_DAI_EXTPROC_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX, + SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("STUB_1_TX_HL", MSM_BACKEND_DAI_EXTPROC_EC_TX, + SOC_DOUBLE_EXT("STUB_1_TX_HL", SND_SOC_NOPM, + MSM_BACKEND_DAI_EXTPROC_EC_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_DOUBLE_EXT("TERT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX, + SOC_DOUBLE_EXT("SLIM_3_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_7_TX, + SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_8_TX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_VOLTE_STUB, 1, 0, msm_routing_get_voice_stub_mixer, msm_routing_put_voice_stub_mixer), }; static const struct snd_kcontrol_new tx_qchat_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_TX_QCHAT", MSM_BACKEND_DAI_PRI_I2S_TX, + SOC_DOUBLE_EXT("PRI_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_I2S_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_0_TX_QCHAT", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIM_0_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_QCHAT", + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX_QCHAT", SND_SOC_NOPM, MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX_QCHAT", MSM_BACKEND_DAI_AFE_PCM_TX, + SOC_DOUBLE_EXT("AFE_PCM_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_AUXPCM_TX, + SOC_DOUBLE_EXT("AUX_PCM_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_SEC_AUXPCM_TX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_TERT_AUXPCM_TX, + SOC_DOUBLE_EXT("TERT_AUX_PCM_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("QUAT_AUX_PCM_TX_QCHAT", MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + SOC_DOUBLE_EXT("QUAT_AUX_PCM_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("MI2S_TX_QCHAT", MSM_BACKEND_DAI_MI2S_TX, + SOC_DOUBLE_EXT("MI2S_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX_QCHAT", MSM_BACKEND_DAI_PRI_MI2S_TX, + SOC_DOUBLE_EXT("PRI_MI2S_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX_QCHAT", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX_QCHAT", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_7_TX_QCHAT", MSM_BACKEND_DAI_SLIMBUS_7_TX, + SOC_DOUBLE_EXT("SLIM_7_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_7_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("SLIM_8_TX_QCHAT", MSM_BACKEND_DAI_SLIMBUS_8_TX, + SOC_DOUBLE_EXT("SLIM_8_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_8_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), - SOC_SINGLE_EXT("USB_AUDIO_TX_QCHAT", MSM_BACKEND_DAI_USB_TX, + SOC_DOUBLE_EXT("USB_AUDIO_TX_QCHAT", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_TX, MSM_FRONTEND_DAI_QCHAT, 1, 0, msm_routing_get_voice_mixer, msm_routing_put_voice_mixer), }; static const struct snd_kcontrol_new int0_mi2s_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_BACKEND_DAI_INT3_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_7_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_INT0_MI2S_RX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT0_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new int4_mi2s_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_BACKEND_DAI_INT3_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_7_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_INT4_MI2S_RX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT4_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_SLIMBUS_7_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("TERT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_TERT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("QUAT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_QUAT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_MI2S_RX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("PRI_MI2S_RX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_PRI_MI2S_RX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_RX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("SEC_MI2S_RX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_SECONDARY_MI2S_RX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_MI2S_RX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("TERT_MI2S_RX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_TERTIARY_MI2S_RX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_RX", MSM_BACKEND_DAI_SLIMBUS_0_RX, + SOC_DOUBLE_EXT("QUAT_MI2S_RX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_RX, MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new aux_pcm_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_AUXPCM_RX, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_AUXPCM_RX, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new sec_auxpcm_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_RX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new tert_auxpcm_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("TERT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_BACKEND_DAI_TERT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_AUXPCM_RX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_AUXPCM_RX, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new quat_auxpcm_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("QUAT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_BACKEND_DAI_QUAT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_AUXPCM_RX, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new sbus_1_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_RX, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_RX, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_RX, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_RX, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_AUXPCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX, + SOC_DOUBLE_EXT("TERT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_RX, MSM_BACKEND_DAI_TERT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_AUXPCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_1_RX, + SOC_DOUBLE_EXT("QUAT_AUXPCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_RX, MSM_BACKEND_DAI_QUAT_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new sbus_3_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("INTERNAL_BT_SCO_RX", MSM_BACKEND_DAI_SLIMBUS_3_RX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_RX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_RX, MSM_BACKEND_DAI_INT_BT_SCO_RX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_3_RX, + SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_RX, MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_RX", MSM_BACKEND_DAI_SLIMBUS_3_RX, + SOC_DOUBLE_EXT("AFE_PCM_RX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_RX, MSM_BACKEND_DAI_AFE_PCM_RX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_RX", MSM_BACKEND_DAI_SLIMBUS_3_RX, + SOC_DOUBLE_EXT("AUX_PCM_RX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_RX, MSM_BACKEND_DAI_AUXPCM_RX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_0_RX", MSM_BACKEND_DAI_SLIMBUS_3_RX, + SOC_DOUBLE_EXT("SLIM_0_RX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_RX, MSM_BACKEND_DAI_SLIMBUS_0_RX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new sbus_6_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_7_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("SLIM_7_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_SLIMBUS_7_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SLIMBUS_6_RX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_6_RX, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new bt_sco_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT_BT_SCO_RX, MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new afe_pcm_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_AFE_PCM_RX, + SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_AFE_PCM_RX, MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new hdmi_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_HDMI_RX, + SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_HDMI_RX, MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new display_port_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_DISPLAY_PORT_RX, + SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_DISPLAY_PORT_RX, MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new sec_i2s_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_SEC_I2S_RX, + SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_I2S_RX, MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new mi2s_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("SLIM_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_RX, + SOC_DOUBLE_EXT("MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_MI2S_RX, MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new primary_mi2s_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUIN_MI2S_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("QUIN_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_BACKEND_DAI_QUINARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_PRI_MI2S_RX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new usb_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("USB_AUDIO_TX", MSM_BACKEND_DAI_USB_RX, + SOC_DOUBLE_EXT("USB_AUDIO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_USB_RX, MSM_BACKEND_DAI_USB_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new quat_mi2s_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_0_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_1_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_2_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new pri_tdm_rx_3_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_PRI_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_0_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_SEC_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_SEC_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_SEC_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_SEC_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_1_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_SEC_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_SEC_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_SEC_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_SEC_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_2_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_SEC_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_SEC_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_SEC_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_SEC_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new sec_tdm_rx_3_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_SEC_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_SEC_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_SEC_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("SEC_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_SEC_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_SEC_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_0_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_1_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_2_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new tert_tdm_rx_3_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_TERT_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERT_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_0_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_0, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_1_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_1, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_1, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_2_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_2, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_2, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new quat_tdm_rx_3_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("INTERNAL_BT_SCO_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_INT_BT_SCO_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AFE_PCM_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("AFE_PCM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_AFE_PCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("SEC_AUX_PCM_UL_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_SEC_AUXPCM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_PRI_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_PRI_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_PRI_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("PRI_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("PRI_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_PRI_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_TERT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_TERT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_TERT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("TERT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_TERT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_0, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_1", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_1", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_1, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_2", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_2", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_2, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_3", MSM_BACKEND_DAI_QUAT_TDM_RX_3, + SOC_DOUBLE_EXT("QUAT_TDM_TX_3", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_RX_3, MSM_BACKEND_DAI_QUAT_TDM_TX_3, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new tert_mi2s_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new sec_mi2s_rx_port_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("PRI_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_PRI_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_SECONDARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_0_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_0_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("INTERNAL_FM_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("INTERNAL_FM_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_INT_FM_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), - SOC_SINGLE_EXT("SLIM_8_TX", MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + SOC_DOUBLE_EXT("SLIM_8_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_RX, MSM_BACKEND_DAI_SLIMBUS_8_TX, 1, 0, msm_routing_get_port_mixer, msm_routing_put_port_mixer), }; static const struct snd_kcontrol_new lsm1_mixer_controls[] = { - SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIMBUS_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX, + SOC_DOUBLE_EXT("SLIMBUS_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_TX, MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX, + SOC_DOUBLE_EXT("SLIMBUS_3_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_TX, MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX, + SOC_DOUBLE_EXT("SLIMBUS_4_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_4_TX, MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX, + SOC_DOUBLE_EXT("SLIMBUS_5_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_TX, MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_LSM1, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm2_mixer_controls[] = { - SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIMBUS_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX, + SOC_DOUBLE_EXT("SLIMBUS_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_TX, MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX, + SOC_DOUBLE_EXT("SLIMBUS_3_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_TX, MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX, + SOC_DOUBLE_EXT("SLIMBUS_4_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_4_TX, MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX, + SOC_DOUBLE_EXT("SLIMBUS_5_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_TX, MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_LSM2, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm3_mixer_controls[] = { - SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIMBUS_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX, + SOC_DOUBLE_EXT("SLIMBUS_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_TX, MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX, + SOC_DOUBLE_EXT("SLIMBUS_3_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_TX, MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX, + SOC_DOUBLE_EXT("SLIMBUS_4_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_4_TX, MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX, + SOC_DOUBLE_EXT("SLIMBUS_5_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_TX, MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_LSM3, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm4_mixer_controls[] = { - SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIMBUS_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX, + SOC_DOUBLE_EXT("SLIMBUS_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_TX, MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX, + SOC_DOUBLE_EXT("SLIMBUS_3_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_TX, MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX, + SOC_DOUBLE_EXT("SLIMBUS_4_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_4_TX, MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX, + SOC_DOUBLE_EXT("SLIMBUS_5_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_TX, MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_LSM4, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm5_mixer_controls[] = { - SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIMBUS_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX, + SOC_DOUBLE_EXT("SLIMBUS_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_TX, MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX, + SOC_DOUBLE_EXT("SLIMBUS_3_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_TX, MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX, + SOC_DOUBLE_EXT("SLIMBUS_4_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_4_TX, MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX, + SOC_DOUBLE_EXT("SLIMBUS_5_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_TX, MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_LSM5, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm6_mixer_controls[] = { - SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIMBUS_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX, + SOC_DOUBLE_EXT("SLIMBUS_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_TX, MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX, + SOC_DOUBLE_EXT("SLIMBUS_3_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_TX, MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX, + SOC_DOUBLE_EXT("SLIMBUS_4_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_4_TX, MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX, + SOC_DOUBLE_EXT("SLIMBUS_5_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_TX, MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_LSM6, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm7_mixer_controls[] = { - SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIMBUS_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX, + SOC_DOUBLE_EXT("SLIMBUS_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_TX, MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX, + SOC_DOUBLE_EXT("SLIMBUS_3_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_TX, MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX, + SOC_DOUBLE_EXT("SLIMBUS_4_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_4_TX, MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX, + SOC_DOUBLE_EXT("SLIMBUS_5_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_TX, MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_LSM7, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), }; static const struct snd_kcontrol_new lsm8_mixer_controls[] = { - SOC_SINGLE_EXT("SLIMBUS_0_TX", MSM_BACKEND_DAI_SLIMBUS_0_TX, + SOC_DOUBLE_EXT("SLIMBUS_0_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_0_TX, MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX, + SOC_DOUBLE_EXT("SLIMBUS_1_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_1_TX, MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX, + SOC_DOUBLE_EXT("SLIMBUS_3_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_3_TX, MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_4_TX", MSM_BACKEND_DAI_SLIMBUS_4_TX, + SOC_DOUBLE_EXT("SLIMBUS_4_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_4_TX, MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("SLIMBUS_5_TX", MSM_BACKEND_DAI_SLIMBUS_5_TX, + SOC_DOUBLE_EXT("SLIMBUS_5_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SLIMBUS_5_TX, MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + SOC_DOUBLE_EXT("QUAT_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_MI2S_TX, + SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), - SOC_SINGLE_EXT("QUAT_TDM_TX_0", MSM_BACKEND_DAI_QUAT_TDM_TX_0, + SOC_DOUBLE_EXT("QUAT_TDM_TX_0", SND_SOC_NOPM, + MSM_BACKEND_DAI_QUAT_TDM_TX_0, MSM_FRONTEND_DAI_LSM8, 1, 0, msm_routing_get_listen_mixer, msm_routing_put_listen_mixer), }; + static const struct snd_kcontrol_new slim_fm_switch_mixer_controls = SOC_SINGLE_EXT("Switch", SND_SOC_NOPM, 0, 1, 0, msm_routing_get_switch_mixer, @@ -12773,6 +15278,7 @@ static int msm_routing_put_lsm_app_type_cfg_control( __func__); return -EINVAL; } + for (j = 0; j < num_app_types; j++) { lsm_app_type_cfg[j].app_type = ucontrol->value.integer.value[i++]; @@ -13400,28 +15906,28 @@ static const int const int4_mi2s_rx_vi_fb_tx_stereo_ch_value[] = { }; static const struct soc_enum slim0_rx_vi_fb_lch_mux_enum = - SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_SLIMBUS_0_RX, 0, 0, + SOC_VALUE_ENUM_DOUBLE(SND_SOC_NOPM, MSM_BACKEND_DAI_SLIMBUS_0_RX, 0, 0, ARRAY_SIZE(slim0_rx_vi_fb_tx_lch_mux_text), slim0_rx_vi_fb_tx_lch_mux_text, slim0_rx_vi_fb_tx_lch_value); static const struct soc_enum slim0_rx_vi_fb_rch_mux_enum = - SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_SLIMBUS_0_RX, 0, 0, + SOC_VALUE_ENUM_DOUBLE(SND_SOC_NOPM, MSM_BACKEND_DAI_SLIMBUS_0_RX, 0, 0, ARRAY_SIZE(slim0_rx_vi_fb_tx_rch_mux_text), slim0_rx_vi_fb_tx_rch_mux_text, slim0_rx_vi_fb_tx_rch_value); static const struct soc_enum mi2s_rx_vi_fb_mux_enum = - SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_PRI_MI2S_RX, 0, 0, + SOC_VALUE_ENUM_DOUBLE(SND_SOC_NOPM, MSM_BACKEND_DAI_PRI_MI2S_RX, 0, 0, ARRAY_SIZE(mi2s_rx_vi_fb_tx_mux_text), mi2s_rx_vi_fb_tx_mux_text, mi2s_rx_vi_fb_tx_value); static const struct soc_enum int4_mi2s_rx_vi_fb_mono_ch_mux_enum = - SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_INT4_MI2S_RX, 0, 0, + SOC_VALUE_ENUM_DOUBLE(SND_SOC_NOPM, MSM_BACKEND_DAI_INT4_MI2S_RX, 0, 0, ARRAY_SIZE(int4_mi2s_rx_vi_fb_tx_mono_mux_text), int4_mi2s_rx_vi_fb_tx_mono_mux_text, int4_mi2s_rx_vi_fb_tx_mono_ch_value); static const struct soc_enum int4_mi2s_rx_vi_fb_stereo_ch_mux_enum = - SOC_VALUE_ENUM_DOUBLE(0, MSM_BACKEND_DAI_INT4_MI2S_RX, 0, 0, + SOC_VALUE_ENUM_DOUBLE(SND_SOC_NOPM, MSM_BACKEND_DAI_INT4_MI2S_RX, 0, 0, ARRAY_SIZE(int4_mi2s_rx_vi_fb_tx_stereo_mux_text), int4_mi2s_rx_vi_fb_tx_stereo_mux_text, int4_mi2s_rx_vi_fb_tx_stereo_ch_value); -- cgit v1.2.3 From 66b26c141c4ecaa3c4e0d4dba53a4421550a329c Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Wed, 16 Oct 2019 16:48:20 +0530 Subject: asoc: msm-routing: Fix array out of bounds issue It seems there is out of bound access chances for lsm_app_type_cfg array within msm_routing_get_lsm_app_type_cfg_control() callback. Added case check to return invalid value if user tries to exceed maximum allocated size of array to avoid it. Change-Id: Ied86e6c9a957255c55bb126a09741fbde429be32 Signed-off-by: Soumya Managoli --- sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c index 965de5ca4f66..ed3ee03553b3 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c @@ -15269,16 +15269,18 @@ static int msm_routing_put_lsm_app_type_cfg_control( struct snd_ctl_elem_value *ucontrol) { int i = 0, j; - int num_app_types = ucontrol->value.integer.value[i++]; + int num_app_types; - memset(lsm_app_type_cfg, 0, MAX_APP_TYPES* - sizeof(struct msm_pcm_routing_app_type_data)); - if (num_app_types > MAX_APP_TYPES) { + if (ucontrol->value.integer.value[0] > MAX_APP_TYPES) { pr_err("%s: number of app types exceed the max supported\n", __func__); return -EINVAL; } + num_app_types = ucontrol->value.integer.value[i++]; + memset(lsm_app_type_cfg, 0, MAX_APP_TYPES* + sizeof(struct msm_pcm_routing_app_type_data)); + for (j = 0; j < num_app_types; j++) { lsm_app_type_cfg[j].app_type = ucontrol->value.integer.value[i++]; -- cgit v1.2.3 From 126ed52d7cea9ef7b8cd22e9421649002645d3bb Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 29 Aug 2019 14:25:17 +0200 Subject: KVM: s390: Test for bad access register and size at the start of S390_MEM_OP commit a13b03bbb4575b350b46090af4dfd30e735aaed1 upstream. If the KVM_S390_MEM_OP ioctl is called with an access register >= 16, then there is certainly a bug in the calling userspace application. We check for wrong access registers, but only if the vCPU was already in the access register mode before (i.e. the SIE block has recorded it). The check is also buried somewhere deep in the calling chain (in the function ar_translation()), so this is somewhat hard to find. It's better to always report an error to the userspace in case this field is set wrong, and it's safer in the KVM code if we block wrong values here early instead of relying on a check somewhere deep down the calling chain, so let's add another check to kvm_s390_guest_mem_op() directly. We also should check that the "size" is non-zero here (thanks to Janosch Frank for the hint!). If we do not check the size, we could call vmalloc() with this 0 value, and this will cause a kernel warning. Signed-off-by: Thomas Huth Link: https://lkml.kernel.org/r/20190829122517.31042-1-thuth@redhat.com Reviewed-by: Cornelia Huck Reviewed-by: Janosch Frank Reviewed-by: David Hildenbrand Cc: stable@vger.kernel.org Signed-off-by: Christian Borntraeger Signed-off-by: Greg Kroah-Hartman --- arch/s390/kvm/kvm-s390.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 14d2ca9c779e..3e46f62d32ad 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2471,7 +2471,7 @@ static long kvm_s390_guest_mem_op(struct kvm_vcpu *vcpu, const u64 supported_flags = KVM_S390_MEMOP_F_INJECT_EXCEPTION | KVM_S390_MEMOP_F_CHECK_ONLY; - if (mop->flags & ~supported_flags) + if (mop->flags & ~supported_flags || mop->ar >= NUM_ACRS || !mop->size) return -EINVAL; if (mop->size > MEM_OP_MAX_SIZE) -- cgit v1.2.3 From 399b4e062f76693b8b0eac6a760cca7fbb546c79 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Tue, 17 Sep 2019 22:59:03 +0200 Subject: s390/topology: avoid firing events before kobjs are created commit f3122a79a1b0a113d3aea748e0ec26f2cb2889de upstream. arch_update_cpu_topology is first called from: kernel_init_freeable->sched_init_smp->sched_init_domains even before cpus has been registered in: kernel_init_freeable->do_one_initcall->s390_smp_init Do not trigger kobject_uevent change events until cpu devices are actually created. Fixes the following kasan findings: BUG: KASAN: global-out-of-bounds in kobject_uevent_env+0xb40/0xee0 Read of size 8 at addr 0000000000000020 by task swapper/0/1 BUG: KASAN: global-out-of-bounds in kobject_uevent_env+0xb36/0xee0 Read of size 8 at addr 0000000000000018 by task swapper/0/1 CPU: 0 PID: 1 Comm: swapper/0 Tainted: G B Hardware name: IBM 3906 M04 704 (LPAR) Call Trace: ([<0000000143c6db7e>] show_stack+0x14e/0x1a8) [<0000000145956498>] dump_stack+0x1d0/0x218 [<000000014429fb4c>] print_address_description+0x64/0x380 [<000000014429f630>] __kasan_report+0x138/0x168 [<0000000145960b96>] kobject_uevent_env+0xb36/0xee0 [<0000000143c7c47c>] arch_update_cpu_topology+0x104/0x108 [<0000000143df9e22>] sched_init_domains+0x62/0xe8 [<000000014644c94a>] sched_init_smp+0x3a/0xc0 [<0000000146433a20>] kernel_init_freeable+0x558/0x958 [<000000014599002a>] kernel_init+0x22/0x160 [<00000001459a71d4>] ret_from_fork+0x28/0x30 [<00000001459a71dc>] kernel_thread_starter+0x0/0x10 Cc: stable@vger.kernel.org Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/topology.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 40b8102fdadb..ff95ddd031d1 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c @@ -291,7 +291,8 @@ int arch_update_cpu_topology(void) topology_update_polarization_simple(); for_each_online_cpu(cpu) { dev = get_cpu_device(cpu); - kobject_uevent(&dev->kobj, KOBJ_CHANGE); + if (dev) + kobject_uevent(&dev->kobj, KOBJ_CHANGE); } return rc; } -- cgit v1.2.3 From ea947b87349e51c41e33923fe9518f72feb0c581 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Tue, 17 Sep 2019 20:04:04 +0200 Subject: s390/cio: avoid calling strlen on null pointer commit ea298e6ee8b34b3ed4366be7eb799d0650ebe555 upstream. Fix the following kasan finding: BUG: KASAN: global-out-of-bounds in ccwgroup_create_dev+0x850/0x1140 Read of size 1 at addr 0000000000000000 by task systemd-udevd.r/561 CPU: 30 PID: 561 Comm: systemd-udevd.r Tainted: G B Hardware name: IBM 3906 M04 704 (LPAR) Call Trace: ([<0000000231b3db7e>] show_stack+0x14e/0x1a8) [<0000000233826410>] dump_stack+0x1d0/0x218 [<000000023216fac4>] print_address_description+0x64/0x380 [<000000023216f5a8>] __kasan_report+0x138/0x168 [<00000002331b8378>] ccwgroup_create_dev+0x850/0x1140 [<00000002332b618a>] group_store+0x3a/0x50 [<00000002323ac706>] kernfs_fop_write+0x246/0x3b8 [<00000002321d409a>] vfs_write+0x132/0x450 [<00000002321d47da>] ksys_write+0x122/0x208 [<0000000233877102>] system_call+0x2a6/0x2c8 Triggered by: openat(AT_FDCWD, "/sys/bus/ccwgroup/drivers/qeth/group", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 16 write(16, "0.0.bd00,0.0.bd01,0.0.bd02", 26) = 26 The problem is that __get_next_id in ccwgroup_create_dev might set "buf" buffer pointer to NULL and explicit check for that is required. Cc: stable@vger.kernel.org Reviewed-by: Sebastian Ott Signed-off-by: Vasily Gorbik Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/ccwgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index e443b0d0b236..0d59c128f734 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -369,7 +369,7 @@ int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv, goto error; } /* Check for trailing stuff. */ - if (i == num_devices && strlen(buf) > 0) { + if (i == num_devices && buf && strlen(buf) > 0) { rc = -EINVAL; goto error; } -- cgit v1.2.3 From a179b845b9823e2c3b14c38a9da99280e8495c2f Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Thu, 19 Sep 2019 15:55:17 +0200 Subject: s390/cio: exclude subchannels with no parent from pseudo check commit ab5758848039de9a4b249d46e4ab591197eebaf2 upstream. ccw console is created early in start_kernel and used before css is initialized or ccw console subchannel is registered. Until then console subchannel does not have a parent. For that reason assume subchannels with no parent are not pseudo subchannels. This fixes the following kasan finding: BUG: KASAN: global-out-of-bounds in sch_is_pseudo_sch+0x8e/0x98 Read of size 8 at addr 00000000000005e8 by task swapper/0/0 CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.3.0-rc8-07370-g6ac43dd12538 #2 Hardware name: IBM 2964 NC9 702 (z/VM 6.4.0) Call Trace: ([<000000000012cd76>] show_stack+0x14e/0x1e0) [<0000000001f7fb44>] dump_stack+0x1a4/0x1f8 [<00000000007d7afc>] print_address_description+0x64/0x3c8 [<00000000007d75f6>] __kasan_report+0x14e/0x180 [<00000000018a2986>] sch_is_pseudo_sch+0x8e/0x98 [<000000000189b950>] cio_enable_subchannel+0x1d0/0x510 [<00000000018cac7c>] ccw_device_recognition+0x12c/0x188 [<0000000002ceb1a8>] ccw_device_enable_console+0x138/0x340 [<0000000002cf1cbe>] con3215_init+0x25e/0x300 [<0000000002c8770a>] console_init+0x68a/0x9b8 [<0000000002c6a3d6>] start_kernel+0x4fe/0x728 [<0000000000100070>] startup_continue+0x70/0xd0 Cc: stable@vger.kernel.org Reviewed-by: Sebastian Ott Signed-off-by: Vasily Gorbik Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/css.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 489e703dc82d..8ecc956ecb59 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -1120,6 +1120,8 @@ device_initcall(cio_settle_init); int sch_is_pseudo_sch(struct subchannel *sch) { + if (!sch->dev.parent) + return 0; return sch == to_css(sch->dev.parent)->pseudo_subchannel; } -- cgit v1.2.3 From 59b3647b86fc86e27f5fc7e0ed281b113d045c1d Mon Sep 17 00:00:00 2001 From: Jack Wang Date: Mon, 7 Oct 2019 14:36:53 +0200 Subject: KVM: nVMX: handle page fault in vmread fix During backport f7eea636c3d5 ("KVM: nVMX: handle page fault in vmread"), there was a mistake the exception reference should be passed to function kvm_write_guest_virt_system, instead of NULL, other wise, we will get NULL pointer deref, eg kvm-unit-test triggered a NULL pointer deref below: [ 948.518437] kvm [24114]: vcpu0, guest rIP: 0x407ef9 kvm_set_msr_common: MSR_IA32_DEBUGCTLMSR 0x3, nop [ 949.106464] BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 [ 949.106707] PGD 0 P4D 0 [ 949.106872] Oops: 0002 [#1] SMP [ 949.107038] CPU: 2 PID: 24126 Comm: qemu-2.7 Not tainted 4.19.77-pserver #4.19.77-1+feature+daily+update+20191005.1625+a4168bb~deb9 [ 949.107283] Hardware name: Dell Inc. Precision Tower 3620/09WH54, BIOS 2.7.3 01/31/2018 [ 949.107549] RIP: 0010:kvm_write_guest_virt_system+0x12/0x40 [kvm] [ 949.107719] Code: c0 5d 41 5c 41 5d 41 5e 83 f8 03 41 0f 94 c0 41 c1 e0 02 e9 b0 ed ff ff 0f 1f 44 00 00 48 89 f0 c6 87 59 56 00 00 01 48 89 d6 <49> c7 00 00 00 00 00 89 ca 49 c7 40 08 00 00 00 00 49 c7 40 10 00 [ 949.108044] RSP: 0018:ffffb31b0a953cb0 EFLAGS: 00010202 [ 949.108216] RAX: 000000000046b4d8 RBX: ffff9e9f415b0000 RCX: 0000000000000008 [ 949.108389] RDX: ffffb31b0a953cc0 RSI: ffffb31b0a953cc0 RDI: ffff9e9f415b0000 [ 949.108562] RBP: 00000000d2e14928 R08: 0000000000000000 R09: 0000000000000000 [ 949.108733] R10: 0000000000000000 R11: 0000000000000000 R12: ffffffffffffffc8 [ 949.108907] R13: 0000000000000002 R14: ffff9e9f4f26f2e8 R15: 0000000000000000 [ 949.109079] FS: 00007eff8694c700(0000) GS:ffff9e9f51a80000(0000) knlGS:0000000031415928 [ 949.109318] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 949.109495] CR2: 0000000000000000 CR3: 00000003be53b002 CR4: 00000000003626e0 [ 949.109671] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 949.109845] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 949.110017] Call Trace: [ 949.110186] handle_vmread+0x22b/0x2f0 [kvm_intel] [ 949.110356] ? vmexit_fill_RSB+0xc/0x30 [kvm_intel] [ 949.110549] kvm_arch_vcpu_ioctl_run+0xa98/0x1b30 [kvm] [ 949.110725] ? kvm_vcpu_ioctl+0x388/0x5d0 [kvm] [ 949.110901] kvm_vcpu_ioctl+0x388/0x5d0 [kvm] [ 949.111072] do_vfs_ioctl+0xa2/0x620 Signed-off-by: Jack Wang Acked-by: Paolo Bonzini --- arch/x86/kvm/vmx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 343c8ddad86a..f8f9d1b368bf 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -7276,7 +7276,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu) /* _system ok, as nested_vmx_check_permission verified cpl=0 */ if (kvm_write_guest_virt_system(vcpu, gva, &field_value, (is_long_mode(vcpu) ? 8 : 4), - NULL)) + &e)) kvm_inject_page_fault(vcpu, &e); } -- cgit v1.2.3 From d4a8a6d767cecd4d637e061e6baabcf2e6c89c20 Mon Sep 17 00:00:00 2001 From: Oleksandr Suvorov Date: Fri, 19 Jul 2019 10:05:30 +0000 Subject: ASoC: Define a set of DAPM pre/post-up events commit cfc8f568aada98f9608a0a62511ca18d647613e2 upstream. Prepare to use SND_SOC_DAPM_PRE_POST_PMU definition to reduce coming code size and make it more readable. Cc: stable@vger.kernel.org Signed-off-by: Oleksandr Suvorov Reviewed-by: Marcel Ziswiler Reviewed-by: Igor Opaniuk Reviewed-by: Fabio Estevam Link: https://lore.kernel.org/r/20190719100524.23300-2-oleksandr.suvorov@toradex.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- include/sound/soc-dapm.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 95a937eafb79..2fc28324351d 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -335,6 +335,8 @@ struct device; #define SND_SOC_DAPM_WILL_PMD 0x80 /* called at start of sequence */ #define SND_SOC_DAPM_PRE_POST_PMD \ (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD) +#define SND_SOC_DAPM_PRE_POST_PMU \ + (SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU) /* convenience event type detection */ #define SND_SOC_DAPM_EVENT_ON(e) \ -- cgit v1.2.3 From cc5d103da4446aa95630d906f4e16fe703d78114 Mon Sep 17 00:00:00 2001 From: Andrew Donnellan Date: Fri, 3 May 2019 17:52:53 +1000 Subject: powerpc/powernv: Restrict OPAL symbol map to only be readable by root commit e7de4f7b64c23e503a8c42af98d56f2a7462bd6d upstream. Currently the OPAL symbol map is globally readable, which seems bad as it contains physical addresses. Restrict it to root. Fixes: c8742f85125d ("powerpc/powernv: Expose OPAL firmware symbol map") Cc: stable@vger.kernel.org # v3.19+ Suggested-by: Michael Ellerman Signed-off-by: Andrew Donnellan Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20190503075253.22798-1-ajd@linux.ibm.com Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/opal.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index b40606051efe..d3787618315f 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -580,7 +580,10 @@ static ssize_t symbol_map_read(struct file *fp, struct kobject *kobj, bin_attr->size); } -static BIN_ATTR_RO(symbol_map, 0); +static struct bin_attribute symbol_map_attr = { + .attr = {.name = "symbol_map", .mode = 0400}, + .read = symbol_map_read +}; static void opal_export_symmap(void) { @@ -597,10 +600,10 @@ static void opal_export_symmap(void) return; /* Setup attributes */ - bin_attr_symbol_map.private = __va(be64_to_cpu(syms[0])); - bin_attr_symbol_map.size = be64_to_cpu(syms[1]); + symbol_map_attr.private = __va(be64_to_cpu(syms[0])); + symbol_map_attr.size = be64_to_cpu(syms[1]); - rc = sysfs_create_bin_file(opal_kobj, &bin_attr_symbol_map); + rc = sysfs_create_bin_file(opal_kobj, &symbol_map_attr); if (rc) pr_warn("Error %d creating OPAL symbols file\n", rc); } -- cgit v1.2.3 From 62db62a4313444a69f640a3250cef4646c2aceeb Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 13 Aug 2019 16:01:02 +0200 Subject: can: mcp251x: mcp251x_hw_reset(): allow more time after a reset commit d84ea2123f8d27144e3f4d58cd88c9c6ddc799de upstream. Some boards take longer than 5ms to power up after a reset, so allow some retries attempts before giving up. Fixes: ff06d611a31c ("can: mcp251x: Improve mcp251x_hw_reset()") Cc: linux-stable Tested-by: Sean Nyekjaer Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/spi/mcp251x.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index 3bcbfcf0455a..83ddb7d8214a 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -627,7 +627,7 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv, static int mcp251x_hw_reset(struct spi_device *spi) { struct mcp251x_priv *priv = spi_get_drvdata(spi); - u8 reg; + unsigned long timeout; int ret; /* Wait for oscillator startup timer after power up */ @@ -641,10 +641,19 @@ static int mcp251x_hw_reset(struct spi_device *spi) /* Wait for oscillator startup timer after reset */ mdelay(MCP251X_OST_DELAY_MS); - reg = mcp251x_read_reg(spi, CANSTAT); - if ((reg & CANCTRL_REQOP_MASK) != CANCTRL_REQOP_CONF) - return -ENODEV; - + /* Wait for reset to finish */ + timeout = jiffies + HZ; + while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) != + CANCTRL_REQOP_CONF) { + usleep_range(MCP251X_OST_DELAY_MS * 1000, + MCP251X_OST_DELAY_MS * 1000 * 2); + + if (time_after(jiffies, timeout)) { + dev_err(&spi->dev, + "MCP251x didn't enter in conf mode after reset\n"); + return -EBUSY; + } + } return 0; } -- cgit v1.2.3 From 448ad4ac56f8dce293c5804f8690fa6f6c69276a Mon Sep 17 00:00:00 2001 From: Alexander Sverdlin Date: Tue, 23 Jul 2019 07:24:01 +0000 Subject: crypto: qat - Silence smp_processor_id() warning commit 1b82feb6c5e1996513d0fb0bbb475417088b4954 upstream. It seems that smp_processor_id() is only used for a best-effort load-balancing, refer to qat_crypto_get_instance_node(). It's not feasible to disable preemption for the duration of the crypto requests. Therefore, just silence the warning. This commit is similar to e7a9b05ca4 ("crypto: cavium - Fix smp_processor_id() warnings"). Silences the following splat: BUG: using smp_processor_id() in preemptible [00000000] code: cryptomgr_test/2904 caller is qat_alg_ablkcipher_setkey+0x300/0x4a0 [intel_qat] CPU: 1 PID: 2904 Comm: cryptomgr_test Tainted: P O 4.14.69 #1 ... Call Trace: dump_stack+0x5f/0x86 check_preemption_disabled+0xd3/0xe0 qat_alg_ablkcipher_setkey+0x300/0x4a0 [intel_qat] skcipher_setkey_ablkcipher+0x2b/0x40 __test_skcipher+0x1f3/0xb20 ? cpumask_next_and+0x26/0x40 ? find_busiest_group+0x10e/0x9d0 ? preempt_count_add+0x49/0xa0 ? try_module_get+0x61/0xf0 ? crypto_mod_get+0x15/0x30 ? __kmalloc+0x1df/0x1f0 ? __crypto_alloc_tfm+0x116/0x180 ? crypto_skcipher_init_tfm+0xa6/0x180 ? crypto_create_tfm+0x4b/0xf0 test_skcipher+0x21/0xa0 alg_test_skcipher+0x3f/0xa0 alg_test.part.6+0x126/0x2a0 ? finish_task_switch+0x21b/0x260 ? __schedule+0x1e9/0x800 ? __wake_up_common+0x8d/0x140 cryptomgr_test+0x40/0x50 kthread+0xff/0x130 ? cryptomgr_notify+0x540/0x540 ? kthread_create_on_node+0x70/0x70 ret_from_fork+0x24/0x50 Fixes: ed8ccaef52 ("crypto: qat - Add support for SRIOV") Cc: stable@vger.kernel.org Signed-off-by: Alexander Sverdlin Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/qat/qat_common/adf_common_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index aa1dbeaa9b49..5358162018dd 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -95,7 +95,7 @@ struct service_hndl { static inline int get_current_node(void) { - return topology_physical_package_id(smp_processor_id()); + return topology_physical_package_id(raw_smp_processor_id()); } int adf_service_register(struct service_hndl *service); -- cgit v1.2.3 From 1fb673245b24832acb411db7ffe207fb470559ab Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 19 Sep 2019 14:12:34 +0200 Subject: ieee802154: atusb: fix use-after-free at disconnect commit 7fd25e6fc035f4b04b75bca6d7e8daa069603a76 upstream. The disconnect callback was accessing the hardware-descriptor private data after having having freed it. Fixes: 7490b008d123 ("ieee802154: add support for atusb transceiver") Cc: stable # 4.2 Cc: Alexander Aring Reported-by: syzbot+f4509a9138a1472e7e80@syzkaller.appspotmail.com Signed-off-by: Johan Hovold Signed-off-by: Stefan Schmidt Signed-off-by: Greg Kroah-Hartman --- drivers/net/ieee802154/atusb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index 3a429f1a8002..d5e0e2aedc55 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -756,10 +756,11 @@ static void atusb_disconnect(struct usb_interface *interface) ieee802154_unregister_hw(atusb->hw); + usb_put_dev(atusb->usb_dev); + ieee802154_free_hw(atusb->hw); usb_set_intfdata(interface, NULL); - usb_put_dev(atusb->usb_dev); pr_debug("atusb_disconnect done\n"); } -- cgit v1.2.3 From ef1bcee5e92e321967aab05e7ed5a91a3f8d78e9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 23 Sep 2019 13:51:16 +0200 Subject: cfg80211: initialize on-stack chandefs commit f43e5210c739fe76a4b0ed851559d6902f20ceb1 upstream. In a few places we don't properly initialize on-stack chandefs, resulting in EDMG data to be non-zero, which broke things. Additionally, in a few places we rely on the driver to init the data completely, but perhaps we shouldn't as non-EDMG drivers may not initialize the EDMG data, also initialize it there. Cc: stable@vger.kernel.org Fixes: 2a38075cd0be ("nl80211: Add support for EDMG channels") Reported-by: Dmitry Osipenko Tested-by: Dmitry Osipenko Link: https://lore.kernel.org/r/1569239475-I2dcce394ecf873376c386a78f31c2ec8b538fa25@changeid Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/wireless/nl80211.c | 4 +++- net/wireless/reg.c | 2 +- net/wireless/wext-compat.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1968998e6c6c..844614453852 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1934,6 +1934,8 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); + memset(chandef, 0, sizeof(*chandef)); + chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq); chandef->width = NL80211_CHAN_WIDTH_20_NOHT; chandef->center_freq1 = control_freq; @@ -2402,7 +2404,7 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag if (rdev->ops->get_channel) { int ret; - struct cfg80211_chan_def chandef; + struct cfg80211_chan_def chandef = {}; ret = rdev_get_channel(rdev, wdev, &chandef); if (ret == 0) { diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 6a670a373e29..437ec52d5e71 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1604,7 +1604,7 @@ static void reg_call_notifier(struct wiphy *wiphy, static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev) { - struct cfg80211_chan_def chandef; + struct cfg80211_chan_def chandef = {}; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); enum nl80211_iftype iftype; diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index fd682832a0e3..cd119943612b 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -821,7 +821,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); - struct cfg80211_chan_def chandef; + struct cfg80211_chan_def chandef = {}; int ret; switch (wdev->iftype) { -- cgit v1.2.3 From b1b8f7b23a2832f46593707627fee765575bcd7c Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 2 Jul 2019 10:00:40 +0200 Subject: ima: always return negative code for error [ Upstream commit f5e1040196dbfe14c77ce3dfe3b7b08d2d961e88 ] integrity_kernel_read() returns the number of bytes read. If this is a short read then this positive value is returned from ima_calc_file_hash_atfm(). Currently this is only indirectly called from ima_calc_file_hash() and this function only tests for the return value being zero or nonzero and also doesn't forward the return value. Nevertheless there's no point in returning a positive value as an error, so translate a short read into -EINVAL. Signed-off-by: Sascha Hauer Signed-off-by: Mimi Zohar Signed-off-by: Sasha Levin --- security/integrity/ima/ima_crypto.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index a29209fa5674..5c87baaefafb 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -298,8 +298,11 @@ static int ima_calc_file_hash_atfm(struct file *file, rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]); rc = integrity_kernel_read(file, offset, rbuf[active], rbuf_len); - if (rc != rbuf_len) + if (rc != rbuf_len) { + if (rc >= 0) + rc = -EINVAL; goto out3; + } if (rbuf[1] && offset) { /* Using two buffers, and it is not the first -- cgit v1.2.3 From 5deaece94aa9f3be912ec2c61483ba876fcef12e Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Fri, 26 Jul 2019 15:48:53 +0800 Subject: fs: nfs: Fix possible null-pointer dereferences in encode_attrs() [ Upstream commit e2751463eaa6f9fec8fea80abbdc62dbc487b3c5 ] In encode_attrs(), there is an if statement on line 1145 to check whether label is NULL: if (label && (attrmask[2] & FATTR4_WORD2_SECURITY_LABEL)) When label is NULL, it is used on lines 1178-1181: *p++ = cpu_to_be32(label->lfs); *p++ = cpu_to_be32(label->pi); *p++ = cpu_to_be32(label->len); p = xdr_encode_opaque_fixed(p, label->label, label->len); To fix these bugs, label is checked before being used. These bugs are found by a static analysis tool STCheck written by us. Signed-off-by: Jia-Ju Bai Signed-off-by: Anna Schumaker Signed-off-by: Sasha Levin --- fs/nfs/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 1cb50bb898b0..15cd9db6d616 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1123,7 +1123,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, } else *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME); } - if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) { + if (label && (bmval[2] & FATTR4_WORD2_SECURITY_LABEL)) { *p++ = cpu_to_be32(label->lfs); *p++ = cpu_to_be32(label->pi); *p++ = cpu_to_be32(label->len); -- cgit v1.2.3 From 06453e2abdd2ec2ff40fc0324adead84ff4899b7 Mon Sep 17 00:00:00 2001 From: Chengguang Xu Date: Tue, 20 Aug 2019 18:03:25 +0800 Subject: 9p: avoid attaching writeback_fid on mmap with type PRIVATE [ Upstream commit c87a37ebd40b889178664c2c09cc187334146292 ] Currently on mmap cache policy, we always attach writeback_fid whether mmap type is SHARED or PRIVATE. However, in the use case of kata-container which combines 9p(Guest OS) with overlayfs(Host OS), this behavior will trigger overlayfs' copy-up when excute command inside container. Link: http://lkml.kernel.org/r/20190820100325.10313-1-cgxu519@zoho.com.cn Signed-off-by: Chengguang Xu Signed-off-by: Dominique Martinet Signed-off-by: Sasha Levin --- fs/9p/vfs_file.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 373cc50544e9..9dbf37147126 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -528,6 +528,7 @@ v9fs_mmap_file_mmap(struct file *filp, struct vm_area_struct *vma) v9inode = V9FS_I(inode); mutex_lock(&v9inode->v_mutex); if (!v9inode->writeback_fid && + (vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_WRITE)) { /* * clone a fid and add it to writeback_fid @@ -629,6 +630,8 @@ static void v9fs_mmap_vm_close(struct vm_area_struct *vma) (vma->vm_end - vma->vm_start - 1), }; + if (!(vma->vm_flags & VM_SHARED)) + return; p9_debug(P9_DEBUG_VFS, "9p VMA close, %p, flushing", vma); -- cgit v1.2.3 From 6390b01bb7062f438570ee63756e25f89bfc19a7 Mon Sep 17 00:00:00 2001 From: Igor Druzhinin Date: Thu, 12 Sep 2019 19:31:51 +0100 Subject: xen/pci: reserve MCFG areas earlier [ Upstream commit a4098bc6eed5e31e0391bcc068e61804c98138df ] If MCFG area is not reserved in E820, Xen by default will defer its usage until Dom0 registers it explicitly after ACPI parser recognizes it as a reserved resource in DSDT. Having it reserved in E820 is not mandatory according to "PCI Firmware Specification, rev 3.2" (par. 4.1.2) and firmware is free to keep a hole in E820 in that place. Xen doesn't know what exactly is inside this hole since it lacks full ACPI view of the platform therefore it's potentially harmful to access MCFG region without additional checks as some machines are known to provide inconsistent information on the size of the region. Now xen_mcfg_late() runs after acpi_init() which is too late as some basic PCI enumeration starts exactly there as well. Trying to register a device prior to MCFG reservation causes multiple problems with PCIe extended capability initializations in Xen (e.g. SR-IOV VF BAR sizing). There are no convenient hooks for us to subscribe to so register MCFG areas earlier upon the first invocation of xen_add_device(). It should be safe to do once since all the boot time buses must have their MCFG areas in MCFG table already and we don't support PCI bus hot-plug. Signed-off-by: Igor Druzhinin Reviewed-by: Boris Ostrovsky Signed-off-by: Boris Ostrovsky Signed-off-by: Sasha Levin --- drivers/xen/pci.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c index 7494dbeb4409..db58aaa4dc59 100644 --- a/drivers/xen/pci.c +++ b/drivers/xen/pci.c @@ -29,6 +29,8 @@ #include "../pci/pci.h" #ifdef CONFIG_PCI_MMCONFIG #include + +static int xen_mcfg_late(void); #endif static bool __read_mostly pci_seg_supported = true; @@ -40,7 +42,18 @@ static int xen_add_device(struct device *dev) #ifdef CONFIG_PCI_IOV struct pci_dev *physfn = pci_dev->physfn; #endif - +#ifdef CONFIG_PCI_MMCONFIG + static bool pci_mcfg_reserved = false; + /* + * Reserve MCFG areas in Xen on first invocation due to this being + * potentially called from inside of acpi_init immediately after + * MCFG table has been finally parsed. + */ + if (!pci_mcfg_reserved) { + xen_mcfg_late(); + pci_mcfg_reserved = true; + } +#endif if (pci_seg_supported) { struct { struct physdev_pci_device_add add; @@ -213,7 +226,7 @@ static int __init register_xen_pci_notifier(void) arch_initcall(register_xen_pci_notifier); #ifdef CONFIG_PCI_MMCONFIG -static int __init xen_mcfg_late(void) +static int xen_mcfg_late(void) { struct pci_mmcfg_region *cfg; int rc; @@ -252,8 +265,4 @@ static int __init xen_mcfg_late(void) } return 0; } -/* - * Needs to be done after acpi_init which are subsys_initcall. - */ -subsys_initcall_sync(xen_mcfg_late); #endif -- cgit v1.2.3 From 78ba94e80f840537fae75e180bf85e7431f5b09c Mon Sep 17 00:00:00 2001 From: Luis Henriques Date: Tue, 23 Jul 2019 16:50:20 +0100 Subject: ceph: fix directories inode i_blkbits initialization [ Upstream commit 750670341a24cb714e624e0fd7da30900ad93752 ] When filling an inode with info from the MDS, i_blkbits is being initialized using fl_stripe_unit, which contains the stripe unit in bytes. Unfortunately, this doesn't make sense for directories as they have fl_stripe_unit set to '0'. This means that i_blkbits will be set to 0xff, causing an UBSAN undefined behaviour in i_blocksize(): UBSAN: Undefined behaviour in ./include/linux/fs.h:731:12 shift exponent 255 is too large for 32-bit type 'int' Fix this by initializing i_blkbits to CEPH_BLOCK_SHIFT if fl_stripe_unit is zero. Signed-off-by: Luis Henriques Reviewed-by: Jeff Layton Signed-off-by: Ilya Dryomov Signed-off-by: Sasha Levin --- fs/ceph/inode.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index a663b676d566..2ad3f4ab4dcf 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -725,7 +725,12 @@ static int fill_inode(struct inode *inode, struct page *locked_page, ci->i_version = le64_to_cpu(info->version); inode->i_version++; inode->i_rdev = le32_to_cpu(info->rdev); - inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1; + /* directories have fl_stripe_unit set to zero */ + if (le32_to_cpu(info->layout.fl_stripe_unit)) + inode->i_blkbits = + fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1; + else + inode->i_blkbits = CEPH_BLOCK_SHIFT; if ((new_version || (new_issued & CEPH_CAP_AUTH_SHARED)) && (issued & CEPH_CAP_AUTH_EXCL) == 0) { -- cgit v1.2.3 From e4165f2d4a4e313717cf2db435c0a8c23456da8d Mon Sep 17 00:00:00 2001 From: Trek Date: Sat, 31 Aug 2019 21:25:36 +0200 Subject: drm/amdgpu: Check for valid number of registers to read [ Upstream commit 73d8e6c7b841d9bf298c8928f228fb433676635c ] Do not try to allocate any amount of memory requested by the user. Instead limit it to 128 registers. Actually the longest series of consecutive allowed registers are 48, mmGB_TILE_MODE0-31 and mmGB_MACROTILE_MODE0-15 (0x2644-0x2673). Bug: https://bugs.freedesktop.org/show_bug.cgi?id=111273 Signed-off-by: Trek Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index a5c824078472..e35e603710b4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -406,6 +406,9 @@ static int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file if (sh_num == AMDGPU_INFO_MMR_SH_INDEX_MASK) sh_num = 0xffffffff; + if (info->read_mmr_reg.count > 128) + return -EINVAL; + regs = kmalloc_array(info->read_mmr_reg.count, sizeof(*regs), GFP_KERNEL); if (!regs) return -ENOMEM; -- cgit v1.2.3 From b30c56ee03b688d0ec769eeb14801f8eb9d2bbad Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 10 Jul 2019 13:14:52 +0300 Subject: thermal: Fix use-after-free when unregistering thermal zone device [ Upstream commit 1851799e1d2978f68eea5d9dff322e121dcf59c1 ] thermal_zone_device_unregister() cancels the delayed work that polls the thermal zone, but it does not wait for it to finish. This is racy with respect to the freeing of the thermal zone device, which can result in a use-after-free [1]. Fix this by waiting for the delayed work to finish before freeing the thermal zone device. Note that thermal_zone_device_set_polling() is never invoked from an atomic context, so it is safe to call cancel_delayed_work_sync() that can block. [1] [ +0.002221] ================================================================== [ +0.000064] BUG: KASAN: use-after-free in __mutex_lock+0x1076/0x11c0 [ +0.000016] Read of size 8 at addr ffff8881e48e0450 by task kworker/1:0/17 [ +0.000023] CPU: 1 PID: 17 Comm: kworker/1:0 Not tainted 5.2.0-rc6-custom-02495-g8e73ca3be4af #1701 [ +0.000010] Hardware name: Mellanox Technologies Ltd. MSN2100-CB2FO/SA001017, BIOS 5.6.5 06/07/2016 [ +0.000016] Workqueue: events_freezable_power_ thermal_zone_device_check [ +0.000012] Call Trace: [ +0.000021] dump_stack+0xa9/0x10e [ +0.000020] print_address_description.cold.2+0x9/0x25e [ +0.000018] __kasan_report.cold.3+0x78/0x9d [ +0.000016] kasan_report+0xe/0x20 [ +0.000016] __mutex_lock+0x1076/0x11c0 [ +0.000014] step_wise_throttle+0x72/0x150 [ +0.000018] handle_thermal_trip+0x167/0x760 [ +0.000019] thermal_zone_device_update+0x19e/0x5f0 [ +0.000019] process_one_work+0x969/0x16f0 [ +0.000017] worker_thread+0x91/0xc40 [ +0.000014] kthread+0x33d/0x400 [ +0.000015] ret_from_fork+0x3a/0x50 [ +0.000020] Allocated by task 1: [ +0.000015] save_stack+0x19/0x80 [ +0.000015] __kasan_kmalloc.constprop.4+0xc1/0xd0 [ +0.000014] kmem_cache_alloc_trace+0x152/0x320 [ +0.000015] thermal_zone_device_register+0x1b4/0x13a0 [ +0.000015] mlxsw_thermal_init+0xc92/0x23d0 [ +0.000014] __mlxsw_core_bus_device_register+0x659/0x11b0 [ +0.000013] mlxsw_core_bus_device_register+0x3d/0x90 [ +0.000013] mlxsw_pci_probe+0x355/0x4b0 [ +0.000014] local_pci_probe+0xc3/0x150 [ +0.000013] pci_device_probe+0x280/0x410 [ +0.000013] really_probe+0x26a/0xbb0 [ +0.000013] driver_probe_device+0x208/0x2e0 [ +0.000013] device_driver_attach+0xfe/0x140 [ +0.000013] __driver_attach+0x110/0x310 [ +0.000013] bus_for_each_dev+0x14b/0x1d0 [ +0.000013] driver_register+0x1c0/0x400 [ +0.000015] mlxsw_sp_module_init+0x5d/0xd3 [ +0.000014] do_one_initcall+0x239/0x4dd [ +0.000013] kernel_init_freeable+0x42b/0x4e8 [ +0.000012] kernel_init+0x11/0x18b [ +0.000013] ret_from_fork+0x3a/0x50 [ +0.000015] Freed by task 581: [ +0.000013] save_stack+0x19/0x80 [ +0.000014] __kasan_slab_free+0x125/0x170 [ +0.000013] kfree+0xf3/0x310 [ +0.000013] thermal_release+0xc7/0xf0 [ +0.000014] device_release+0x77/0x200 [ +0.000014] kobject_put+0x1a8/0x4c0 [ +0.000014] device_unregister+0x38/0xc0 [ +0.000014] thermal_zone_device_unregister+0x54e/0x6a0 [ +0.000014] mlxsw_thermal_fini+0x184/0x35a [ +0.000014] mlxsw_core_bus_device_unregister+0x10a/0x640 [ +0.000013] mlxsw_devlink_core_bus_device_reload+0x92/0x210 [ +0.000015] devlink_nl_cmd_reload+0x113/0x1f0 [ +0.000014] genl_family_rcv_msg+0x700/0xee0 [ +0.000013] genl_rcv_msg+0xca/0x170 [ +0.000013] netlink_rcv_skb+0x137/0x3a0 [ +0.000012] genl_rcv+0x29/0x40 [ +0.000013] netlink_unicast+0x49b/0x660 [ +0.000013] netlink_sendmsg+0x755/0xc90 [ +0.000013] __sys_sendto+0x3de/0x430 [ +0.000013] __x64_sys_sendto+0xe2/0x1b0 [ +0.000013] do_syscall_64+0xa4/0x4d0 [ +0.000013] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ +0.000017] The buggy address belongs to the object at ffff8881e48e0008 which belongs to the cache kmalloc-2k of size 2048 [ +0.000012] The buggy address is located 1096 bytes inside of 2048-byte region [ffff8881e48e0008, ffff8881e48e0808) [ +0.000007] The buggy address belongs to the page: [ +0.000012] page:ffffea0007923800 refcount:1 mapcount:0 mapping:ffff88823680d0c0 index:0x0 compound_mapcount: 0 [ +0.000020] flags: 0x200000000010200(slab|head) [ +0.000019] raw: 0200000000010200 ffffea0007682008 ffffea00076ab808 ffff88823680d0c0 [ +0.000016] raw: 0000000000000000 00000000000d000d 00000001ffffffff 0000000000000000 [ +0.000007] page dumped because: kasan: bad access detected [ +0.000012] Memory state around the buggy address: [ +0.000012] ffff8881e48e0300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ +0.000012] ffff8881e48e0380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ +0.000012] >ffff8881e48e0400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ +0.000008] ^ [ +0.000012] ffff8881e48e0480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ +0.000012] ffff8881e48e0500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ +0.000007] ================================================================== Fixes: b1569e99c795 ("ACPI: move thermal trip handling to generic thermal layer") Reported-by: Jiri Pirko Signed-off-by: Ido Schimmel Acked-by: Jiri Pirko Signed-off-by: Zhang Rui Signed-off-by: Sasha Levin --- drivers/thermal/thermal_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 3d5f8f432b5b..929092fc25ef 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -402,7 +402,7 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz, mod_delayed_work(system_freezable_wq, &tz->poll_queue, msecs_to_jiffies(delay)); else - cancel_delayed_work(&tz->poll_queue); + cancel_delayed_work_sync(&tz->poll_queue); } static void monitor_thermal_zone(struct thermal_zone_device *tz) -- cgit v1.2.3 From d082c610bce7df91fc94d07d382baf495f55752e Mon Sep 17 00:00:00 2001 From: zhengbin Date: Wed, 14 Aug 2019 15:59:09 +0800 Subject: fuse: fix memleak in cuse_channel_open [ Upstream commit 9ad09b1976c562061636ff1e01bfc3a57aebe56b ] If cuse_send_init fails, need to fuse_conn_put cc->fc. cuse_channel_open->fuse_conn_init->refcount_set(&fc->count, 1) ->fuse_dev_alloc->fuse_conn_get ->fuse_dev_free->fuse_conn_put Fixes: cc080e9e9be1 ("fuse: introduce per-instance fuse_dev structure") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Miklos Szeredi Signed-off-by: Sasha Levin --- fs/fuse/cuse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index c5b6b7165489..d9aba9700726 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c @@ -513,6 +513,7 @@ static int cuse_channel_open(struct inode *inode, struct file *file) rc = cuse_send_init(cc); if (rc) { fuse_dev_free(fud); + fuse_conn_put(&cc->fc); return rc; } file->private_data = fud; -- cgit v1.2.3 From 65514877299b29cfc90d5a51c2ac6692094229ce Mon Sep 17 00:00:00 2001 From: Valdis Kletnieks Date: Wed, 25 Sep 2019 16:45:59 -0700 Subject: kernel/elfcore.c: include proper prototypes [ Upstream commit 0f74914071ab7e7b78731ed62bf350e3a344e0a5 ] When building with W=1, gcc properly complains that there's no prototypes: CC kernel/elfcore.o kernel/elfcore.c:7:17: warning: no previous prototype for 'elf_core_extra_phdrs' [-Wmissing-prototypes] 7 | Elf_Half __weak elf_core_extra_phdrs(void) | ^~~~~~~~~~~~~~~~~~~~ kernel/elfcore.c:12:12: warning: no previous prototype for 'elf_core_write_extra_phdrs' [-Wmissing-prototypes] 12 | int __weak elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset) | ^~~~~~~~~~~~~~~~~~~~~~~~~~ kernel/elfcore.c:17:12: warning: no previous prototype for 'elf_core_write_extra_data' [-Wmissing-prototypes] 17 | int __weak elf_core_write_extra_data(struct coredump_params *cprm) | ^~~~~~~~~~~~~~~~~~~~~~~~~ kernel/elfcore.c:22:15: warning: no previous prototype for 'elf_core_extra_data_size' [-Wmissing-prototypes] 22 | size_t __weak elf_core_extra_data_size(void) | ^~~~~~~~~~~~~~~~~~~~~~~~ Provide the include file so gcc is happy, and we don't have potential code drift Link: http://lkml.kernel.org/r/29875.1565224705@turing-police Signed-off-by: Valdis Kletnieks Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- kernel/elfcore.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/elfcore.c b/kernel/elfcore.c index e556751d15d9..a2b29b9bdfcb 100644 --- a/kernel/elfcore.c +++ b/kernel/elfcore.c @@ -2,6 +2,7 @@ #include #include #include +#include Elf_Half __weak elf_core_extra_phdrs(void) { -- cgit v1.2.3 From bacdf1ea1671c97be514fd90ae852810812f0d99 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 28 Aug 2019 15:05:28 -0400 Subject: tools lib traceevent: Do not free tep->cmdlines in add_new_comm() on failure [ Upstream commit e0d2615856b2046c2e8d5bfd6933f37f69703b0b ] If the re-allocation of tep->cmdlines succeeds, then the previous allocation of tep->cmdlines will be freed. If we later fail in add_new_comm(), we must not free cmdlines, and also should assign tep->cmdlines to the new allocation. Otherwise when freeing tep, the tep->cmdlines will be pointing to garbage. Fixes: a6d2a61ac653a ("tools lib traceevent: Remove some die() calls") Signed-off-by: Steven Rostedt (VMware) Cc: Andrew Morton Cc: Jiri Olsa Cc: Namhyung Kim Cc: linux-trace-devel@vger.kernel.org Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20190828191819.970121417@goodmis.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin --- tools/lib/traceevent/event-parse.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index df3c73e9dea4..9954b069b3ca 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -265,10 +265,10 @@ static int add_new_comm(struct pevent *pevent, const char *comm, int pid) errno = ENOMEM; return -1; } + pevent->cmdlines = cmdlines; cmdlines[pevent->cmdline_count].comm = strdup(comm); if (!cmdlines[pevent->cmdline_count].comm) { - free(cmdlines); errno = ENOMEM; return -1; } @@ -279,7 +279,6 @@ static int add_new_comm(struct pevent *pevent, const char *comm, int pid) pevent->cmdline_count++; qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp); - pevent->cmdlines = cmdlines; return 0; } -- cgit v1.2.3 From 0f714ca2b3f32fe2b4f3a7222c8066b77ea25a51 Mon Sep 17 00:00:00 2001 From: Srikar Dronamraju Date: Wed, 4 Sep 2019 15:17:38 +0530 Subject: perf stat: Fix a segmentation fault when using repeat forever [ Upstream commit 443f2d5ba13d65ccfd879460f77941875159d154 ] Observe a segmentation fault when 'perf stat' is asked to repeat forever with the interval option. Without fix: # perf stat -r 0 -I 5000 -e cycles -a sleep 10 # time counts unit events 5.000211692 3,13,89,82,34,157 cycles 10.000380119 1,53,98,52,22,294 cycles 10.040467280 17,16,79,265 cycles Segmentation fault This problem was only observed when we use forever option aka -r 0 and works with limited repeats. Calling print_counter with ts being set to NULL, is not a correct option when interval is set. Hence avoid print_counter(NULL,..) if interval is set. With fix: # perf stat -r 0 -I 5000 -e cycles -a sleep 10 # time counts unit events 5.019866622 3,15,14,43,08,697 cycles 10.039865756 3,15,16,31,95,261 cycles 10.059950628 1,26,05,47,158 cycles 5.009902655 3,14,52,62,33,932 cycles 10.019880228 3,14,52,22,89,154 cycles 10.030543876 66,90,18,333 cycles 5.009848281 3,14,51,98,25,437 cycles 10.029854402 3,15,14,93,04,918 cycles 5.009834177 3,14,51,95,92,316 cycles Committer notes: Did the 'git bisect' to find the cset introducing the problem to add the Fixes tag below, and at that time the problem reproduced as: (gdb) run stat -r0 -I500 sleep 1 Program received signal SIGSEGV, Segmentation fault. print_interval (prefix=prefix@entry=0x7fffffffc8d0 "", ts=ts@entry=0x0) at builtin-stat.c:866 866 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); (gdb) bt #0 print_interval (prefix=prefix@entry=0x7fffffffc8d0 "", ts=ts@entry=0x0) at builtin-stat.c:866 #1 0x000000000041860a in print_counters (ts=ts@entry=0x0, argc=argc@entry=2, argv=argv@entry=0x7fffffffd640) at builtin-stat.c:938 #2 0x0000000000419a7f in cmd_stat (argc=2, argv=0x7fffffffd640, prefix=) at builtin-stat.c:1411 #3 0x000000000045c65a in run_builtin (p=p@entry=0x6291b8 , argc=argc@entry=5, argv=argv@entry=0x7fffffffd640) at perf.c:370 #4 0x000000000045c893 in handle_internal_command (argc=5, argv=0x7fffffffd640) at perf.c:429 #5 0x000000000045c8f1 in run_argv (argcp=argcp@entry=0x7fffffffd4ac, argv=argv@entry=0x7fffffffd4a0) at perf.c:473 #6 0x000000000045cac9 in main (argc=, argv=) at perf.c:588 (gdb) Mostly the same as just before this patch: Program received signal SIGSEGV, Segmentation fault. 0x00000000005874a7 in print_interval (config=0xa1f2a0 , evlist=0xbc9b90, prefix=0x7fffffffd1c0 "`", ts=0x0) at util/stat-display.c:964 964 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, config->csv_sep); (gdb) bt #0 0x00000000005874a7 in print_interval (config=0xa1f2a0 , evlist=0xbc9b90, prefix=0x7fffffffd1c0 "`", ts=0x0) at util/stat-display.c:964 #1 0x0000000000588047 in perf_evlist__print_counters (evlist=0xbc9b90, config=0xa1f2a0 , _target=0xa1f0c0 , ts=0x0, argc=2, argv=0x7fffffffd670) at util/stat-display.c:1172 #2 0x000000000045390f in print_counters (ts=0x0, argc=2, argv=0x7fffffffd670) at builtin-stat.c:656 #3 0x0000000000456bb5 in cmd_stat (argc=2, argv=0x7fffffffd670) at builtin-stat.c:1960 #4 0x00000000004dd2e0 in run_builtin (p=0xa30e00 , argc=5, argv=0x7fffffffd670) at perf.c:310 #5 0x00000000004dd54d in handle_internal_command (argc=5, argv=0x7fffffffd670) at perf.c:362 #6 0x00000000004dd694 in run_argv (argcp=0x7fffffffd4cc, argv=0x7fffffffd4c0) at perf.c:406 #7 0x00000000004dda11 in main (argc=5, argv=0x7fffffffd670) at perf.c:531 (gdb) Fixes: d4f63a4741a8 ("perf stat: Introduce print_counters function") Signed-off-by: Srikar Dronamraju Acked-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Tested-by: Ravi Bangoria Cc: Namhyung Kim Cc: Naveen N. Rao Cc: stable@vger.kernel.org # v4.2+ Link: http://lore.kernel.org/lkml/20190904094738.9558-3-srikar@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin --- tools/perf/builtin-stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e77880b5094d..65a6922db722 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1416,7 +1416,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) run_idx + 1); status = run_perf_stat(argc, argv); - if (forever && status != -1) { + if (forever && status != -1 && !interval) { print_counters(NULL, argc, argv); perf_stat__reset_stats(); } -- cgit v1.2.3 From a3cda6a020433446d5424c05326149549b7e0d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horia=20Geant=C4=83?= Date: Tue, 30 Jul 2019 08:48:33 +0300 Subject: crypto: caam - fix concurrency issue in givencrypt descriptor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 48f89d2a2920166c35b1c0b69917dbb0390ebec7 upstream. IV transfer from ofifo to class2 (set up at [29][30]) is not guaranteed to be scheduled before the data transfer from ofifo to external memory (set up at [38]: [29] 10FA0004 ld: ind-nfifo (len=4) imm [30] 81F00010 class2 type=msg len=16> [31] 14820004 ld: ccb2-datasz len=4 offs=0 imm [32] 00000010 data:0x00000010 [33] 8210010D operation: cls1-op aes cbc init-final enc [34] A8080B04 math: (seqin + math0)->vseqout len=4 [35] 28000010 seqfifold: skip len=16 [36] A8080A04 math: (seqin + math0)->vseqin len=4 [37] 2F1E0000 seqfifold: both msg1->2-last2-last1 len=vseqinsz [38] 69300000 seqfifostr: msg len=vseqoutsz [39] 5C20000C seqstr: ccb2 ctx len=12 offs=0 If ofifo -> external memory transfer happens first, DECO will hang (issuing a Watchdog Timeout error, if WDOG is enabled) waiting for data availability in ofifo for the ofifo -> c2 ififo transfer. Make sure IV transfer happens first by waiting for all CAAM internal transfers to end before starting payload transfer. New descriptor with jump command inserted at [37]: [..] [36] A8080A04 math: (seqin + math0)->vseqin len=4 [37] A1000401 jump: jsl1 all-match[!nfifopend] offset=[01] local->[38] [38] 2F1E0000 seqfifold: both msg1->2-last2-last1 len=vseqinsz [39] 69300000 seqfifostr: msg len=vseqoutsz [40] 5C20000C seqstr: ccb2 ctx len=12 offs=0 [Note: the issue is present in the descriptor from the very beginning (cf. Fixes tag). However I've marked it v4.19+ since it's the oldest maintained kernel that the patch applies clean against.] Cc: # v4.19+ Fixes: 1acebad3d8db8 ("crypto: caam - faster aead implementation") Signed-off-by: Herbert Xu [Horia: backport to v4.4, v4.9] Signed-off-by: Horia Geantă Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/caam/caamalg.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index f2d1fea23fbf..492432dd5cd6 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -75,7 +75,7 @@ #define DESC_AEAD_BASE (4 * CAAM_CMD_SZ) #define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 11 * CAAM_CMD_SZ) #define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 15 * CAAM_CMD_SZ) -#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 9 * CAAM_CMD_SZ) +#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 10 * CAAM_CMD_SZ) /* Note: Nonce is counted in enckeylen */ #define DESC_AEAD_CTR_RFC3686_LEN (4 * CAAM_CMD_SZ) @@ -437,6 +437,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) u32 geniv, moveiv; u32 ctx1_iv_off = 0; u32 *desc; + u32 *wait_cmd; const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == OP_ALG_AAI_CTR_MOD128); const bool is_rfc3686 = alg->caam.rfc3686; @@ -702,6 +703,14 @@ copy_iv: /* Will read cryptlen */ append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + + /* + * Wait for IV transfer (ofifo -> class2) to finish before starting + * ciphertext transfer (ofifo -> external memory). + */ + wait_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_NIFP); + set_jump_tgt_here(desc, wait_cmd); + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | KEY_VLF | FIFOLD_TYPE_MSG1OUT2 | FIFOLD_TYPE_LASTBOTH); append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); -- cgit v1.2.3 From 933f4f10c9286ce577db1454abb6b50c124823f9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 7 Feb 2019 21:44:41 +0100 Subject: cfg80211: add and use strongly typed element iteration macros commit 0f3b07f027f87a38ebe5c436490095df762819be upstream. Rather than always iterating elements from frames with pure u8 pointers, add a type "struct element" that encapsulates the id/datalen/data format of them. Then, add the element iteration macros * for_each_element * for_each_element_id * for_each_element_extid which take, as their first 'argument', such a structure and iterate through a given u8 array interpreting it as elements. While at it and since we'll need it, also add * for_each_subelement * for_each_subelement_id * for_each_subelement_extid which instead of taking data/length just take an outer element and use its data/datalen. Also add for_each_element_completed() to determine if any of the loops above completed, i.e. it was able to parse all of the elements successfully and no data remained. Use for_each_element_id() in cfg80211_find_ie_match() as the first user of this. Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- include/linux/ieee80211.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 452c0b0d2f32..40978def5aca 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2550,4 +2550,57 @@ static inline bool ieee80211_action_contains_tpc(struct sk_buff *skb) return true; } +struct element { + u8 id; + u8 datalen; + u8 data[]; +}; + +/* element iteration helpers */ +#define for_each_element(element, _data, _datalen) \ + for (element = (void *)(_data); \ + (u8 *)(_data) + (_datalen) - (u8 *)element >= \ + sizeof(*element) && \ + (u8 *)(_data) + (_datalen) - (u8 *)element >= \ + sizeof(*element) + element->datalen; \ + element = (void *)(element->data + element->datalen)) + +#define for_each_element_id(element, _id, data, datalen) \ + for_each_element(element, data, datalen) \ + if (element->id == (_id)) + +#define for_each_element_extid(element, extid, data, datalen) \ + for_each_element(element, data, datalen) \ + if (element->id == WLAN_EID_EXTENSION && \ + element->datalen > 0 && \ + element->data[0] == (extid)) + +#define for_each_subelement(sub, element) \ + for_each_element(sub, (element)->data, (element)->datalen) + +#define for_each_subelement_id(sub, id, element) \ + for_each_element_id(sub, id, (element)->data, (element)->datalen) + +#define for_each_subelement_extid(sub, extid, element) \ + for_each_element_extid(sub, extid, (element)->data, (element)->datalen) + +/** + * for_each_element_completed - determine if element parsing consumed all data + * @element: element pointer after for_each_element() or friends + * @data: same data pointer as passed to for_each_element() or friends + * @datalen: same data length as passed to for_each_element() or friends + * + * This function returns %true if all the data was parsed or considered + * while walking the elements. Only use this if your for_each_element() + * loop cannot be broken out of, otherwise it always returns %false. + * + * If some data was malformed, this returns %false since the last parsed + * element will not fill the whole remaining data. + */ +static inline bool for_each_element_completed(const struct element *element, + const void *data, size_t datalen) +{ + return (u8 *)element == (u8 *)data + datalen; +} + #endif /* LINUX_IEEE80211_H */ -- cgit v1.2.3 From a698649b8e32f80ab1e863f9133ae00f8848544b Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 11 Feb 2019 16:29:04 +0200 Subject: cfg80211: Use const more consistently in for_each_element macros commit 7388afe09143210f555bdd6c75035e9acc1fab96 upstream. Enforce the first argument to be a correct type of a pointer to struct element and avoid unnecessary typecasts from const to non-const pointers (the change in validate_ie_attr() is needed to make this part work). In addition, avoid signed/unsigned comparison within for_each_element() and mark struct element packed just in case. Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- include/linux/ieee80211.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 40978def5aca..149a7a6687e9 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2554,16 +2554,16 @@ struct element { u8 id; u8 datalen; u8 data[]; -}; +} __packed; /* element iteration helpers */ -#define for_each_element(element, _data, _datalen) \ - for (element = (void *)(_data); \ - (u8 *)(_data) + (_datalen) - (u8 *)element >= \ - sizeof(*element) && \ - (u8 *)(_data) + (_datalen) - (u8 *)element >= \ - sizeof(*element) + element->datalen; \ - element = (void *)(element->data + element->datalen)) +#define for_each_element(_elem, _data, _datalen) \ + for (_elem = (const struct element *)(_data); \ + (const u8 *)(_data) + (_datalen) - (const u8 *)_elem >= \ + (int)sizeof(*_elem) && \ + (const u8 *)(_data) + (_datalen) - (const u8 *)_elem >= \ + (int)sizeof(*_elem) + _elem->datalen; \ + _elem = (const struct element *)(_elem->data + _elem->datalen)) #define for_each_element_id(element, _id, data, datalen) \ for_each_element(element, data, datalen) \ @@ -2600,7 +2600,7 @@ struct element { static inline bool for_each_element_completed(const struct element *element, const void *data, size_t datalen) { - return (u8 *)element == (u8 *)data + datalen; + return (const u8 *)element == (const u8 *)data + datalen; } #endif /* LINUX_IEEE80211_H */ -- cgit v1.2.3 From fd27e0779cf62f72bd8242d003d30742d11e451e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Sep 2019 21:54:17 +0200 Subject: nl80211: validate beacon head commit f88eb7c0d002a67ef31aeb7850b42ff69abc46dc upstream. We currently don't validate the beacon head, i.e. the header, fixed part and elements that are to go in front of the TIM element. This means that the variable elements there can be malformed, e.g. have a length exceeding the buffer size, but most downstream code from this assumes that this has already been checked. Add the necessary checks to the netlink policy. Cc: stable@vger.kernel.org Fixes: ed1b6cc7f80f ("cfg80211/nl80211: add beacon settings") Link: https://lore.kernel.org/r/1569009255-I7ac7fbe9436e9d8733439eab8acbbd35e55c74ef@changeid Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/wireless/nl80211.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 844614453852..95c8e682b491 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -210,6 +210,36 @@ cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info) return __cfg80211_rdev_from_attrs(netns, info->attrs); } +static int validate_beacon_head(const struct nlattr *attr) +{ + const u8 *data = nla_data(attr); + unsigned int len = nla_len(attr); + const struct element *elem; + const struct ieee80211_mgmt *mgmt = (void *)data; + unsigned int fixedlen = offsetof(struct ieee80211_mgmt, + u.beacon.variable); + + if (len < fixedlen) + goto err; + + if (ieee80211_hdrlen(mgmt->frame_control) != + offsetof(struct ieee80211_mgmt, u.beacon)) + goto err; + + data += fixedlen; + len -= fixedlen; + + for_each_element(elem, data, len) { + /* nothing */ + } + + if (for_each_element_completed(elem, data, len)) + return 0; + +err: + return -EINVAL; +} + /* policy for the attributes */ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, @@ -3214,6 +3244,11 @@ static int nl80211_parse_beacon(struct nlattr *attrs[], memset(bcn, 0, sizeof(*bcn)); if (attrs[NL80211_ATTR_BEACON_HEAD]) { + int ret = validate_beacon_head(attrs[NL80211_ATTR_BEACON_HEAD]); + + if (ret) + return ret; + bcn->head = nla_data(attrs[NL80211_ATTR_BEACON_HEAD]); bcn->head_len = nla_len(attrs[NL80211_ATTR_BEACON_HEAD]); if (!bcn->head_len) -- cgit v1.2.3 From 82ea9d14f7534c1c5233e56fc9fc66a692facc4a Mon Sep 17 00:00:00 2001 From: Oleksandr Suvorov Date: Wed, 9 Oct 2019 14:29:41 +0000 Subject: ASoC: sgtl5000: Improve VAG power and mute control [ Upstream commit b1f373a11d25fc9a5f7679c9b85799fe09b0dc4a ] VAG power control is improved to fit the manual [1]. This patch fixes as minimum one bug: if customer muxes Headphone to Line-In right after boot, the VAG power remains off that leads to poor sound quality from line-in. I.e. after boot: - Connect sound source to Line-In jack; - Connect headphone to HP jack; - Run following commands: $ amixer set 'Headphone' 80% $ amixer set 'Headphone Mux' LINE_IN Change VAG power on/off control according to the following algorithm: - turn VAG power ON on the 1st incoming event. - keep it ON if there is any active VAG consumer (ADC/DAC/HP/Line-In). - turn VAG power OFF when there is the latest consumer's pre-down event come. - always delay after VAG power OFF to avoid pop. - delay after VAG power ON if the initiative consumer is Line-In, this prevents pop during line-in muxing. According to the data sheet [1], to avoid any pops/clicks, the outputs should be muted during input/output routing changes. [1] https://www.nxp.com/docs/en/data-sheet/SGTL5000.pdf Cc: stable@vger.kernel.org Fixes: 9b34e6cc3bc2 ("ASoC: Add Freescale SGTL5000 codec support") Signed-off-by: Oleksandr Suvorov Reviewed-by: Marcel Ziswiler Reviewed-by: Fabio Estevam Reviewed-by: Cezary Rojewski Link: https://lore.kernel.org/r/20190719100524.23300-3-oleksandr.suvorov@toradex.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/sgtl5000.c | 232 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 202 insertions(+), 30 deletions(-) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 549f853c4092..4808b70ec12c 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -35,6 +35,13 @@ #define SGTL5000_DAP_REG_OFFSET 0x0100 #define SGTL5000_MAX_REG_OFFSET 0x013A +/* Delay for the VAG ramp up */ +#define SGTL5000_VAG_POWERUP_DELAY 500 /* ms */ +/* Delay for the VAG ramp down */ +#define SGTL5000_VAG_POWERDOWN_DELAY 500 /* ms */ + +#define SGTL5000_OUTPUTS_MUTE (SGTL5000_HP_MUTE | SGTL5000_LINE_OUT_MUTE) + /* default value of sgtl5000 registers */ static const struct reg_default sgtl5000_reg_defaults[] = { { SGTL5000_CHIP_DIG_POWER, 0x0000 }, @@ -129,6 +136,13 @@ enum sgtl5000_micbias_resistor { SGTL5000_MICBIAS_8K = 8, }; +enum { + HP_POWER_EVENT, + DAC_POWER_EVENT, + ADC_POWER_EVENT, + LAST_POWER_EVENT = ADC_POWER_EVENT +}; + /* sgtl5000 private structure in codec */ struct sgtl5000_priv { int sysclk; /* sysclk rate */ @@ -141,8 +155,117 @@ struct sgtl5000_priv { int revision; u8 micbias_resistor; u8 micbias_voltage; + u16 mute_state[LAST_POWER_EVENT + 1]; }; +static inline int hp_sel_input(struct snd_soc_component *component) +{ + unsigned int ana_reg = 0; + + snd_soc_component_read(component, SGTL5000_CHIP_ANA_CTRL, &ana_reg); + + return (ana_reg & SGTL5000_HP_SEL_MASK) >> SGTL5000_HP_SEL_SHIFT; +} + +static inline u16 mute_output(struct snd_soc_component *component, + u16 mute_mask) +{ + unsigned int mute_reg = 0; + + snd_soc_component_read(component, SGTL5000_CHIP_ANA_CTRL, &mute_reg); + + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_CTRL, + mute_mask, mute_mask); + return mute_reg; +} + +static inline void restore_output(struct snd_soc_component *component, + u16 mute_mask, u16 mute_reg) +{ + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_CTRL, + mute_mask, mute_reg); +} + +static void vag_power_on(struct snd_soc_component *component, u32 source) +{ + unsigned int ana_reg = 0; + + snd_soc_component_read(component, SGTL5000_CHIP_ANA_POWER, &ana_reg); + + if (ana_reg & SGTL5000_VAG_POWERUP) + return; + + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER, + SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP); + + /* When VAG powering on to get local loop from Line-In, the sleep + * is required to avoid loud pop. + */ + if (hp_sel_input(component) == SGTL5000_HP_SEL_LINE_IN && + source == HP_POWER_EVENT) + msleep(SGTL5000_VAG_POWERUP_DELAY); +} + +static int vag_power_consumers(struct snd_soc_component *component, + u16 ana_pwr_reg, u32 source) +{ + int consumers = 0; + + /* count dac/adc consumers unconditional */ + if (ana_pwr_reg & SGTL5000_DAC_POWERUP) + consumers++; + if (ana_pwr_reg & SGTL5000_ADC_POWERUP) + consumers++; + + /* + * If the event comes from HP and Line-In is selected, + * current action is 'DAC to be powered down'. + * As HP_POWERUP is not set when HP muxed to line-in, + * we need to keep VAG power ON. + */ + if (source == HP_POWER_EVENT) { + if (hp_sel_input(component) == SGTL5000_HP_SEL_LINE_IN) + consumers++; + } else { + if (ana_pwr_reg & SGTL5000_HP_POWERUP) + consumers++; + } + + return consumers; +} + +static void vag_power_off(struct snd_soc_component *component, u32 source) +{ + unsigned int ana_pwr = SGTL5000_VAG_POWERUP; + + snd_soc_component_read(component, SGTL5000_CHIP_ANA_POWER, &ana_pwr); + + if (!(ana_pwr & SGTL5000_VAG_POWERUP)) + return; + + /* + * This function calls when any of VAG power consumers is disappearing. + * Thus, if there is more than one consumer at the moment, as minimum + * one consumer will definitely stay after the end of the current + * event. + * Don't clear VAG_POWERUP if 2 or more consumers of VAG present: + * - LINE_IN (for HP events) / HP (for DAC/ADC events) + * - DAC + * - ADC + * (the current consumer is disappearing right now) + */ + if (vag_power_consumers(component, ana_pwr, source) >= 2) + return; + + snd_soc_component_update_bits(component, SGTL5000_CHIP_ANA_POWER, + SGTL5000_VAG_POWERUP, 0); + /* In power down case, we need wait 400-1000 ms + * when VAG fully ramped down. + * As longer we wait, as smaller pop we've got. + */ + msleep(SGTL5000_VAG_POWERDOWN_DELAY); +} + /* * mic_bias power on/off share the same register bits with * output impedance of mic bias, when power on mic bias, we @@ -174,36 +297,46 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, return 0; } -/* - * As manual described, ADC/DAC only works when VAG powerup, - * So enabled VAG before ADC/DAC up. - * In power down case, we need wait 400ms when vag fully ramped down. - */ -static int power_vag_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static int vag_and_mute_control(struct snd_soc_component *component, + int event, int event_source) { - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - const u32 mask = SGTL5000_DAC_POWERUP | SGTL5000_ADC_POWERUP; + static const u16 mute_mask[] = { + /* + * Mask for HP_POWER_EVENT. + * Muxing Headphones have to be wrapped with mute/unmute + * headphones only. + */ + SGTL5000_HP_MUTE, + /* + * Masks for DAC_POWER_EVENT/ADC_POWER_EVENT. + * Muxing DAC or ADC block have to be wrapped with mute/unmute + * both headphones and line-out. + */ + SGTL5000_OUTPUTS_MUTE, + SGTL5000_OUTPUTS_MUTE + }; + + struct sgtl5000_priv *sgtl5000 = + snd_soc_component_get_drvdata(component); switch (event) { + case SND_SOC_DAPM_PRE_PMU: + sgtl5000->mute_state[event_source] = + mute_output(component, mute_mask[event_source]); + break; case SND_SOC_DAPM_POST_PMU: - snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, - SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP); - msleep(400); + vag_power_on(component, event_source); + restore_output(component, mute_mask[event_source], + sgtl5000->mute_state[event_source]); break; - case SND_SOC_DAPM_PRE_PMD: - /* - * Don't clear VAG_POWERUP, when both DAC and ADC are - * operational to prevent inadvertently starving the - * other one of them. - */ - if ((snd_soc_read(codec, SGTL5000_CHIP_ANA_POWER) & - mask) != mask) { - snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, - SGTL5000_VAG_POWERUP, 0); - msleep(400); - } + sgtl5000->mute_state[event_source] = + mute_output(component, mute_mask[event_source]); + vag_power_off(component, event_source); + break; + case SND_SOC_DAPM_POST_PMD: + restore_output(component, mute_mask[event_source], + sgtl5000->mute_state[event_source]); break; default: break; @@ -212,6 +345,41 @@ static int power_vag_event(struct snd_soc_dapm_widget *w, return 0; } +/* + * Mute Headphone when power it up/down. + * Control VAG power on HP power path. + */ +static int headphone_pga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + return vag_and_mute_control(component, event, HP_POWER_EVENT); +} + +/* As manual describes, ADC/DAC powering up/down requires + * to mute outputs to avoid pops. + * Control VAG power on ADC/DAC power path. + */ +static int adc_updown_depop(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + return vag_and_mute_control(component, event, ADC_POWER_EVENT); +} + +static int dac_updown_depop(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + return vag_and_mute_control(component, event, DAC_POWER_EVENT); +} + /* input sources for ADC */ static const char *adc_mux_text[] = { "MIC_IN", "LINE_IN" @@ -247,7 +415,10 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = { mic_bias_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_PGA("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0, + headphone_pga_event, + SND_SOC_DAPM_PRE_POST_PMU | + SND_SOC_DAPM_PRE_POST_PMD), SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0), SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, &adc_mux), @@ -263,11 +434,12 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = { 0, SGTL5000_CHIP_DIG_POWER, 1, 0), - SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0), - SND_SOC_DAPM_DAC("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0), - - SND_SOC_DAPM_PRE("VAG_POWER_PRE", power_vag_event), - SND_SOC_DAPM_POST("VAG_POWER_POST", power_vag_event), + SND_SOC_DAPM_ADC_E("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0, + adc_updown_depop, SND_SOC_DAPM_PRE_POST_PMU | + SND_SOC_DAPM_PRE_POST_PMD), + SND_SOC_DAPM_DAC_E("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0, + dac_updown_depop, SND_SOC_DAPM_PRE_POST_PMU | + SND_SOC_DAPM_PRE_POST_PMD), }; /* routes for sgtl5000 */ -- cgit v1.2.3 From 43b7a9d0d62a9168605178aeb86d51776db5e044 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Sun, 6 Oct 2019 17:58:00 -0700 Subject: panic: ensure preemption is disabled during panic() commit 20bb759a66be52cf4a9ddd17fddaf509e11490cd upstream. Calling 'panic()' on a kernel with CONFIG_PREEMPT=y can leave the calling CPU in an infinite loop, but with interrupts and preemption enabled. From this state, userspace can continue to be scheduled, despite the system being "dead" as far as the kernel is concerned. This is easily reproducible on arm64 when booting with "nosmp" on the command line; a couple of shell scripts print out a periodic "Ping" message whilst another triggers a crash by writing to /proc/sysrq-trigger: | sysrq: Trigger a crash | Kernel panic - not syncing: sysrq triggered crash | CPU: 0 PID: 1 Comm: init Not tainted 5.2.15 #1 | Hardware name: linux,dummy-virt (DT) | Call trace: | dump_backtrace+0x0/0x148 | show_stack+0x14/0x20 | dump_stack+0xa0/0xc4 | panic+0x140/0x32c | sysrq_handle_reboot+0x0/0x20 | __handle_sysrq+0x124/0x190 | write_sysrq_trigger+0x64/0x88 | proc_reg_write+0x60/0xa8 | __vfs_write+0x18/0x40 | vfs_write+0xa4/0x1b8 | ksys_write+0x64/0xf0 | __arm64_sys_write+0x14/0x20 | el0_svc_common.constprop.0+0xb0/0x168 | el0_svc_handler+0x28/0x78 | el0_svc+0x8/0xc | Kernel Offset: disabled | CPU features: 0x0002,24002004 | Memory Limit: none | ---[ end Kernel panic - not syncing: sysrq triggered crash ]--- | Ping 2! | Ping 1! | Ping 1! | Ping 2! The issue can also be triggered on x86 kernels if CONFIG_SMP=n, otherwise local interrupts are disabled in 'smp_send_stop()'. Disable preemption in 'panic()' before re-enabling interrupts. Link: http://lkml.kernel.org/r/20191002123538.22609-1-will@kernel.org Link: https://lore.kernel.org/r/BX1W47JXPMR8.58IYW53H6M5N@dragonstone Signed-off-by: Will Deacon Reported-by: Xogium Reviewed-by: Kees Cook Cc: Russell King Cc: Greg Kroah-Hartman Cc: Ingo Molnar Cc: Petr Mladek Cc: Feng Tang Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/panic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/panic.c b/kernel/panic.c index 1d07cf9af849..dde00886c896 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -84,6 +84,7 @@ void panic(const char *fmt, ...) * after the panic_lock is acquired) from invoking panic again. */ local_irq_disable(); + preempt_disable_notrace(); /* * It's possible to come here directly from a panic-assertion and -- cgit v1.2.3 From b5583d6963d092353214e4b74eada4a201af7586 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 23 Sep 2019 18:18:43 +0200 Subject: USB: rio500: Remove Rio 500 kernel driver commit 015664d15270a112c2371d812f03f7c579b35a73 upstream. The Rio500 kernel driver has not been used by Rio500 owners since 2001 not long after the rio500 project added support for a user-space USB stack through the very first versions of usbdevfs and then libusb. Support for the kernel driver was removed from the upstream utilities in 2008: https://gitlab.freedesktop.org/hadess/rio500/commit/943f624ab721eb8281c287650fcc9e2026f6f5db Cc: Cesar Miquel Signed-off-by: Bastien Nocera Cc: stable Link: https://lore.kernel.org/r/6251c17584d220472ce882a3d9c199c401a51a71.camel@hadess.net Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/rio.txt | 138 --------- MAINTAINERS | 7 - arch/arm/configs/badge4_defconfig | 1 - arch/arm/configs/corgi_defconfig | 1 - arch/arm/configs/s3c2410_defconfig | 1 - arch/arm/configs/spitz_defconfig | 1 - arch/mips/configs/mtx1_defconfig | 1 - arch/mips/configs/rm200_defconfig | 1 - drivers/usb/misc/Kconfig | 10 - drivers/usb/misc/Makefile | 1 - drivers/usb/misc/rio500.c | 578 ------------------------------------- drivers/usb/misc/rio500_usb.h | 37 --- 12 files changed, 777 deletions(-) delete mode 100644 Documentation/usb/rio.txt delete mode 100644 drivers/usb/misc/rio500.c delete mode 100644 drivers/usb/misc/rio500_usb.h diff --git a/Documentation/usb/rio.txt b/Documentation/usb/rio.txt deleted file mode 100644 index aee715af7db7..000000000000 --- a/Documentation/usb/rio.txt +++ /dev/null @@ -1,138 +0,0 @@ -Copyright (C) 1999, 2000 Bruce Tenison -Portions Copyright (C) 1999, 2000 David Nelson -Thanks to David Nelson for guidance and the usage of the scanner.txt -and scanner.c files to model our driver and this informative file. - -Mar. 2, 2000 - -CHANGES - -- Initial Revision - - -OVERVIEW - -This README will address issues regarding how to configure the kernel -to access a RIO 500 mp3 player. -Before I explain how to use this to access the Rio500 please be warned: - -W A R N I N G: --------------- - -Please note that this software is still under development. The authors -are in no way responsible for any damage that may occur, no matter how -inconsequential. - -It seems that the Rio has a problem when sending .mp3 with low batteries. -I suggest when the batteries are low and you want to transfer stuff that you -replace it with a fresh one. In my case, what happened is I lost two 16kb -blocks (they are no longer usable to store information to it). But I don't -know if that's normal or not; it could simply be a problem with the flash -memory. - -In an extreme case, I left my Rio playing overnight and the batteries wore -down to nothing and appear to have corrupted the flash memory. My RIO -needed to be replaced as a result. Diamond tech support is aware of the -problem. Do NOT allow your batteries to wear down to nothing before -changing them. It appears RIO 500 firmware does not handle low battery -power well at all. - -On systems with OHCI controllers, the kernel OHCI code appears to have -power on problems with some chipsets. If you are having problems -connecting to your RIO 500, try turning it on first and then plugging it -into the USB cable. - -Contact information: --------------------- - - The main page for the project is hosted at sourceforge.net in the following - URL: . You can also go to the project's - sourceforge home page at: . - There is also a mailing list: rio500-users@lists.sourceforge.net - -Authors: -------- - -Most of the code was written by Cesar Miquel . Keith -Clayton is incharge of the PPC port and making sure -things work there. Bruce Tenison is adding support -for .fon files and also does testing. The program will mostly sure be -re-written and Pete Ikusz along with the rest will re-design it. I would -also like to thank Tri Nguyen who provided use -with some important information regarding the communication with the Rio. - -ADDITIONAL INFORMATION and Userspace tools - -http://rio500.sourceforge.net/ - - -REQUIREMENTS - -A host with a USB port. Ideally, either a UHCI (Intel) or OHCI -(Compaq and others) hardware port should work. - -A Linux development kernel (2.3.x) with USB support enabled or a -backported version to linux-2.2.x. See http://www.linux-usb.org for -more information on accomplishing this. - -A Linux kernel with RIO 500 support enabled. - -'lspci' which is only needed to determine the type of USB hardware -available in your machine. - -CONFIGURATION - -Using `lspci -v`, determine the type of USB hardware available. - - If you see something like: - - USB Controller: ...... - Flags: ..... - I/O ports at .... - - Then you have a UHCI based controller. - - If you see something like: - - USB Controller: ..... - Flags: .... - Memory at ..... - - Then you have a OHCI based controller. - -Using `make menuconfig` or your preferred method for configuring the -kernel, select 'Support for USB', 'OHCI/UHCI' depending on your -hardware (determined from the steps above), 'USB Diamond Rio500 support', and -'Preliminary USB device filesystem'. Compile and install the modules -(you may need to execute `depmod -a` to update the module -dependencies). - -Add a device for the USB rio500: - `mknod /dev/usb/rio500 c 180 64` - -Set appropriate permissions for /dev/usb/rio500 (don't forget about -group and world permissions). Both read and write permissions are -required for proper operation. - -Load the appropriate modules (if compiled as modules): - - OHCI: - modprobe usbcore - modprobe usb-ohci - modprobe rio500 - - UHCI: - modprobe usbcore - modprobe usb-uhci (or uhci) - modprobe rio500 - -That's it. The Rio500 Utils at: http://rio500.sourceforge.net should -be able to access the rio500. - -BUGS - -If you encounter any problems feel free to drop me an email. - -Bruce Tenison -btenison@dibbs.net - diff --git a/MAINTAINERS b/MAINTAINERS index 20a31b357929..e1a15f7507fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11100,13 +11100,6 @@ W: http://www.linux-usb.org/usbnet S: Maintained F: drivers/net/usb/dm9601.c -USB DIAMOND RIO500 DRIVER -M: Cesar Miquel -L: rio500-users@lists.sourceforge.net -W: http://rio500.sourceforge.net -S: Maintained -F: drivers/usb/misc/rio500* - USB EHCI DRIVER M: Alan Stern L: linux-usb@vger.kernel.org diff --git a/arch/arm/configs/badge4_defconfig b/arch/arm/configs/badge4_defconfig index d59009878312..067d73e3b28b 100644 --- a/arch/arm/configs/badge4_defconfig +++ b/arch/arm/configs/badge4_defconfig @@ -97,7 +97,6 @@ CONFIG_USB_SERIAL_PL2303=m CONFIG_USB_SERIAL_CYBERJACK=m CONFIG_USB_SERIAL_XIRCOM=m CONFIG_USB_SERIAL_OMNINET=m -CONFIG_USB_RIO500=m CONFIG_EXT2_FS=m CONFIG_EXT3_FS=m CONFIG_MSDOS_FS=y diff --git a/arch/arm/configs/corgi_defconfig b/arch/arm/configs/corgi_defconfig index c1470a00f55a..031d9d3549b9 100644 --- a/arch/arm/configs/corgi_defconfig +++ b/arch/arm/configs/corgi_defconfig @@ -207,7 +207,6 @@ CONFIG_USB_SERIAL_XIRCOM=m CONFIG_USB_SERIAL_OMNINET=m CONFIG_USB_EMI62=m CONFIG_USB_EMI26=m -CONFIG_USB_RIO500=m CONFIG_USB_LEGOTOWER=m CONFIG_USB_LCD=m CONFIG_USB_LED=m diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig index 01116ee1284b..a199b0e1a6ea 100644 --- a/arch/arm/configs/s3c2410_defconfig +++ b/arch/arm/configs/s3c2410_defconfig @@ -354,7 +354,6 @@ CONFIG_USB_EMI62=m CONFIG_USB_EMI26=m CONFIG_USB_ADUTUX=m CONFIG_USB_SEVSEG=m -CONFIG_USB_RIO500=m CONFIG_USB_LEGOTOWER=m CONFIG_USB_LCD=m CONFIG_USB_LED=m diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig index a1ede1966baf..7d9aa284cb6f 100644 --- a/arch/arm/configs/spitz_defconfig +++ b/arch/arm/configs/spitz_defconfig @@ -202,7 +202,6 @@ CONFIG_USB_SERIAL_XIRCOM=m CONFIG_USB_SERIAL_OMNINET=m CONFIG_USB_EMI62=m CONFIG_USB_EMI26=m -CONFIG_USB_RIO500=m CONFIG_USB_LEGOTOWER=m CONFIG_USB_LCD=m CONFIG_USB_LED=m diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig index 9b6926d6bb32..6ac662afd5c1 100644 --- a/arch/mips/configs/mtx1_defconfig +++ b/arch/mips/configs/mtx1_defconfig @@ -638,7 +638,6 @@ CONFIG_USB_SERIAL_OMNINET=m CONFIG_USB_EMI62=m CONFIG_USB_EMI26=m CONFIG_USB_ADUTUX=m -CONFIG_USB_RIO500=m CONFIG_USB_LEGOTOWER=m CONFIG_USB_LCD=m CONFIG_USB_LED=m diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig index db029f4ff759..4acaa3fb4818 100644 --- a/arch/mips/configs/rm200_defconfig +++ b/arch/mips/configs/rm200_defconfig @@ -351,7 +351,6 @@ CONFIG_USB_SERIAL_SAFE_PADDED=y CONFIG_USB_SERIAL_CYBERJACK=m CONFIG_USB_SERIAL_XIRCOM=m CONFIG_USB_SERIAL_OMNINET=m -CONFIG_USB_RIO500=m CONFIG_USB_LEGOTOWER=m CONFIG_USB_LCD=m CONFIG_USB_LED=m diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index f7a7fc21be8a..c7383c41c90e 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -46,16 +46,6 @@ config USB_SEVSEG To compile this driver as a module, choose M here: the module will be called usbsevseg. -config USB_RIO500 - tristate "USB Diamond Rio500 support" - help - Say Y here if you want to connect a USB Rio500 mp3 player to your - computer's USB port. Please read - for more information. - - To compile this driver as a module, choose M here: the - module will be called rio500. - config USB_LEGOTOWER tristate "USB Lego Infrared Tower support" help diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 45fd4ac39d3e..0cbdd77363f2 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -17,7 +17,6 @@ obj-$(CONFIG_USB_LCD) += usblcd.o obj-$(CONFIG_USB_LD) += ldusb.o obj-$(CONFIG_USB_LED) += usbled.o obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o -obj-$(CONFIG_USB_RIO500) += rio500.o obj-$(CONFIG_USB_TEST) += usbtest.o obj-$(CONFIG_USB_EHSET_TEST_FIXTURE) += ehset.o obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c deleted file mode 100644 index 6e761fabffca..000000000000 --- a/drivers/usb/misc/rio500.c +++ /dev/null @@ -1,578 +0,0 @@ -/* -*- linux-c -*- */ - -/* - * Driver for USB Rio 500 - * - * Cesar Miquel (miquel@df.uba.ar) - * - * based on hp_scanner.c by David E. Nelson (dnelson@jump.net) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee). - * - * Changelog: - * 30/05/2003 replaced lock/unlock kernel with up/down - * Daniele Bellucci bellucda@tiscali.it - * */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rio500_usb.h" - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.1" -#define DRIVER_AUTHOR "Cesar Miquel " -#define DRIVER_DESC "USB Rio 500 driver" - -#define RIO_MINOR 64 - -/* stall/wait timeout for rio */ -#define NAK_TIMEOUT (HZ) - -#define IBUF_SIZE 0x1000 - -/* Size of the rio buffer */ -#define OBUF_SIZE 0x10000 - -struct rio_usb_data { - struct usb_device *rio_dev; /* init: probe_rio */ - unsigned int ifnum; /* Interface number of the USB device */ - int isopen; /* nz if open */ - int present; /* Device is present on the bus */ - char *obuf, *ibuf; /* transfer buffers */ - char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */ - wait_queue_head_t wait_q; /* for timeouts */ - struct mutex lock; /* general race avoidance */ -}; - -static DEFINE_MUTEX(rio500_mutex); -static struct rio_usb_data rio_instance; - -static int open_rio(struct inode *inode, struct file *file) -{ - struct rio_usb_data *rio = &rio_instance; - - /* against disconnect() */ - mutex_lock(&rio500_mutex); - mutex_lock(&(rio->lock)); - - if (rio->isopen || !rio->present) { - mutex_unlock(&(rio->lock)); - mutex_unlock(&rio500_mutex); - return -EBUSY; - } - rio->isopen = 1; - - init_waitqueue_head(&rio->wait_q); - - mutex_unlock(&(rio->lock)); - - dev_info(&rio->rio_dev->dev, "Rio opened.\n"); - mutex_unlock(&rio500_mutex); - - return 0; -} - -static int close_rio(struct inode *inode, struct file *file) -{ - struct rio_usb_data *rio = &rio_instance; - - /* against disconnect() */ - mutex_lock(&rio500_mutex); - mutex_lock(&(rio->lock)); - - rio->isopen = 0; - if (!rio->present) { - /* cleanup has been delayed */ - kfree(rio->ibuf); - kfree(rio->obuf); - rio->ibuf = NULL; - rio->obuf = NULL; - } else { - dev_info(&rio->rio_dev->dev, "Rio closed.\n"); - } - mutex_unlock(&(rio->lock)); - mutex_unlock(&rio500_mutex); - return 0; -} - -static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct RioCommand rio_cmd; - struct rio_usb_data *rio = &rio_instance; - void __user *data; - unsigned char *buffer; - int result, requesttype; - int retries; - int retval=0; - - mutex_lock(&(rio->lock)); - /* Sanity check to make sure rio is connected, powered, etc */ - if (rio->present == 0 || rio->rio_dev == NULL) { - retval = -ENODEV; - goto err_out; - } - - switch (cmd) { - case RIO_RECV_COMMAND: - data = (void __user *) arg; - if (data == NULL) - break; - if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) { - retval = -EFAULT; - goto err_out; - } - if (rio_cmd.length < 0 || rio_cmd.length > PAGE_SIZE) { - retval = -EINVAL; - goto err_out; - } - buffer = (unsigned char *) __get_free_page(GFP_KERNEL); - if (buffer == NULL) { - retval = -ENOMEM; - goto err_out; - } - if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) { - retval = -EFAULT; - free_page((unsigned long) buffer); - goto err_out; - } - - requesttype = rio_cmd.requesttype | USB_DIR_IN | - USB_TYPE_VENDOR | USB_RECIP_DEVICE; - dev_dbg(&rio->rio_dev->dev, - "sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", - requesttype, rio_cmd.request, rio_cmd.value, - rio_cmd.index, rio_cmd.length); - /* Send rio control message */ - retries = 3; - while (retries) { - result = usb_control_msg(rio->rio_dev, - usb_rcvctrlpipe(rio-> rio_dev, 0), - rio_cmd.request, - requesttype, - rio_cmd.value, - rio_cmd.index, buffer, - rio_cmd.length, - jiffies_to_msecs(rio_cmd.timeout)); - if (result == -ETIMEDOUT) - retries--; - else if (result < 0) { - dev_err(&rio->rio_dev->dev, - "Error executing ioctrl. code = %d\n", - result); - retries = 0; - } else { - dev_dbg(&rio->rio_dev->dev, - "Executed ioctl. Result = %d (data=%02x)\n", - result, buffer[0]); - if (copy_to_user(rio_cmd.buffer, buffer, - rio_cmd.length)) { - free_page((unsigned long) buffer); - retval = -EFAULT; - goto err_out; - } - retries = 0; - } - - /* rio_cmd.buffer contains a raw stream of single byte - data which has been returned from rio. Data is - interpreted at application level. For data that - will be cast to data types longer than 1 byte, data - will be little_endian and will potentially need to - be swapped at the app level */ - - } - free_page((unsigned long) buffer); - break; - - case RIO_SEND_COMMAND: - data = (void __user *) arg; - if (data == NULL) - break; - if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) { - retval = -EFAULT; - goto err_out; - } - if (rio_cmd.length < 0 || rio_cmd.length > PAGE_SIZE) { - retval = -EINVAL; - goto err_out; - } - buffer = (unsigned char *) __get_free_page(GFP_KERNEL); - if (buffer == NULL) { - retval = -ENOMEM; - goto err_out; - } - if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) { - free_page((unsigned long)buffer); - retval = -EFAULT; - goto err_out; - } - - requesttype = rio_cmd.requesttype | USB_DIR_OUT | - USB_TYPE_VENDOR | USB_RECIP_DEVICE; - dev_dbg(&rio->rio_dev->dev, - "sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", - requesttype, rio_cmd.request, rio_cmd.value, - rio_cmd.index, rio_cmd.length); - /* Send rio control message */ - retries = 3; - while (retries) { - result = usb_control_msg(rio->rio_dev, - usb_sndctrlpipe(rio-> rio_dev, 0), - rio_cmd.request, - requesttype, - rio_cmd.value, - rio_cmd.index, buffer, - rio_cmd.length, - jiffies_to_msecs(rio_cmd.timeout)); - if (result == -ETIMEDOUT) - retries--; - else if (result < 0) { - dev_err(&rio->rio_dev->dev, - "Error executing ioctrl. code = %d\n", - result); - retries = 0; - } else { - dev_dbg(&rio->rio_dev->dev, - "Executed ioctl. Result = %d\n", result); - retries = 0; - - } - - } - free_page((unsigned long) buffer); - break; - - default: - retval = -ENOTTY; - break; - } - - -err_out: - mutex_unlock(&(rio->lock)); - return retval; -} - -static ssize_t -write_rio(struct file *file, const char __user *buffer, - size_t count, loff_t * ppos) -{ - DEFINE_WAIT(wait); - struct rio_usb_data *rio = &rio_instance; - - unsigned long copy_size; - unsigned long bytes_written = 0; - unsigned int partial; - - int result = 0; - int maxretry; - int errn = 0; - int intr; - - intr = mutex_lock_interruptible(&(rio->lock)); - if (intr) - return -EINTR; - /* Sanity check to make sure rio is connected, powered, etc */ - if (rio->present == 0 || rio->rio_dev == NULL) { - mutex_unlock(&(rio->lock)); - return -ENODEV; - } - - - - do { - unsigned long thistime; - char *obuf = rio->obuf; - - thistime = copy_size = - (count >= OBUF_SIZE) ? OBUF_SIZE : count; - if (copy_from_user(rio->obuf, buffer, copy_size)) { - errn = -EFAULT; - goto error; - } - maxretry = 5; - while (thistime) { - if (!rio->rio_dev) { - errn = -ENODEV; - goto error; - } - if (signal_pending(current)) { - mutex_unlock(&(rio->lock)); - return bytes_written ? bytes_written : -EINTR; - } - - result = usb_bulk_msg(rio->rio_dev, - usb_sndbulkpipe(rio->rio_dev, 2), - obuf, thistime, &partial, 5000); - - dev_dbg(&rio->rio_dev->dev, - "write stats: result:%d thistime:%lu partial:%u\n", - result, thistime, partial); - - if (result == -ETIMEDOUT) { /* NAK - so hold for a while */ - if (!maxretry--) { - errn = -ETIME; - goto error; - } - prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE); - schedule_timeout(NAK_TIMEOUT); - finish_wait(&rio->wait_q, &wait); - continue; - } else if (!result && partial) { - obuf += partial; - thistime -= partial; - } else - break; - } - if (result) { - dev_err(&rio->rio_dev->dev, "Write Whoops - %x\n", - result); - errn = -EIO; - goto error; - } - bytes_written += copy_size; - count -= copy_size; - buffer += copy_size; - } while (count > 0); - - mutex_unlock(&(rio->lock)); - - return bytes_written ? bytes_written : -EIO; - -error: - mutex_unlock(&(rio->lock)); - return errn; -} - -static ssize_t -read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) -{ - DEFINE_WAIT(wait); - struct rio_usb_data *rio = &rio_instance; - ssize_t read_count; - unsigned int partial; - int this_read; - int result; - int maxretry = 10; - char *ibuf; - int intr; - - intr = mutex_lock_interruptible(&(rio->lock)); - if (intr) - return -EINTR; - /* Sanity check to make sure rio is connected, powered, etc */ - if (rio->present == 0 || rio->rio_dev == NULL) { - mutex_unlock(&(rio->lock)); - return -ENODEV; - } - - ibuf = rio->ibuf; - - read_count = 0; - - - while (count > 0) { - if (signal_pending(current)) { - mutex_unlock(&(rio->lock)); - return read_count ? read_count : -EINTR; - } - if (!rio->rio_dev) { - mutex_unlock(&(rio->lock)); - return -ENODEV; - } - this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count; - - result = usb_bulk_msg(rio->rio_dev, - usb_rcvbulkpipe(rio->rio_dev, 1), - ibuf, this_read, &partial, - 8000); - - dev_dbg(&rio->rio_dev->dev, - "read stats: result:%d this_read:%u partial:%u\n", - result, this_read, partial); - - if (partial) { - count = this_read = partial; - } else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */ - if (!maxretry--) { - mutex_unlock(&(rio->lock)); - dev_err(&rio->rio_dev->dev, - "read_rio: maxretry timeout\n"); - return -ETIME; - } - prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE); - schedule_timeout(NAK_TIMEOUT); - finish_wait(&rio->wait_q, &wait); - continue; - } else if (result != -EREMOTEIO) { - mutex_unlock(&(rio->lock)); - dev_err(&rio->rio_dev->dev, - "Read Whoops - result:%u partial:%u this_read:%u\n", - result, partial, this_read); - return -EIO; - } else { - mutex_unlock(&(rio->lock)); - return (0); - } - - if (this_read) { - if (copy_to_user(buffer, ibuf, this_read)) { - mutex_unlock(&(rio->lock)); - return -EFAULT; - } - count -= this_read; - read_count += this_read; - buffer += this_read; - } - } - mutex_unlock(&(rio->lock)); - return read_count; -} - -static const struct file_operations usb_rio_fops = { - .owner = THIS_MODULE, - .read = read_rio, - .write = write_rio, - .unlocked_ioctl = ioctl_rio, - .open = open_rio, - .release = close_rio, - .llseek = noop_llseek, -}; - -static struct usb_class_driver usb_rio_class = { - .name = "rio500%d", - .fops = &usb_rio_fops, - .minor_base = RIO_MINOR, -}; - -static int probe_rio(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct rio_usb_data *rio = &rio_instance; - int retval = 0; - - mutex_lock(&rio500_mutex); - if (rio->present) { - dev_info(&intf->dev, "Second USB Rio at address %d refused\n", dev->devnum); - retval = -EBUSY; - goto bail_out; - } else { - dev_info(&intf->dev, "USB Rio found at address %d\n", dev->devnum); - } - - retval = usb_register_dev(intf, &usb_rio_class); - if (retval) { - dev_err(&dev->dev, - "Not able to get a minor for this device.\n"); - retval = -ENOMEM; - goto bail_out; - } - - rio->rio_dev = dev; - - if (!(rio->obuf = kmalloc(OBUF_SIZE, GFP_KERNEL))) { - dev_err(&dev->dev, - "probe_rio: Not enough memory for the output buffer\n"); - usb_deregister_dev(intf, &usb_rio_class); - retval = -ENOMEM; - goto bail_out; - } - dev_dbg(&intf->dev, "obuf address:%p\n", rio->obuf); - - if (!(rio->ibuf = kmalloc(IBUF_SIZE, GFP_KERNEL))) { - dev_err(&dev->dev, - "probe_rio: Not enough memory for the input buffer\n"); - usb_deregister_dev(intf, &usb_rio_class); - kfree(rio->obuf); - retval = -ENOMEM; - goto bail_out; - } - dev_dbg(&intf->dev, "ibuf address:%p\n", rio->ibuf); - - mutex_init(&(rio->lock)); - - usb_set_intfdata (intf, rio); - rio->present = 1; -bail_out: - mutex_unlock(&rio500_mutex); - - return retval; -} - -static void disconnect_rio(struct usb_interface *intf) -{ - struct rio_usb_data *rio = usb_get_intfdata (intf); - - usb_set_intfdata (intf, NULL); - mutex_lock(&rio500_mutex); - if (rio) { - usb_deregister_dev(intf, &usb_rio_class); - - mutex_lock(&(rio->lock)); - if (rio->isopen) { - rio->isopen = 0; - /* better let it finish - the release will do whats needed */ - rio->rio_dev = NULL; - mutex_unlock(&(rio->lock)); - mutex_unlock(&rio500_mutex); - return; - } - kfree(rio->ibuf); - kfree(rio->obuf); - - dev_info(&intf->dev, "USB Rio disconnected.\n"); - - rio->present = 0; - mutex_unlock(&(rio->lock)); - } - mutex_unlock(&rio500_mutex); -} - -static const struct usb_device_id rio_table[] = { - { USB_DEVICE(0x0841, 1) }, /* Rio 500 */ - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, rio_table); - -static struct usb_driver rio_driver = { - .name = "rio500", - .probe = probe_rio, - .disconnect = disconnect_rio, - .id_table = rio_table, -}; - -module_usb_driver(rio_driver); - -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); - diff --git a/drivers/usb/misc/rio500_usb.h b/drivers/usb/misc/rio500_usb.h deleted file mode 100644 index 359abc98e706..000000000000 --- a/drivers/usb/misc/rio500_usb.h +++ /dev/null @@ -1,37 +0,0 @@ -/* ---------------------------------------------------------------------- - - Copyright (C) 2000 Cesar Miquel (miquel@df.uba.ar) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - ---------------------------------------------------------------------- */ - - - -#define RIO_SEND_COMMAND 0x1 -#define RIO_RECV_COMMAND 0x2 - -#define RIO_DIR_OUT 0x0 -#define RIO_DIR_IN 0x1 - -struct RioCommand { - short length; - int request; - int requesttype; - int value; - int index; - void __user *buffer; - int timeout; -}; -- cgit v1.2.3 From d777eecf20bd7835f292d252deae4d236aad69aa Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 17 Sep 2019 12:47:23 -0400 Subject: USB: yurex: Don't retry on unexpected errors commit 32a0721c6620b77504916dac0cea8ad497c4878a upstream. According to Greg KH, it has been generally agreed that when a USB driver encounters an unknown error (or one it can't handle directly), it should just give up instead of going into a potentially infinite retry loop. The three codes -EPROTO, -EILSEQ, and -ETIME fall into this category. They can be caused by bus errors such as packet loss or corruption, attempting to communicate with a disconnected device, or by malicious firmware. Nowadays the extent of packet loss or corruption is negligible, so it should be safe for a driver to give up whenever one of these errors occurs. Although the yurex driver handles -EILSEQ errors in this way, it doesn't do the same for -EPROTO (as discovered by the syzbot fuzzer) or other unrecognized errors. This patch adjusts the driver so that it doesn't log an error message for -EPROTO or -ETIME, and it doesn't retry after any errors. Reported-and-tested-by: syzbot+b24d736f18a1541ad550@syzkaller.appspotmail.com Signed-off-by: Alan Stern CC: Tomoki Sekiyama CC: Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.1909171245410.1590-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/yurex.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index 2222ec2275fc..51f7e7f24ca4 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -136,6 +136,7 @@ static void yurex_interrupt(struct urb *urb) switch (status) { case 0: /*success*/ break; + /* The device is terminated or messed up, give up */ case -EOVERFLOW: dev_err(&dev->interface->dev, "%s - overflow with length %d, actual length is %d\n", @@ -144,12 +145,13 @@ static void yurex_interrupt(struct urb *urb) case -ENOENT: case -ESHUTDOWN: case -EILSEQ: - /* The device is terminated, clean up */ + case -EPROTO: + case -ETIME: return; default: dev_err(&dev->interface->dev, "%s - unknown status received: %d\n", __func__, status); - goto exit; + return; } /* handle received message */ @@ -181,7 +183,6 @@ static void yurex_interrupt(struct urb *urb) break; } -exit: retval = usb_submit_urb(dev->urb, GFP_ATOMIC); if (retval) { dev_err(&dev->interface->dev, "%s - usb_submit_urb failed: %d\n", -- cgit v1.2.3 From 591e060b72f4e6530ad74b4c66a99b56ebb3ccaf Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 9 Oct 2019 17:38:48 +0200 Subject: USB: yurex: fix NULL-derefs on disconnect commit aafb00a977cf7d81821f7c9d12e04c558c22dc3c upstream. The driver was using its struct usb_interface pointer as an inverted disconnected flag, but was setting it to NULL without making sure all code paths that used it were done with it. Before commit ef61eb43ada6 ("USB: yurex: Fix protection fault after device removal") this included the interrupt-in completion handler, but there are further accesses in dev_err and dev_dbg statements in yurex_write() and the driver-data destructor (sic!). Fix this by unconditionally stopping also the control URB at disconnect and by using a dedicated disconnected flag. Note that we need to take a reference to the struct usb_interface to avoid a use-after-free in the destructor whenever the device was disconnected while the character device was still open. Fixes: aadd6472d904 ("USB: yurex.c: remove dbg() usage") Fixes: 45714104b9e8 ("USB: yurex.c: remove err() usage") Cc: stable # 3.5: ef61eb43ada6 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191009153848.8664-6-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/yurex.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index 51f7e7f24ca4..44c6ced5d442 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -64,6 +64,7 @@ struct usb_yurex { struct kref kref; struct mutex io_mutex; + unsigned long disconnected:1; struct fasync_struct *async_queue; wait_queue_head_t waitq; @@ -111,6 +112,7 @@ static void yurex_delete(struct kref *kref) dev->int_buffer, dev->urb->transfer_dma); usb_free_urb(dev->urb); } + usb_put_intf(dev->interface); usb_put_dev(dev->udev); kfree(dev); } @@ -211,7 +213,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ init_waitqueue_head(&dev->waitq); dev->udev = usb_get_dev(interface_to_usbdev(interface)); - dev->interface = interface; + dev->interface = usb_get_intf(interface); /* set up the endpoint information */ iface_desc = interface->cur_altsetting; @@ -334,8 +336,9 @@ static void yurex_disconnect(struct usb_interface *interface) /* prevent more I/O from starting */ usb_poison_urb(dev->urb); + usb_poison_urb(dev->cntl_urb); mutex_lock(&dev->io_mutex); - dev->interface = NULL; + dev->disconnected = 1; mutex_unlock(&dev->io_mutex); /* wakeup waiters */ @@ -423,7 +426,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count, dev = file->private_data; mutex_lock(&dev->io_mutex); - if (!dev->interface) { /* already disconnected */ + if (dev->disconnected) { /* already disconnected */ mutex_unlock(&dev->io_mutex); return -ENODEV; } @@ -458,7 +461,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer, goto error; mutex_lock(&dev->io_mutex); - if (!dev->interface) { /* already disconnected */ + if (dev->disconnected) { /* already disconnected */ mutex_unlock(&dev->io_mutex); retval = -ENODEV; goto error; -- cgit v1.2.3 From d3488daeaa27da9511c7a73012c2a80f2c6f3988 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 1 Oct 2019 10:49:05 +0200 Subject: USB: usb-skeleton: fix runtime PM after driver unbind commit 5c290a5e42c3387e82de86965784d30e6c5270fd upstream. Since commit c2b71462d294 ("USB: core: Fix bug caused by duplicate interface PM usage counter") USB drivers must always balance their runtime PM gets and puts, including when the driver has already been unbound from the interface. Leaving the interface with a positive PM usage counter would prevent a later bound driver from suspending the device. Fixes: c2b71462d294 ("USB: core: Fix bug caused by duplicate interface PM usage counter") Cc: stable Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191001084908.2003-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usb-skeleton.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 545d09b8081d..fb7bd253faf2 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -75,6 +75,7 @@ static void skel_delete(struct kref *kref) struct usb_skel *dev = to_skel_dev(kref); usb_free_urb(dev->bulk_in_urb); + usb_put_intf(dev->interface); usb_put_dev(dev->udev); kfree(dev->bulk_in_buffer); kfree(dev); @@ -126,10 +127,7 @@ static int skel_release(struct inode *inode, struct file *file) return -ENODEV; /* allow the device to be autosuspended */ - mutex_lock(&dev->io_mutex); - if (dev->interface) - usb_autopm_put_interface(dev->interface); - mutex_unlock(&dev->io_mutex); + usb_autopm_put_interface(dev->interface); /* decrement the count on our device */ kref_put(&dev->kref, skel_delete); @@ -511,7 +509,7 @@ static int skel_probe(struct usb_interface *interface, init_waitqueue_head(&dev->bulk_in_wait); dev->udev = usb_get_dev(interface_to_usbdev(interface)); - dev->interface = interface; + dev->interface = usb_get_intf(interface); /* set up the endpoint information */ /* use only the first bulk-in and bulk-out endpoints */ -- cgit v1.2.3 From f88d1294ee785b031ae892d5a6b8b295bcb1c4eb Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 9 Oct 2019 19:09:42 +0200 Subject: USB: usb-skeleton: fix NULL-deref on disconnect commit bed5ef230943863b9abf5eae226a20fad9a8ff71 upstream. The driver was using its struct usb_interface pointer as an inverted disconnected flag and was setting it to NULL before making sure all completion handlers had run. This could lead to NULL-pointer dereferences in the dev_err() statements in the completion handlers which relies on said pointer. Fix this by using a dedicated disconnected flag. Note that this is also addresses a NULL-pointer dereference at release() and a struct usb_interface reference leak introduced by a recent runtime PM fix, which depends on and should have been submitted together with this patch. Fixes: 4212cd74ca6f ("USB: usb-skeleton.c: remove err() usage") Fixes: 5c290a5e42c3 ("USB: usb-skeleton: fix runtime PM after driver unbind") Cc: stable Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191009170944.30057-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usb-skeleton.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index fb7bd253faf2..871c366d9229 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -63,6 +63,7 @@ struct usb_skel { spinlock_t err_lock; /* lock for errors */ struct kref kref; struct mutex io_mutex; /* synchronize I/O with disconnect */ + unsigned long disconnected:1; wait_queue_head_t bulk_in_wait; /* to wait for an ongoing read */ }; #define to_skel_dev(d) container_of(d, struct usb_skel, kref) @@ -239,7 +240,7 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count, if (rv < 0) return rv; - if (!dev->interface) { /* disconnect() was called */ + if (dev->disconnected) { /* disconnect() was called */ rv = -ENODEV; goto exit; } @@ -420,7 +421,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, /* this lock makes sure we don't submit URBs to gone devices */ mutex_lock(&dev->io_mutex); - if (!dev->interface) { /* disconnect() was called */ + if (dev->disconnected) { /* disconnect() was called */ mutex_unlock(&dev->io_mutex); retval = -ENODEV; goto error; @@ -588,7 +589,7 @@ static void skel_disconnect(struct usb_interface *interface) /* prevent more I/O from starting */ mutex_lock(&dev->io_mutex); - dev->interface = NULL; + dev->disconnected = 1; mutex_unlock(&dev->io_mutex); usb_kill_anchored_urbs(&dev->submitted); -- cgit v1.2.3 From 8af575b89e497a6330b5f96ee878f7964ddac2da Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 4 Oct 2019 14:59:27 +0300 Subject: xhci: Prevent device initiated U1/U2 link pm if exit latency is too long commit cd9d9491e835a845c1a98b8471f88d26285e0bb9 upstream. If host/hub initiated link pm is prevented by a driver flag we still must ensure that periodic endpoints have longer service intervals than link pm exit latency before allowing device initiated link pm. Fix this by continue walking and checking endpoint service interval if xhci_get_timeout_no_hub_lpm() returns anything else than USB3_LPM_DISABLED While at it fix the split line error message Tested-by: Jan Schmidt Cc: Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/1570190373-30684-3-git-send-email-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index ed152b8ea645..6e45409bd6fe 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4645,10 +4645,12 @@ static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd, if (intf->dev.driver) { driver = to_usb_driver(intf->dev.driver); if (driver && driver->disable_hub_initiated_lpm) { - dev_dbg(&udev->dev, "Hub-initiated %s disabled " - "at request of driver %s\n", - state_name, driver->name); - return xhci_get_timeout_no_hub_lpm(udev, state); + dev_dbg(&udev->dev, "Hub-initiated %s disabled at request of driver %s\n", + state_name, driver->name); + timeout = xhci_get_timeout_no_hub_lpm(udev, + state); + if (timeout == USB3_LPM_DISABLED) + return timeout; } } -- cgit v1.2.3 From 0cd0bbdad9a4dff6d91d341cfe267afe4dae2f9c Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Fri, 4 Oct 2019 14:59:28 +0300 Subject: xhci: Check all endpoints for LPM timeout commit d500c63f80f2ea08ee300e57da5f2af1c13875f5 upstream. If an endpoint is encountered that returns USB3_LPM_DEVICE_INITIATED, keep checking further endpoints, as there might be periodic endpoints later that return USB3_LPM_DISABLED due to shorter service intervals. Without this, the code can set too high a maximum-exit-latency and prevent the use of multiple USB3 cameras that should be able to work. Cc: Signed-off-by: Jan Schmidt Tested-by: Philipp Zabel Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/1570190373-30684-4-git-send-email-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 6e45409bd6fe..3b2b34ab1a6e 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4529,12 +4529,12 @@ static int xhci_update_timeout_for_endpoint(struct xhci_hcd *xhci, alt_timeout = xhci_call_host_update_timeout_for_endpoint(xhci, udev, desc, state, timeout); - /* If we found we can't enable hub-initiated LPM, or + /* If we found we can't enable hub-initiated LPM, and * the U1 or U2 exit latency was too high to allow - * device-initiated LPM as well, just stop searching. + * device-initiated LPM as well, then we will disable LPM + * for this device, so stop searching any further. */ - if (alt_timeout == USB3_LPM_DISABLED || - alt_timeout == USB3_LPM_DEVICE_INITIATED) { + if (alt_timeout == USB3_LPM_DISABLED) { *timeout = alt_timeout; return -E2BIG; } -- cgit v1.2.3 From 384f906e724c7ced8c53143c4a5300b3b4c249d9 Mon Sep 17 00:00:00 2001 From: Rick Tseng Date: Fri, 4 Oct 2019 14:59:30 +0300 Subject: usb: xhci: wait for CNR controller not ready bit in xhci resume commit a70bcbc322837eda1ab5994d12db941dc9733a7d upstream. NVIDIA 3.1 xHCI card would lose power when moving power state into D3Cold. Thus we need to wait for CNR bit to clear in xhci resume, just as in xhci init. [Minor changes to comment and commit message -Mathias] Cc: Signed-off-by: Rick Tseng Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/1570190373-30684-6-git-send-email-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 3b2b34ab1a6e..f28ea3cadbd5 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1041,6 +1041,18 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) hibernated = true; if (!hibernated) { + /* + * Some controllers might lose power during suspend, so wait + * for controller not ready bit to clear, just as in xHC init. + */ + retval = xhci_handshake(&xhci->op_regs->status, + STS_CNR, 0, 10 * 1000 * 1000); + if (retval) { + xhci_warn(xhci, "Controller not ready at resume %d\n", + retval); + spin_unlock_irq(&xhci->lock); + return retval; + } /* step 1: restore register */ xhci_restore_registers(xhci); /* step 2: initialize command ring buffer */ -- cgit v1.2.3 From 557b03eb449184ce0e182c585e8838441bde2049 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Fri, 4 Oct 2019 14:59:32 +0300 Subject: xhci: Increase STS_SAVE timeout in xhci_suspend() commit ac343366846a445bb81f0a0e8f16abb8bd5d5d88 upstream. After commit f7fac17ca925 ("xhci: Convert xhci_handshake() to use readl_poll_timeout_atomic()"), ASMedia xHCI may fail to suspend. Although the algorithms are essentially the same, the old max timeout is (usec + usec * time of doing readl()), and the new max timeout is just usec, which is much less than the old one. Increase the timeout to make ASMedia xHCI able to suspend again. BugLink: https://bugs.launchpad.net/bugs/1844021 Fixes: f7fac17ca925 ("xhci: Convert xhci_handshake() to use readl_poll_timeout_atomic()") Cc: # v5.2+ Signed-off-by: Kai-Heng Feng Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/1570190373-30684-8-git-send-email-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f28ea3cadbd5..202c806b972a 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -981,7 +981,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) command |= CMD_CSS; writel(command, &xhci->op_regs->command); if (xhci_handshake(&xhci->op_regs->status, - STS_SAVE, 0, 10 * 1000)) { + STS_SAVE, 0, 20 * 1000)) { xhci_warn(xhci, "WARN: xHC save state timeout\n"); spin_unlock_irq(&xhci->lock); return -ETIMEDOUT; -- cgit v1.2.3 From d5b8fadb2a057abb735863aa9a5403c6c28ed042 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 7 Nov 2017 11:45:27 +0000 Subject: USB: adutux: remove redundant variable minor commit 8444efc4a052332d643ed5c8aebcca148c7de032 upstream. Variable minor is being assigned but never read, hence it is redundant and can be removed. Cleans up clang warning: drivers/usb/misc/adutux.c:770:2: warning: Value stored to 'minor' is never read Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/adutux.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 3071c0ef909b..f499cab7e89c 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -800,13 +800,11 @@ error: static void adu_disconnect(struct usb_interface *interface) { struct adu_device *dev; - int minor; dev = usb_get_intfdata(interface); mutex_lock(&dev->mtx); /* not interruptible */ dev->udev = NULL; /* poison */ - minor = dev->minor; usb_deregister_dev(interface, &adu_class); mutex_unlock(&dev->mtx); -- cgit v1.2.3 From cd3cfbafe8eb9761950873c04c0147b40a85d29f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 25 Sep 2019 11:29:12 +0200 Subject: USB: adutux: fix use-after-free on disconnect commit 44efc269db7929f6275a1fa927ef082e533ecde0 upstream. The driver was clearing its struct usb_device pointer, which it used as an inverted disconnected flag, before deregistering the character device and without serialising against racing release(). This could lead to a use-after-free if a racing release() callback observes the cleared pointer and frees the driver data before disconnect() is finished with it. This could also lead to NULL-pointer dereferences in a racing open(). Fixes: f08812d5eb8f ("USB: FIx locks and urb->status in adutux (updated)") Cc: stable # 2.6.24 Reported-by: syzbot+0243cb250a51eeefb8cc@syzkaller.appspotmail.com Tested-by: syzbot+0243cb250a51eeefb8cc@syzkaller.appspotmail.com Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20190925092913.8608-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/adutux.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index f499cab7e89c..c88ccd03c76c 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -803,14 +803,15 @@ static void adu_disconnect(struct usb_interface *interface) dev = usb_get_intfdata(interface); - mutex_lock(&dev->mtx); /* not interruptible */ - dev->udev = NULL; /* poison */ usb_deregister_dev(interface, &adu_class); - mutex_unlock(&dev->mtx); mutex_lock(&adutux_mutex); usb_set_intfdata(interface, NULL); + mutex_lock(&dev->mtx); /* not interruptible */ + dev->udev = NULL; /* poison */ + mutex_unlock(&dev->mtx); + /* if the device is not opened, then we clean up right now */ if (!dev->open_count) adu_delete(dev); -- cgit v1.2.3 From ffb59e0701a9db59e1c9247c2748cc388b499c2e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 25 Sep 2019 11:29:13 +0200 Subject: USB: adutux: fix NULL-derefs on disconnect commit b2fa7baee744fde746c17bc1860b9c6f5c2eebb7 upstream. The driver was using its struct usb_device pointer as an inverted disconnected flag, but was setting it to NULL before making sure all completion handlers had run. This could lead to a NULL-pointer dereference in a number of dev_dbg statements in the completion handlers which relies on said pointer. The pointer was also dereferenced unconditionally in a dev_dbg statement release() something which would lead to a NULL-deref whenever a device was disconnected before the final character-device close if debugging was enabled. Fix this by unconditionally stopping all I/O and preventing resubmissions by poisoning the interrupt URBs at disconnect and using a dedicated disconnected flag. This also makes sure that all I/O has completed by the time the disconnect callback returns. Fixes: 1ef37c6047fe ("USB: adutux: remove custom debug macro and module parameter") Fixes: 66d4bc30d128 ("USB: adutux: remove custom debug macro") Cc: stable # 3.12 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20190925092913.8608-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/adutux.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index c88ccd03c76c..aa0d85f07cfe 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -80,6 +80,7 @@ struct adu_device { char serial_number[8]; int open_count; /* number of times this port has been opened */ + unsigned long disconnected:1; char *read_buffer_primary; int read_buffer_length; @@ -121,7 +122,7 @@ static void adu_abort_transfers(struct adu_device *dev) { unsigned long flags; - if (dev->udev == NULL) + if (dev->disconnected) return; /* shutdown transfer */ @@ -244,7 +245,7 @@ static int adu_open(struct inode *inode, struct file *file) } dev = usb_get_intfdata(interface); - if (!dev || !dev->udev) { + if (!dev) { retval = -ENODEV; goto exit_no_device; } @@ -327,7 +328,7 @@ static int adu_release(struct inode *inode, struct file *file) } adu_release_internal(dev); - if (dev->udev == NULL) { + if (dev->disconnected) { /* the device was unplugged before the file was released */ if (!dev->open_count) /* ... and we're the last user */ adu_delete(dev); @@ -356,7 +357,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, return -ERESTARTSYS; /* verify that the device wasn't unplugged */ - if (dev->udev == NULL) { + if (dev->disconnected) { retval = -ENODEV; pr_err("No device or device unplugged %d\n", retval); goto exit; @@ -525,7 +526,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, goto exit_nolock; /* verify that the device wasn't unplugged */ - if (dev->udev == NULL) { + if (dev->disconnected) { retval = -ENODEV; pr_err("No device or device unplugged %d\n", retval); goto exit; @@ -805,11 +806,14 @@ static void adu_disconnect(struct usb_interface *interface) usb_deregister_dev(interface, &adu_class); + usb_poison_urb(dev->interrupt_in_urb); + usb_poison_urb(dev->interrupt_out_urb); + mutex_lock(&adutux_mutex); usb_set_intfdata(interface, NULL); mutex_lock(&dev->mtx); /* not interruptible */ - dev->udev = NULL; /* poison */ + dev->disconnected = 1; mutex_unlock(&dev->mtx); /* if the device is not opened, then we clean up right now */ -- cgit v1.2.3 From f14fed62a96bb5ba53ddb51b42989d3e1e0451fa Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 9 Oct 2019 17:38:44 +0200 Subject: USB: adutux: fix use-after-free on release commit 123a0f125fa3d2104043697baa62899d9e549272 upstream. The driver was accessing its struct usb_device in its release() callback without holding a reference. This would lead to a use-after-free whenever the device was disconnected while the character device was still open. Fixes: 66d4bc30d128 ("USB: adutux: remove custom debug macro") Cc: stable # 3.12 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191009153848.8664-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/adutux.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index aa0d85f07cfe..6d849e7dc842 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -152,6 +152,7 @@ static void adu_delete(struct adu_device *dev) kfree(dev->read_buffer_secondary); kfree(dev->interrupt_in_buffer); kfree(dev->interrupt_out_buffer); + usb_put_dev(dev->udev); kfree(dev); } @@ -681,7 +682,7 @@ static int adu_probe(struct usb_interface *interface, mutex_init(&dev->mtx); spin_lock_init(&dev->buflock); - dev->udev = udev; + dev->udev = usb_get_dev(udev); init_waitqueue_head(&dev->read_wait); init_waitqueue_head(&dev->write_wait); -- cgit v1.2.3 From f723d7ea08e2c69ac9ecd87828c650745270fb98 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 9 Oct 2019 12:48:41 +0200 Subject: USB: iowarrior: fix use-after-free on disconnect commit edc4746f253d907d048de680a621e121517f484b upstream. A recent fix addressing a deadlock on disconnect introduced a new bug by moving the present flag out of the critical section protected by the driver-data mutex. This could lead to a racing release() freeing the driver data before disconnect() is done with it. Due to insufficient locking a related use-after-free could be triggered also before the above mentioned commit. Specifically, the driver needs to hold the driver-data mutex also while checking the opened flag at disconnect(). Fixes: c468a8aa790e ("usb: iowarrior: fix deadlock on disconnect") Fixes: 946b960d13c1 ("USB: add driver for iowarrior devices.") Cc: stable # 2.6.21 Reported-by: syzbot+0761012cebf7bdb38137@syzkaller.appspotmail.com Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191009104846.5925-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/iowarrior.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 836fb65c3c72..4af9279f2cf0 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -898,8 +898,6 @@ static void iowarrior_disconnect(struct usb_interface *interface) dev = usb_get_intfdata(interface); mutex_lock(&iowarrior_open_disc_lock); usb_set_intfdata(interface, NULL); - /* prevent device read, write and ioctl */ - dev->present = 0; minor = dev->minor; mutex_unlock(&iowarrior_open_disc_lock); @@ -910,8 +908,7 @@ static void iowarrior_disconnect(struct usb_interface *interface) mutex_lock(&dev->mutex); /* prevent device read, write and ioctl */ - - mutex_unlock(&dev->mutex); + dev->present = 0; if (dev->opened) { /* There is a process that holds a filedescriptor to the device , @@ -921,8 +918,10 @@ static void iowarrior_disconnect(struct usb_interface *interface) usb_kill_urb(dev->int_in_urb); wake_up_interruptible(&dev->read_wait); wake_up_interruptible(&dev->write_wait); + mutex_unlock(&dev->mutex); } else { /* no process is using the device, cleanup now */ + mutex_unlock(&dev->mutex); iowarrior_delete(dev); } -- cgit v1.2.3 From ded3c707e373f58ad5c9a7a85459387ec5e19009 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 9 Oct 2019 12:48:42 +0200 Subject: USB: iowarrior: fix use-after-free on release commit 80cd5479b525093a56ef768553045741af61b250 upstream. The driver was accessing its struct usb_interface from its release() callback without holding a reference. This would lead to a use-after-free whenever debugging was enabled and the device was disconnected while its character device was open. Fixes: 549e83500b80 ("USB: iowarrior: Convert local dbg macro to dev_dbg") Cc: stable # 3.16 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191009104846.5925-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/iowarrior.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 4af9279f2cf0..22df8c337369 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -248,6 +248,7 @@ static inline void iowarrior_delete(struct iowarrior *dev) kfree(dev->int_in_buffer); usb_free_urb(dev->int_in_urb); kfree(dev->read_queue); + usb_put_intf(dev->interface); kfree(dev); } @@ -782,7 +783,7 @@ static int iowarrior_probe(struct usb_interface *interface, init_waitqueue_head(&dev->write_wait); dev->udev = udev; - dev->interface = interface; + dev->interface = usb_get_intf(interface); iface_desc = interface->cur_altsetting; dev->product_id = le16_to_cpu(udev->descriptor.idProduct); -- cgit v1.2.3 From ac7266d990f76db73d0dfb01b43b37ac68ac1950 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 9 Oct 2019 12:48:43 +0200 Subject: USB: iowarrior: fix use-after-free after driver unbind commit b5f8d46867ca233d773408ffbe691a8062ed718f upstream. Make sure to stop also the asynchronous write URBs on disconnect() to avoid use-after-free in the completion handler after driver unbind. Fixes: 946b960d13c1 ("USB: add driver for iowarrior devices.") Cc: stable # 2.6.21: 51a2f077c44e ("USB: introduce usb_anchor") Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191009104846.5925-4-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/iowarrior.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 22df8c337369..83342e579233 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -89,6 +89,7 @@ struct iowarrior { char chip_serial[9]; /* the serial number string of the chip connected */ int report_size; /* number of bytes in a report */ u16 product_id; + struct usb_anchor submitted; }; /*--------------*/ @@ -437,11 +438,13 @@ static ssize_t iowarrior_write(struct file *file, retval = -EFAULT; goto error; } + usb_anchor_urb(int_out_urb, &dev->submitted); retval = usb_submit_urb(int_out_urb, GFP_KERNEL); if (retval) { dev_dbg(&dev->interface->dev, "submit error %d for urb nr.%d\n", retval, atomic_read(&dev->write_busy)); + usb_unanchor_urb(int_out_urb); goto error; } /* submit was ok */ @@ -788,6 +791,8 @@ static int iowarrior_probe(struct usb_interface *interface, iface_desc = interface->cur_altsetting; dev->product_id = le16_to_cpu(udev->descriptor.idProduct); + init_usb_anchor(&dev->submitted); + /* set up the endpoint information */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; @@ -917,6 +922,7 @@ static void iowarrior_disconnect(struct usb_interface *interface) Deleting the device is postponed until close() was called. */ usb_kill_urb(dev->int_in_urb); + usb_kill_anchored_urbs(&dev->submitted); wake_up_interruptible(&dev->read_wait); wake_up_interruptible(&dev->write_wait); mutex_unlock(&dev->mutex); -- cgit v1.2.3 From 8f75201338782777452e8c3599854601b734a792 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 1 Oct 2019 10:49:06 +0200 Subject: USB: usblp: fix runtime PM after driver unbind commit 9a31535859bfd8d1c3ed391f5e9247cd87bb7909 upstream. Since commit c2b71462d294 ("USB: core: Fix bug caused by duplicate interface PM usage counter") USB drivers must always balance their runtime PM gets and puts, including when the driver has already been unbound from the interface. Leaving the interface with a positive PM usage counter would prevent a later bound driver from suspending the device. Fixes: c2b71462d294 ("USB: core: Fix bug caused by duplicate interface PM usage counter") Cc: stable Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191001084908.2003-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 071964c7847f..0669fbb0ec25 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -474,10 +474,12 @@ static int usblp_release(struct inode *inode, struct file *file) mutex_lock(&usblp_mutex); usblp->used = 0; - if (usblp->present) { + if (usblp->present) usblp_unlink_urbs(usblp); - usb_autopm_put_interface(usblp->intf); - } else /* finish cleanup from disconnect */ + + usb_autopm_put_interface(usblp->intf); + + if (!usblp->present) /* finish cleanup from disconnect */ usblp_cleanup(usblp); mutex_unlock(&usblp_mutex); return 0; -- cgit v1.2.3 From ebfb3be3b0af07cd195875565b6b34542d69c431 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 9 Oct 2019 17:38:45 +0200 Subject: USB: chaoskey: fix use-after-free on release commit 93ddb1f56ae102f14f9e46a9a9c8017faa970003 upstream. The driver was accessing its struct usb_interface in its release() callback without holding a reference. This would lead to a use-after-free whenever the device was disconnected while the character device was still open. Fixes: 66e3e591891d ("usb: Add driver for Altus Metrum ChaosKey device (v2)") Cc: stable # 4.1 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191009153848.8664-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/chaoskey.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c index 23c794813e6a..a3692811248b 100644 --- a/drivers/usb/misc/chaoskey.c +++ b/drivers/usb/misc/chaoskey.c @@ -96,6 +96,7 @@ static void chaoskey_free(struct chaoskey *dev) usb_dbg(dev->interface, "free"); kfree(dev->name); kfree(dev->buf); + usb_put_intf(dev->interface); kfree(dev); } @@ -144,6 +145,8 @@ static int chaoskey_probe(struct usb_interface *interface, if (dev == NULL) return -ENOMEM; + dev->interface = usb_get_intf(interface); + dev->buf = kmalloc(size, GFP_KERNEL); if (dev->buf == NULL) { @@ -169,8 +172,6 @@ static int chaoskey_probe(struct usb_interface *interface, strcat(dev->name, udev->serial); } - dev->interface = interface; - dev->in_ep = in_ep; dev->size = size; -- cgit v1.2.3 From 107ef3bb5e7460bc030aef2753b7d561de5dfc35 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 9 Oct 2019 17:38:46 +0200 Subject: USB: ldusb: fix NULL-derefs on driver unbind commit 58ecf131e74620305175a7aa103f81350bb37570 upstream. The driver was using its struct usb_interface pointer as an inverted disconnected flag, but was setting it to NULL before making sure all completion handlers had run. This could lead to a NULL-pointer dereference in a number of dev_dbg, dev_warn and dev_err statements in the completion handlers which relies on said pointer. Fix this by unconditionally stopping all I/O and preventing resubmissions by poisoning the interrupt URBs at disconnect and using a dedicated disconnected flag. This also makes sure that all I/O has completed by the time the disconnect callback returns. Fixes: 2824bd250f0b ("[PATCH] USB: add ldusb driver") Cc: stable # 2.6.13 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191009153848.8664-4-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ldusb.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index e9113238d9e3..84f12c1bf9e6 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -158,6 +158,7 @@ MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in struct ld_usb { struct mutex mutex; /* locks this structure */ struct usb_interface* intf; /* save off the usb interface pointer */ + unsigned long disconnected:1; int open_count; /* number of times this port has been opened */ @@ -197,12 +198,10 @@ static void ld_usb_abort_transfers(struct ld_usb *dev) /* shutdown transfer */ if (dev->interrupt_in_running) { dev->interrupt_in_running = 0; - if (dev->intf) - usb_kill_urb(dev->interrupt_in_urb); + usb_kill_urb(dev->interrupt_in_urb); } if (dev->interrupt_out_busy) - if (dev->intf) - usb_kill_urb(dev->interrupt_out_urb); + usb_kill_urb(dev->interrupt_out_urb); } /** @@ -210,8 +209,6 @@ static void ld_usb_abort_transfers(struct ld_usb *dev) */ static void ld_usb_delete(struct ld_usb *dev) { - ld_usb_abort_transfers(dev); - /* free data structures */ usb_free_urb(dev->interrupt_in_urb); usb_free_urb(dev->interrupt_out_urb); @@ -267,7 +264,7 @@ static void ld_usb_interrupt_in_callback(struct urb *urb) resubmit: /* resubmit if we're still running */ - if (dev->interrupt_in_running && !dev->buffer_overflow && dev->intf) { + if (dev->interrupt_in_running && !dev->buffer_overflow) { retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); if (retval) { dev_err(&dev->intf->dev, @@ -396,7 +393,7 @@ static int ld_usb_release(struct inode *inode, struct file *file) retval = -ENODEV; goto unlock_exit; } - if (dev->intf == NULL) { + if (dev->disconnected) { /* the device was unplugged before the file was released */ mutex_unlock(&dev->mutex); /* unlock here as ld_usb_delete frees dev */ @@ -427,7 +424,7 @@ static unsigned int ld_usb_poll(struct file *file, poll_table *wait) dev = file->private_data; - if (!dev->intf) + if (dev->disconnected) return POLLERR | POLLHUP; poll_wait(file, &dev->read_wait, wait); @@ -466,7 +463,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, } /* verify that the device wasn't unplugged */ - if (dev->intf == NULL) { + if (dev->disconnected) { retval = -ENODEV; printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval); goto unlock_exit; @@ -546,7 +543,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, } /* verify that the device wasn't unplugged */ - if (dev->intf == NULL) { + if (dev->disconnected) { retval = -ENODEV; printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval); goto unlock_exit; @@ -782,6 +779,9 @@ static void ld_usb_disconnect(struct usb_interface *intf) /* give back our minor */ usb_deregister_dev(intf, &ld_usb_class); + usb_poison_urb(dev->interrupt_in_urb); + usb_poison_urb(dev->interrupt_out_urb); + mutex_lock(&dev->mutex); /* if the device is not opened, then we clean up right now */ @@ -789,7 +789,7 @@ static void ld_usb_disconnect(struct usb_interface *intf) mutex_unlock(&dev->mutex); ld_usb_delete(dev); } else { - dev->intf = NULL; + dev->disconnected = 1; /* wake up pollers */ wake_up_interruptible_all(&dev->read_wait); wake_up_interruptible_all(&dev->write_wait); -- cgit v1.2.3 From 858841b7cb12fa2daa32e8726bb5b6037cd26cc5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 16 Sep 2019 16:12:23 -0700 Subject: serial: uartlite: fix exit path null pointer commit a553add0846f355a28ed4e81134012e4a1e280c2 upstream. Call uart_unregister_driver() conditionally instead of unconditionally, only if it has been previously registered. This uses driver.state, just as the sh-sci.c driver does. Fixes this null pointer dereference in tty_unregister_driver(), since the 'driver' argument is null: general protection fault: 0000 [#1] PREEMPT SMP KASAN PTI RIP: 0010:tty_unregister_driver+0x25/0x1d0 Fixes: 238b8721a554 ("[PATCH] serial uartlite driver") Signed-off-by: Randy Dunlap Cc: stable Cc: Peter Korsgaard Link: https://lore.kernel.org/r/9c8e6581-6fcc-a595-0897-4d90f5d710df@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/uartlite.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index b1c6bd3d483f..c27db21b71ba 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -701,7 +701,8 @@ err_uart: static void __exit ulite_exit(void) { platform_driver_unregister(&ulite_platform_driver); - uart_unregister_driver(&ulite_uart_driver); + if (ulite_uart_driver.state) + uart_unregister_driver(&ulite_uart_driver); } module_init(ulite_init); -- cgit v1.2.3 From 883457a6af8d7469c3fe0f6a3d5fcd02bb5e6d58 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 3 Oct 2019 15:49:58 +0200 Subject: USB: serial: keyspan: fix NULL-derefs on open() and write() commit 7d7e21fafdbc7fcf0854b877bd0975b487ed2717 upstream. Fix NULL-pointer dereferences on open() and write() which can be triggered by a malicious USB device. The current URB allocation helper would fail to initialise the newly allocated URB if the device has unexpected endpoint descriptors, something which could lead NULL-pointer dereferences in a number of open() and write() paths when accessing the URB. For example: BUG: kernel NULL pointer dereference, address: 0000000000000000 ... RIP: 0010:usb_clear_halt+0x11/0xc0 ... Call Trace: ? tty_port_open+0x4d/0xd0 keyspan_open+0x70/0x160 [keyspan] serial_port_activate+0x5b/0x80 [usbserial] tty_port_open+0x7b/0xd0 ? check_tty_count+0x43/0xa0 tty_open+0xf1/0x490 BUG: kernel NULL pointer dereference, address: 0000000000000000 ... RIP: 0010:keyspan_write+0x14e/0x1f3 [keyspan] ... Call Trace: serial_write+0x43/0xa0 [usbserial] n_tty_write+0x1af/0x4f0 ? do_wait_intr_irq+0x80/0x80 ? process_echoes+0x60/0x60 tty_write+0x13f/0x2f0 BUG: kernel NULL pointer dereference, address: 0000000000000000 ... RIP: 0010:keyspan_usa26_send_setup+0x298/0x305 [keyspan] ... Call Trace: keyspan_open+0x10f/0x160 [keyspan] serial_port_activate+0x5b/0x80 [usbserial] tty_port_open+0x7b/0xd0 ? check_tty_count+0x43/0xa0 tty_open+0xf1/0x490 Fixes: fdcba53e2d58 ("fix for bugzilla #7544 (keyspan USB-to-serial converter)") Cc: stable # 2.6.21 Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/keyspan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 7faa901ee47f..38112be0dbae 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -1249,8 +1249,8 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint, ep_desc = find_ep(serial, endpoint); if (!ep_desc) { - /* leak the urb, something's wrong and the callers don't care */ - return urb; + usb_free_urb(urb); + return NULL; } if (usb_endpoint_xfer_int(ep_desc)) { ep_type_name = "INT"; -- cgit v1.2.3 From 35526e63dcaeb40277ba561ebe347ec00dfcbca8 Mon Sep 17 00:00:00 2001 From: Beni Mahler Date: Thu, 5 Sep 2019 00:26:20 +0200 Subject: USB: serial: ftdi_sio: add device IDs for Sienna and Echelon PL-20 commit 357f16d9e0194cdbc36531ff88b453481560b76a upstream. Both devices added here have a FTDI chip inside. The device from Echelon is called 'Network Interface' it is actually a LON network gateway. ID 0403:8348 Future Technology Devices International, Ltd https://www.eltako.com/fileadmin/downloads/de/datenblatt/Datenblatt_PL-SW-PROF.pdf ID 0920:7500 Network Interface https://www.echelon.com/products/u20-usb-network-interface Signed-off-by: Beni Mahler Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 3 +++ drivers/usb/serial/ftdi_sio_ids.h | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 7edcd5a8d175..2998da6bd901 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1025,6 +1025,9 @@ static const struct usb_device_id id_table_combined[] = { /* EZPrototypes devices */ { USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) }, { USB_DEVICE_INTERFACE_NUMBER(UNJO_VID, UNJO_ISODEBUG_V1_PID, 1) }, + /* Sienna devices */ + { USB_DEVICE(FTDI_VID, FTDI_SIENNA_PID) }, + { USB_DEVICE(ECHELON_VID, ECHELON_U20_PID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index ed6b36674c15..2e8161f79b49 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -38,6 +38,9 @@ #define FTDI_LUMEL_PD12_PID 0x6002 +/* Sienna Serial Interface by Secyourit GmbH */ +#define FTDI_SIENNA_PID 0x8348 + /* Cyber Cortex AV by Fabulous Silicon (http://fabuloussilicon.com) */ #define CYBER_CORTEX_AV_PID 0x8698 @@ -687,6 +690,12 @@ #define BANDB_TTL3USB9M_PID 0xAC50 #define BANDB_ZZ_PROG1_USB_PID 0xBA02 +/* + * Echelon USB Serial Interface + */ +#define ECHELON_VID 0x0920 +#define ECHELON_U20_PID 0x7500 + /* * Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI */ -- cgit v1.2.3 From 2b08f6ffd9d8d37e285e1ac7f6419bc1f3e0152d Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Mon, 23 Sep 2019 12:23:28 +0200 Subject: USB: serial: option: add Telit FN980 compositions commit 5eb3f4b87a0e7e949c976f32f296176a06d1a93b upstream. This patch adds the following Telit FN980 compositions: 0x1050: tty, adb, rmnet, tty, tty, tty, tty 0x1051: tty, adb, mbim, tty, tty, tty, tty 0x1052: rndis, tty, adb, tty, tty, tty, tty 0x1053: tty, adb, ecm, tty, tty, tty, tty Signed-off-by: Daniele Palmas Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 1bceb11f3782..9d9f61da50f8 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1149,6 +1149,14 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff), .driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1050, 0xff), /* Telit FN980 (rmnet) */ + .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1051, 0xff), /* Telit FN980 (MBIM) */ + .driver_info = NCTRL(0) | RSVD(1) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1052, 0xff), /* Telit FN980 (RNDIS) */ + .driver_info = NCTRL(2) | RSVD(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1053, 0xff), /* Telit FN980 (ECM) */ + .driver_info = NCTRL(0) | RSVD(1) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910), .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), -- cgit v1.2.3 From 22727bde284b788d12ea592e386c10d8be50c8e5 Mon Sep 17 00:00:00 2001 From: Reinhard Speyerer Date: Thu, 3 Oct 2019 18:53:21 +0200 Subject: USB: serial: option: add support for Cinterion CLS8 devices commit dfbac2f4da6a0c4a8f6b4d715a4077a7b8df53ad upstream. Add support for the serial ports of Cinterion CLS8 devices. T: Bus=01 Lev=03 Prnt=05 Port=01 Cnt=02 Dev#= 25 Spd=480 MxCh= 0 D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1e2d ProdID=00b0 Rev= 3.18 S: Manufacturer=GEMALTO S: Product=USB Modem C:* #Ifs= 5 Cfg#= 1 Atr=80 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=83(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=85(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=00 Prot=00 Driver=option E: Ad=87(I) Atr=03(Int.) MxPS= 10 Ivl=32ms E: Ad=86(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan E: Ad=89(I) Atr=03(Int.) MxPS= 8 Ivl=32ms E: Ad=88(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms Signed-off-by: Reinhard Speyerer Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 9d9f61da50f8..00a6e62a68a8 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -421,6 +421,7 @@ static void option_instat_callback(struct urb *urb); #define CINTERION_PRODUCT_PH8_AUDIO 0x0083 #define CINTERION_PRODUCT_AHXX_2RMNET 0x0084 #define CINTERION_PRODUCT_AHXX_AUDIO 0x0085 +#define CINTERION_PRODUCT_CLS8 0x00b0 /* Olivetti products */ #define OLIVETTI_VENDOR_ID 0x0b3c @@ -1850,6 +1851,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_2RMNET, 0xff) }, { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_AUDIO, 0xff) }, + { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_CLS8, 0xff), + .driver_info = RSVD(0) | RSVD(4) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) }, -- cgit v1.2.3 From 3ec2dabc9e44b11cb04ec586f405bbce9b4e36fc Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 1 Oct 2019 10:49:07 +0200 Subject: USB: serial: fix runtime PM after driver unbind commit d51bdb93ca7e71d7fb30a572c7b47ed0194bf3fe upstream. Since commit c2b71462d294 ("USB: core: Fix bug caused by duplicate interface PM usage counter") USB drivers must always balance their runtime PM gets and puts, including when the driver has already been unbound from the interface. Leaving the interface with a positive PM usage counter would prevent a later bound driver from suspending the device. Fixes: c2b71462d294 ("USB: core: Fix bug caused by duplicate interface PM usage counter") Cc: stable Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191001084908.2003-4-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index e7e29c797824..80ba818d3a21 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -314,10 +314,7 @@ static void serial_cleanup(struct tty_struct *tty) serial = port->serial; owner = serial->type->driver.owner; - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) - usb_autopm_put_interface(serial->interface); - mutex_unlock(&serial->disc_mutex); + usb_autopm_put_interface(serial->interface); usb_serial_put(serial); module_put(owner); -- cgit v1.2.3 From 78b2e65cb55f369fccbdc8a42083a4b239005b78 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 26 Sep 2019 11:12:25 +0200 Subject: USB: usblcd: fix I/O after disconnect commit eb7f5a490c5edfe8126f64bc58b9ba2edef0a425 upstream. Make sure to stop all I/O on disconnect by adding a disconnected flag which is used to prevent new I/O from being started and by stopping all ongoing I/O before returning. This also fixes a potential use-after-free on driver unbind in case the driver data is freed before the completion handler has run. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable # 7bbe990c989e Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20190926091228.24634-7-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usblcd.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index 1184390508e9..c77974fab29d 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,8 @@ struct usb_lcd { using up all RAM */ struct usb_anchor submitted; /* URBs to wait for before suspend */ + struct rw_semaphore io_rwsem; + unsigned long disconnected:1; }; #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref) @@ -141,6 +144,13 @@ static ssize_t lcd_read(struct file *file, char __user * buffer, dev = file->private_data; + down_read(&dev->io_rwsem); + + if (dev->disconnected) { + retval = -ENODEV; + goto out_up_io; + } + /* do a blocking bulk read to get data from the device */ retval = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, @@ -157,6 +167,9 @@ static ssize_t lcd_read(struct file *file, char __user * buffer, retval = bytes_read; } +out_up_io: + up_read(&dev->io_rwsem); + return retval; } @@ -236,11 +249,18 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, if (r < 0) return -EINTR; + down_read(&dev->io_rwsem); + + if (dev->disconnected) { + retval = -ENODEV; + goto err_up_io; + } + /* create a urb, and a buffer for it, and copy the data to the urb */ urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { retval = -ENOMEM; - goto err_no_buf; + goto err_up_io; } buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL, @@ -277,6 +297,7 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, the USB core will eventually free it entirely */ usb_free_urb(urb); + up_read(&dev->io_rwsem); exit: return count; error_unanchor: @@ -284,7 +305,8 @@ error_unanchor: error: usb_free_coherent(dev->udev, count, buf, urb->transfer_dma); usb_free_urb(urb); -err_no_buf: +err_up_io: + up_read(&dev->io_rwsem); up(&dev->limit_sem); return retval; } @@ -327,6 +349,7 @@ static int lcd_probe(struct usb_interface *interface, } kref_init(&dev->kref); sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES); + init_rwsem(&dev->io_rwsem); init_usb_anchor(&dev->submitted); dev->udev = usb_get_dev(interface_to_usbdev(interface)); @@ -437,6 +460,12 @@ static void lcd_disconnect(struct usb_interface *interface) /* give back our minor */ usb_deregister_dev(interface, &lcd_class); + down_write(&dev->io_rwsem); + dev->disconnected = 1; + up_write(&dev->io_rwsem); + + usb_kill_anchored_urbs(&dev->submitted); + /* decrement our usage count */ kref_put(&dev->kref, lcd_delete); -- cgit v1.2.3 From c841eeea749754ea516130b42d2c9a4d05730eb2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 3 Oct 2019 09:09:31 +0200 Subject: USB: microtek: fix info-leak at probe commit 177238c3d47d54b2ed8f0da7a4290db492f4a057 upstream. Add missing bulk-in endpoint sanity check to prevent uninitialised stack data from being reported to the system log and used as endpoint addresses. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable Reported-by: syzbot+5630ca7c3b2be5c9da5e@syzkaller.appspotmail.com Signed-off-by: Johan Hovold Acked-by: Oliver Neukum Link: https://lore.kernel.org/r/20191003070931.17009-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/image/microtek.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index a4dbb0cd80da..0fecc002fa9f 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -724,6 +724,10 @@ static int mts_usb_probe(struct usb_interface *intf, } + if (ep_in_current != &ep_in_set[2]) { + MTS_WARNING("couldn't find two input bulk endpoints. Bailing out.\n"); + return -ENODEV; + } if ( ep_out == -1 ) { MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" ); -- cgit v1.2.3 From 0d86daeb00168cf574117e9dddab23c96ca6ab2c Mon Sep 17 00:00:00 2001 From: "Jacky.Cao@sony.com" Date: Thu, 5 Sep 2019 04:11:57 +0000 Subject: USB: dummy-hcd: fix power budget for SuperSpeed mode commit 2636d49b64671d3d90ecc4daf971b58df3956519 upstream. The power budget for SuperSpeed mode should be 900 mA according to USB specification, so set the power budget to 900mA for dummy_start_ss which is only used for SuperSpeed mode. If the max power consumption of SuperSpeed device is larger than 500 mA, insufficient available bus power error happens in usb_choose_configuration function when the device connects to dummy hcd. Signed-off-by: Jacky Cao Acked-by: Alan Stern Cc: stable Link: https://lore.kernel.org/r/16EA1F625E922C43B00B9D82250220500871CDE5@APYOKXMS108.ap.sony.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/dummy_hcd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 85f1f282c1d5..0321b9ce9faf 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -50,6 +50,7 @@ #define DRIVER_VERSION "02 May 2005" #define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */ +#define POWER_BUDGET_3 900 /* in mA */ static const char driver_name[] = "dummy_hcd"; static const char driver_desc[] = "USB Host+Gadget Emulator"; @@ -2435,7 +2436,7 @@ static int dummy_start_ss(struct dummy_hcd *dum_hcd) dum_hcd->rh_state = DUMMY_RH_RUNNING; dum_hcd->stream_en_ep = 0; INIT_LIST_HEAD(&dum_hcd->urbp_list); - dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET; + dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET_3; dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING; dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1; #ifdef CONFIG_USB_OTG -- cgit v1.2.3 From 6207b7b8f096c9c94e52181338cf45496da69756 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 1 Oct 2019 19:10:32 +0900 Subject: usb: renesas_usbhs: gadget: Do not discard queues in usb_ep_set_{halt,wedge}() commit 1aae1394294cb71c6aa0bc904a94a7f2f1e75936 upstream. The commit 97664a207bc2 ("usb: renesas_usbhs: shrink spin lock area") had added a usbhsg_pipe_disable() calling into __usbhsg_ep_set_halt_wedge() accidentally. But, this driver should not call the usbhsg_pipe_disable() because the function discards all queues. So, this patch removes it. Fixes: 97664a207bc2 ("usb: renesas_usbhs: shrink spin lock area") Cc: # v3.1+ Signed-off-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/1569924633-322-2-git-send-email-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/mod_gadget.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index c5553028e616..9e86ea6cd18c 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -732,8 +732,6 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge) struct device *dev = usbhsg_gpriv_to_dev(gpriv); unsigned long flags; - usbhsg_pipe_disable(uep); - dev_dbg(dev, "set halt %d (pipe %d)\n", halt, usbhs_pipe_number(pipe)); -- cgit v1.2.3 From d6952c7b39b2609dff01b55d6ccda96d4ac5dd78 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Tue, 1 Oct 2019 19:10:33 +0900 Subject: usb: renesas_usbhs: gadget: Fix usb_ep_set_{halt,wedge}() behavior commit 4d599cd3a097a85a5c68a2c82b9a48cddf9953ec upstream. According to usb_ep_set_halt()'s description, __usbhsg_ep_set_halt_wedge() should return -EAGAIN if the IN endpoint has any queue or data. Otherwise, this driver is possible to cause just STALL without sending a short packet data on g_mass_storage driver, and then a few resetting a device happens on a host side during a usb enumaration. Fixes: 2f98382dcdfe ("usb: renesas_usbhs: Add Renesas USBHS Gadget") Cc: # v3.0+ Signed-off-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/1569924633-322-3-git-send-email-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/common.h | 1 + drivers/usb/renesas_usbhs/fifo.c | 2 +- drivers/usb/renesas_usbhs/fifo.h | 1 + drivers/usb/renesas_usbhs/mod_gadget.c | 16 +++++++++++++++- drivers/usb/renesas_usbhs/pipe.c | 15 +++++++++++++++ drivers/usb/renesas_usbhs/pipe.h | 1 + 6 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 8c5fc12ad778..b8620aa6b72e 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -213,6 +213,7 @@ struct usbhs_priv; /* DCPCTR */ #define BSTS (1 << 15) /* Buffer Status */ #define SUREQ (1 << 14) /* Sending SETUP Token */ +#define INBUFM (1 << 14) /* (PIPEnCTR) Transfer Buffer Monitor */ #define CSSTS (1 << 12) /* CSSTS Status */ #define ACLRM (1 << 9) /* Buffer Auto-Clear Mode */ #define SQCLR (1 << 8) /* Toggle Bit Clear */ diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 5e2aa4f85c81..79efb367e5ce 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -98,7 +98,7 @@ static void __usbhsf_pkt_del(struct usbhs_pkt *pkt) list_del_init(&pkt->node); } -static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe) +struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe) { if (list_empty(&pipe->list)) return NULL; diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index c7d9b86d51bf..3640340e94d6 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h @@ -106,5 +106,6 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, void *buf, int len, int zero, int sequence); struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt); void usbhs_pkt_start(struct usbhs_pipe *pipe); +struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe); #endif /* RENESAS_USB_FIFO_H */ diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 9e86ea6cd18c..efe8d815cf2c 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -731,6 +731,7 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge) struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct device *dev = usbhsg_gpriv_to_dev(gpriv); unsigned long flags; + int ret = 0; dev_dbg(dev, "set halt %d (pipe %d)\n", halt, usbhs_pipe_number(pipe)); @@ -738,6 +739,18 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge) /******************** spin lock ********************/ usbhs_lock(priv, flags); + /* + * According to usb_ep_set_halt()'s description, this function should + * return -EAGAIN if the IN endpoint has any queue or data. Note + * that the usbhs_pipe_is_dir_in() returns false if the pipe is an + * IN endpoint in the gadget mode. + */ + if (!usbhs_pipe_is_dir_in(pipe) && (__usbhsf_pkt_get(pipe) || + usbhs_pipe_contains_transmittable_data(pipe))) { + ret = -EAGAIN; + goto out; + } + if (halt) usbhs_pipe_stall(pipe); else @@ -748,10 +761,11 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge) else usbhsg_status_clr(gpriv, USBHSG_STATUS_WEDGE); +out: usbhs_unlock(priv, flags); /******************** spin unlock ******************/ - return 0; + return ret; } static int usbhsg_ep_set_halt(struct usb_ep *ep, int value) diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 4f9c3356127a..75fb41d4e9fc 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -279,6 +279,21 @@ int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe) return -EBUSY; } +bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe) +{ + u16 val; + + /* Do not support for DCP pipe */ + if (usbhs_pipe_is_dcp(pipe)) + return false; + + val = usbhsp_pipectrl_get(pipe); + if (val & INBUFM) + return true; + + return false; +} + /* * PID ctrl */ diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index b0bc7b603016..b7925d363bb4 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -89,6 +89,7 @@ void usbhs_pipe_init(struct usbhs_priv *priv, int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe); void usbhs_pipe_clear(struct usbhs_pipe *pipe); int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe); +bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe); void usbhs_pipe_enable(struct usbhs_pipe *pipe); void usbhs_pipe_disable(struct usbhs_pipe *pipe); void usbhs_pipe_stall(struct usbhs_pipe *pipe); -- cgit v1.2.3 From ce29fc8d82972c9f8621c2063adffac6a342bbff Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 19 Sep 2019 10:30:36 +0200 Subject: USB: legousbtower: fix slab info leak at probe commit 1d427be4a39defadda6dd8f4659bc17f7591740f upstream. Make sure to check for short transfers when retrieving the version information at probe to avoid leaking uninitialised slab data when logging it. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20190919083039.30898-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/legousbtower.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 0ec9ee573ffa..fc4b1817094e 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -923,8 +923,10 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device get_version_reply, sizeof(*get_version_reply), 1000); - if (result < 0) { - dev_err(idev, "LEGO USB Tower get version control request failed\n"); + if (result < sizeof(*get_version_reply)) { + if (result >= 0) + result = -EIO; + dev_err(idev, "get version request failed: %d\n", result); retval = result; goto error; } -- cgit v1.2.3 From 2e0bcd20f6c72a0ca0aae5ccd6125e20a95abac4 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 19 Sep 2019 10:30:37 +0200 Subject: USB: legousbtower: fix deadlock on disconnect commit 33a7813219f208f4952ece60ee255fd983272dec upstream. Fix a potential deadlock if disconnect races with open. Since commit d4ead16f50f9 ("USB: prevent char device open/deregister race") core holds an rw-semaphore while open is called and when releasing the minor number during deregistration. This can lead to an ABBA deadlock if a driver takes a lock in open which it also holds during deregistration. This effectively reverts commit 78663ecc344b ("USB: disconnect open race in legousbtower") which needlessly introduced this issue after a generic fix for this race had been added to core by commit d4ead16f50f9 ("USB: prevent char device open/deregister race"). Fixes: 78663ecc344b ("USB: disconnect open race in legousbtower") Cc: stable # 2.6.24 Reported-by: syzbot+f9549f5ee8a5416f0b95@syzkaller.appspotmail.com Tested-by: syzbot+f9549f5ee8a5416f0b95@syzkaller.appspotmail.com Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20190919083039.30898-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/legousbtower.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index fc4b1817094e..bb9a3e44cabd 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -185,7 +185,6 @@ static const struct usb_device_id tower_table[] = { }; MODULE_DEVICE_TABLE (usb, tower_table); -static DEFINE_MUTEX(open_disc_mutex); #define LEGO_USB_TOWER_MINOR_BASE 160 @@ -338,18 +337,14 @@ static int tower_open (struct inode *inode, struct file *file) goto exit; } - mutex_lock(&open_disc_mutex); dev = usb_get_intfdata(interface); - if (!dev) { - mutex_unlock(&open_disc_mutex); retval = -ENODEV; goto exit; } /* lock this device */ if (mutex_lock_interruptible(&dev->lock)) { - mutex_unlock(&open_disc_mutex); retval = -ERESTARTSYS; goto exit; } @@ -357,12 +352,10 @@ static int tower_open (struct inode *inode, struct file *file) /* allow opening only once */ if (dev->open_count) { - mutex_unlock(&open_disc_mutex); retval = -EBUSY; goto unlock_exit; } dev->open_count = 1; - mutex_unlock(&open_disc_mutex); /* reset the tower */ result = usb_control_msg (dev->udev, @@ -429,10 +422,9 @@ static int tower_release (struct inode *inode, struct file *file) if (dev == NULL) { retval = -ENODEV; - goto exit_nolock; + goto exit; } - mutex_lock(&open_disc_mutex); if (mutex_lock_interruptible(&dev->lock)) { retval = -ERESTARTSYS; goto exit; @@ -462,10 +454,7 @@ static int tower_release (struct inode *inode, struct file *file) unlock_exit: mutex_unlock(&dev->lock); - exit: - mutex_unlock(&open_disc_mutex); -exit_nolock: return retval; } @@ -944,7 +933,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device if (retval) { /* something prevented us from registering this driver */ dev_err(idev, "Not able to get a minor for this device.\n"); - usb_set_intfdata (interface, NULL); goto error; } dev->minor = interface->minor; @@ -976,16 +964,13 @@ static void tower_disconnect (struct usb_interface *interface) int minor; dev = usb_get_intfdata (interface); - mutex_lock(&open_disc_mutex); - usb_set_intfdata (interface, NULL); minor = dev->minor; - /* give back our minor */ + /* give back our minor and prevent further open() */ usb_deregister_dev (interface, &tower_class); mutex_lock(&dev->lock); - mutex_unlock(&open_disc_mutex); /* if the device is not opened, then we clean up right now */ if (!dev->open_count) { -- cgit v1.2.3 From 28f2c9460ea52a5a896edd24ac941310f9388445 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 19 Sep 2019 10:30:38 +0200 Subject: USB: legousbtower: fix potential NULL-deref on disconnect commit cd81e6fa8e033e7bcd59415b4a65672b4780030b upstream. The driver is using its struct usb_device pointer as an inverted disconnected flag, but was setting it to NULL before making sure all completion handlers had run. This could lead to a NULL-pointer dereference in a number of dev_dbg and dev_err statements in the completion handlers which relies on said pointer. Fix this by unconditionally stopping all I/O and preventing resubmissions by poisoning the interrupt URBs at disconnect and using a dedicated disconnected flag. This also makes sure that all I/O has completed by the time the disconnect callback returns. Fixes: 9d974b2a06e3 ("USB: legousbtower.c: remove err() usage") Fixes: fef526cae700 ("USB: legousbtower: remove custom debug macro") Fixes: 4dae99638097 ("USB: legotower: remove custom debug macro and module parameter") Cc: stable # 3.5 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20190919083039.30898-4-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/legousbtower.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index bb9a3e44cabd..05de83ee2ecf 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -196,6 +196,7 @@ struct lego_usb_tower { unsigned char minor; /* the starting minor number for this device */ int open_count; /* number of times this port has been opened */ + unsigned long disconnected:1; char* read_buffer; size_t read_buffer_length; /* this much came in */ @@ -295,8 +296,6 @@ static inline void lego_usb_tower_debug_data(struct device *dev, */ static inline void tower_delete (struct lego_usb_tower *dev) { - tower_abort_transfers (dev); - /* free data structures */ usb_free_urb(dev->interrupt_in_urb); usb_free_urb(dev->interrupt_out_urb); @@ -436,7 +435,8 @@ static int tower_release (struct inode *inode, struct file *file) retval = -ENODEV; goto unlock_exit; } - if (dev->udev == NULL) { + + if (dev->disconnected) { /* the device was unplugged before the file was released */ /* unlock here as tower_delete frees dev */ @@ -472,10 +472,9 @@ static void tower_abort_transfers (struct lego_usb_tower *dev) if (dev->interrupt_in_running) { dev->interrupt_in_running = 0; mb(); - if (dev->udev) - usb_kill_urb (dev->interrupt_in_urb); + usb_kill_urb(dev->interrupt_in_urb); } - if (dev->interrupt_out_busy && dev->udev) + if (dev->interrupt_out_busy) usb_kill_urb(dev->interrupt_out_urb); } @@ -511,7 +510,7 @@ static unsigned int tower_poll (struct file *file, poll_table *wait) dev = file->private_data; - if (!dev->udev) + if (dev->disconnected) return POLLERR | POLLHUP; poll_wait(file, &dev->read_wait, wait); @@ -558,7 +557,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, } /* verify that the device wasn't unplugged */ - if (dev->udev == NULL) { + if (dev->disconnected) { retval = -ENODEV; pr_err("No device or device unplugged %d\n", retval); goto unlock_exit; @@ -644,7 +643,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t } /* verify that the device wasn't unplugged */ - if (dev->udev == NULL) { + if (dev->disconnected) { retval = -ENODEV; pr_err("No device or device unplugged %d\n", retval); goto unlock_exit; @@ -753,7 +752,7 @@ static void tower_interrupt_in_callback (struct urb *urb) resubmit: /* resubmit if we're still running */ - if (dev->interrupt_in_running && dev->udev) { + if (dev->interrupt_in_running) { retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC); if (retval) dev_err(&dev->udev->dev, @@ -823,6 +822,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device dev->udev = udev; dev->open_count = 0; + dev->disconnected = 0; dev->read_buffer = NULL; dev->read_buffer_length = 0; @@ -970,6 +970,10 @@ static void tower_disconnect (struct usb_interface *interface) /* give back our minor and prevent further open() */ usb_deregister_dev (interface, &tower_class); + /* stop I/O */ + usb_poison_urb(dev->interrupt_in_urb); + usb_poison_urb(dev->interrupt_out_urb); + mutex_lock(&dev->lock); /* if the device is not opened, then we clean up right now */ @@ -977,7 +981,7 @@ static void tower_disconnect (struct usb_interface *interface) mutex_unlock(&dev->lock); tower_delete (dev); } else { - dev->udev = NULL; + dev->disconnected = 1; /* wake up pollers */ wake_up_interruptible_all(&dev->read_wait); wake_up_interruptible_all(&dev->write_wait); -- cgit v1.2.3 From 72ff2f62146267b564da22d2ce01d40635dba41e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 19 Sep 2019 10:30:39 +0200 Subject: USB: legousbtower: fix open after failed reset request commit 0b074f6986751361ff442bc1127c1648567aa8d6 upstream. The driver would return with a nonzero open count in case the reset control request failed. This would prevent any further attempts to open the char dev until the device was disconnected. Fix this by incrementing the open count only on successful open. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold Cc: stable Link: https://lore.kernel.org/r/20190919083039.30898-5-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/legousbtower.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 05de83ee2ecf..036fc5b94407 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -354,7 +354,6 @@ static int tower_open (struct inode *inode, struct file *file) retval = -EBUSY; goto unlock_exit; } - dev->open_count = 1; /* reset the tower */ result = usb_control_msg (dev->udev, @@ -394,13 +393,14 @@ static int tower_open (struct inode *inode, struct file *file) dev_err(&dev->udev->dev, "Couldn't submit interrupt_in_urb %d\n", retval); dev->interrupt_in_running = 0; - dev->open_count = 0; goto unlock_exit; } /* save device in the file's private structure */ file->private_data = dev; + dev->open_count = 1; + unlock_exit: mutex_unlock(&dev->lock); -- cgit v1.2.3 From a9640a94bb6f40225bd089bea1bd5ed596ed53c5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 9 Oct 2019 17:38:47 +0200 Subject: USB: legousbtower: fix use-after-free on release commit 726b55d0e22ca72c69c947af87785c830289ddbc upstream. The driver was accessing its struct usb_device in its release() callback without holding a reference. This would lead to a use-after-free whenever the device was disconnected while the character device was still open. Fixes: fef526cae700 ("USB: legousbtower: remove custom debug macro") Cc: stable # 3.12 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191009153848.8664-5-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/legousbtower.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 036fc5b94407..20e3d577ae5d 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -302,6 +302,7 @@ static inline void tower_delete (struct lego_usb_tower *dev) kfree (dev->read_buffer); kfree (dev->interrupt_in_buffer); kfree (dev->interrupt_out_buffer); + usb_put_dev(dev->udev); kfree (dev); } @@ -820,7 +821,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device mutex_init(&dev->lock); - dev->udev = udev; + dev->udev = usb_get_dev(udev); dev->open_count = 0; dev->disconnected = 0; -- cgit v1.2.3 From cab8f7da72a955ab275dcc27540ccdf902bc3a1a Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Fri, 4 Oct 2019 15:03:15 -0500 Subject: staging: vt6655: Fix memory leak in vt6655_probe commit 80b15db5e1e9c3300de299b2d43d1aafb593e6ac upstream. In vt6655_probe, if vnt_init() fails the cleanup code needs to be called like other error handling cases. The call to device_free_info() is added. Fixes: 67013f2c0e58 ("staging: vt6655: mac80211 conversion add main mac80211 functions") Signed-off-by: Navid Emamdoost Cc: stable Link: https://lore.kernel.org/r/20191004200319.22394-1-navid.emamdoost@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 58b6403458b7..2f3c9217d650 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1668,8 +1668,10 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent) priv->hw->max_signal = 100; - if (vnt_init(priv)) + if (vnt_init(priv)) { + device_free_info(priv); return -ENODEV; + } device_print_info(priv); pci_set_drvdata(pcid, priv); -- cgit v1.2.3 From 2a736f3547c6f13d05aae7f6e5a94cb9adb613ae Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Tue, 17 Sep 2019 18:09:23 +0200 Subject: iio: adc: ad799x: fix probe error handling commit c62dd44901cfff12acc5792bf3d2dec20bcaf392 upstream. Since commit 0f7ddcc1bff1 ("iio:adc:ad799x: Write default config on probe and reset alert status on probe") the error path is wrong since it leaves the vref regulator on. Fix this by disabling both regulators. Fixes: 0f7ddcc1bff1 ("iio:adc:ad799x: Write default config on probe and reset alert status on probe") Signed-off-by: Marco Felsch Reviewed-by: Alexandru Ardelean Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/ad799x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index ba82de25a797..46681e399e22 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -822,10 +822,10 @@ static int ad799x_probe(struct i2c_client *client, ret = ad799x_write_config(st, st->chip_config->default_config); if (ret < 0) - goto error_disable_reg; + goto error_disable_vref; ret = ad799x_read_config(st); if (ret < 0) - goto error_disable_reg; + goto error_disable_vref; st->config = ret; ret = iio_triggered_buffer_setup(indio_dev, NULL, -- cgit v1.2.3 From 07bc13c09be66ab633c69af2ca46be5b5239256f Mon Sep 17 00:00:00 2001 From: David Frey Date: Thu, 19 Sep 2019 15:54:18 -0700 Subject: iio: light: opt3001: fix mutex unlock race commit 82f3015635249a8c8c45bac303fd84905066f04f upstream. When an end-of-conversion interrupt is received after performing a single-shot reading of the light sensor, the driver was waking up the result ready queue before checking opt->ok_to_ignore_lock to determine if it should unlock the mutex. The problem occurred in the case where the other thread woke up and changed the value of opt->ok_to_ignore_lock to false prior to the interrupt thread performing its read of the variable. In this case, the mutex would be unlocked twice. Signed-off-by: David Frey Reviewed-by: Andreas Dannenberg Fixes: 94a9b7b1809f ("iio: light: add support for TI's opt3001 light sensor") Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/light/opt3001.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index 01e111e72d4b..eecdc50ed282 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -646,6 +646,7 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) struct iio_dev *iio = _iio; struct opt3001 *opt = iio_priv(iio); int ret; + bool wake_result_ready_queue = false; if (!opt->ok_to_ignore_lock) mutex_lock(&opt->lock); @@ -680,13 +681,16 @@ static irqreturn_t opt3001_irq(int irq, void *_iio) } opt->result = ret; opt->result_ready = true; - wake_up(&opt->result_ready_queue); + wake_result_ready_queue = true; } out: if (!opt->ok_to_ignore_lock) mutex_unlock(&opt->lock); + if (wake_result_ready_queue) + wake_up(&opt->result_ready_queue); + return IRQ_HANDLED; } -- cgit v1.2.3 From 6d4d8a07ba567b8396c32bfdf2e38869b44c5d8a Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 26 Sep 2019 15:00:18 -0700 Subject: perf llvm: Don't access out-of-scope array commit 7d4c85b7035eb2f9ab217ce649dcd1bfaf0cacd3 upstream. The 'test_dir' variable is assigned to the 'release' array which is out-of-scope 3 lines later. Extend the scope of the 'release' array so that an out-of-scope array isn't accessed. Bug detected by clang's address sanitizer. Fixes: 07bc5c699a3d ("perf tools: Make fetch_kernel_version() publicly available") Cc: stable@vger.kernel.org # v4.4+ Signed-off-by: Ian Rogers Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Wang Nan Link: http://lore.kernel.org/lkml/20190926220018.25402-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/llvm-utils.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 62f6d7dc2dda..9d02aa93ef90 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c @@ -214,14 +214,14 @@ static int detect_kbuild_dir(char **kbuild_dir) const char *prefix_dir = ""; const char *suffix_dir = ""; + /* _UTSNAME_LENGTH is 65 */ + char release[128]; + char *autoconf_path; int err; if (!test_dir) { - /* _UTSNAME_LENGTH is 65 */ - char release[128]; - err = fetch_kernel_version(NULL, release, sizeof(release)); if (err) -- cgit v1.2.3 From 3ca705b89bb45c5f5705e9db2b2cc43be43c22da Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Mon, 30 Sep 2019 10:06:18 -0700 Subject: CIFS: Gracefully handle QueryInfo errors during open commit 30573a82fb179420b8aac30a3a3595aa96a93156 upstream. Currently if the client identifies problems when processing metadata returned in CREATE response, the open handle is being leaked. This causes multiple problems like a file missing a lease break by that client which causes high latencies to other clients accessing the file. Another side-effect of this is that the file can't be deleted. Fix this by closing the file after the client hits an error after the file was opened and the open descriptor wasn't returned to the user space. Also convert -ESTALE to -EOPENSTALE to allow the VFS to revalidate a dentry and retry the open. Cc: Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/file.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 309c134fb66f..737cff7bc08a 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -252,6 +252,12 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, xid, fid); + if (rc) { + server->ops->close(xid, tcon, fid); + if (rc == -ESTALE) + rc = -EOPENSTALE; + } + out: kfree(buf); return rc; -- cgit v1.2.3 From 9dc8594cd7b7d1ecb860546fba5256e1483d8155 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Mon, 30 Sep 2019 10:06:20 -0700 Subject: CIFS: Force reval dentry if LOOKUP_REVAL flag is set commit 0b3d0ef9840f7be202393ca9116b857f6f793715 upstream. Mark inode for force revalidation if LOOKUP_REVAL flag is set. This tells the client to actually send a QueryInfo request to the server to obtain the latest metadata in case a directory or a file were changed remotely. Only do that if the client doesn't have a lease for the file to avoid unneeded round trips to the server. Cc: Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/dir.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index afd317eb9db9..be16da31cbcc 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -830,10 +830,16 @@ lookup_out: static int cifs_d_revalidate(struct dentry *direntry, unsigned int flags) { + struct inode *inode; + if (flags & LOOKUP_RCU) return -ECHILD; if (d_really_is_positive(direntry)) { + inode = d_inode(direntry); + if ((flags & LOOKUP_REVAL) && !CIFS_CACHE_READ(CIFS_I(inode))) + CIFS_I(inode)->time = 0; /* force reval */ + if (cifs_revalidate_dentry(direntry)) return 0; else { @@ -844,7 +850,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags) * attributes will have been updated by * cifs_revalidate_dentry(). */ - if (IS_AUTOMOUNT(d_inode(direntry)) && + if (IS_AUTOMOUNT(inode) && !(direntry->d_flags & DCACHE_NEED_AUTOMOUNT)) { spin_lock(&direntry->d_lock); direntry->d_flags |= DCACHE_NEED_AUTOMOUNT; -- cgit v1.2.3 From db02f78d9609330f64d34bfe45bd80331b42a303 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Sun, 6 Oct 2019 17:58:19 -0700 Subject: kernel/sysctl.c: do not override max_threads provided by userspace commit b0f53dbc4bc4c371f38b14c391095a3bb8a0bb40 upstream. Partially revert 16db3d3f1170 ("kernel/sysctl.c: threads-max observe limits") because the patch is causing a regression to any workload which needs to override the auto-tuning of the limit provided by kernel. set_max_threads is implementing a boot time guesstimate to provide a sensible limit of the concurrently running threads so that runaways will not deplete all the memory. This is a good thing in general but there are workloads which might need to increase this limit for an application to run (reportedly WebSpher MQ is affected) and that is simply not possible after the mentioned change. It is also very dubious to override an admin decision by an estimation that doesn't have any direct relation to correctness of the kernel operation. Fix this by dropping set_max_threads from sysctl_max_threads so any value is accepted as long as it fits into MAX_THREADS which is important to check because allowing more threads could break internal robust futex restriction. While at it, do not use MIN_THREADS as the lower boundary because it is also only a heuristic for automatic estimation and admin might have a good reason to stop new threads to be created even when below this limit. This became more severe when we switched x86 from 4k to 8k kernel stacks. Starting since 6538b8ea886e ("x86_64: expand kernel stack to 16K") (3.16) we use THREAD_SIZE_ORDER = 2 and that halved the auto-tuned value. In the particular case 3.12 kernel.threads-max = 515561 4.4 kernel.threads-max = 200000 Neither of the two values is really insane on 32GB machine. I am not sure we want/need to tune the max_thread value further. If anything the tuning should be removed altogether if proven not useful in general. But we definitely need a way to override this auto-tuning. Link: http://lkml.kernel.org/r/20190922065801.GB18814@dhcp22.suse.cz Fixes: 16db3d3f1170 ("kernel/sysctl.c: threads-max observe limits") Signed-off-by: Michal Hocko Reviewed-by: "Eric W. Biederman" Cc: Heinrich Schuchardt Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/fork.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/fork.c b/kernel/fork.c index bd6aad92819a..a6dc6b3f6a01 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -2152,7 +2152,7 @@ int sysctl_max_threads(struct ctl_table *table, int write, struct ctl_table t; int ret; int threads = max_threads; - int min = MIN_THREADS; + int min = 1; int max = MAX_THREADS; t = *table; @@ -2164,7 +2164,7 @@ int sysctl_max_threads(struct ctl_table *table, int write, if (ret || !write) return ret; - set_max_threads(threads); + max_threads = threads; return 0; } -- cgit v1.2.3 From 8eba41684829532767b273e040de2db3d7dc5dab Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Mon, 14 Oct 2019 13:32:53 +0100 Subject: arm64: capabilities: Handle sign of the feature bit commit ff96f7bc7bf6393eef8ff2bde1279715ce13343a usptream Use the appropriate accessor for the feature bit by keeping track of the sign of the feature. This is a pre-requisite for the commit 28c5dcb22f90 upstream, which fixes the arm64_ftr_value() for signed feature fields. Cc: stable@vger.kernel.org # v4.4 Signed-off-by: Suzuki K Poulose Acked-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Sasha Levin --- arch/arm64/include/asm/cpufeature.h | 7 ++++--- arch/arm64/kernel/cpufeature.c | 33 +++++++++++++++++++-------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 0a66f8241f18..690961a749da 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -88,9 +88,10 @@ struct arm64_cpu_capabilities { struct { /* Feature register checking */ u32 sys_reg; - int field_pos; - int min_field_value; - int hwcap_type; + u8 field_pos; + u8 min_field_value; + u8 hwcap_type; + bool sign; unsigned long hwcap; }; }; diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 062484d34450..3949991e544b 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -636,6 +636,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_useable_gicv3_cpuif, .sys_reg = SYS_ID_AA64PFR0_EL1, .field_pos = ID_AA64PFR0_GIC_SHIFT, + .sign = FTR_UNSIGNED, .min_field_value = 1, }, #ifdef CONFIG_ARM64_PAN @@ -645,6 +646,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_cpuid_feature, .sys_reg = SYS_ID_AA64MMFR1_EL1, .field_pos = ID_AA64MMFR1_PAN_SHIFT, + .sign = FTR_UNSIGNED, .min_field_value = 1, .enable = cpu_enable_pan, }, @@ -656,6 +658,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_cpuid_feature, .sys_reg = SYS_ID_AA64ISAR0_EL1, .field_pos = ID_AA64ISAR0_ATOMICS_SHIFT, + .sign = FTR_UNSIGNED, .min_field_value = 2, }, #endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ @@ -665,37 +668,39 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_cpuid_feature, .sys_reg = SYS_ID_AA64PFR0_EL1, .field_pos = ID_AA64PFR0_EL0_SHIFT, + .sign = FTR_UNSIGNED, .min_field_value = ID_AA64PFR0_EL0_32BIT_64BIT, }, {}, }; -#define HWCAP_CAP(reg, field, min_value, type, cap) \ +#define HWCAP_CAP(reg, field, s, min_value, type, cap) \ { \ .desc = #cap, \ .matches = has_cpuid_feature, \ .sys_reg = reg, \ .field_pos = field, \ + .sign = s, \ .min_field_value = min_value, \ .hwcap_type = type, \ .hwcap = cap, \ } static const struct arm64_cpu_capabilities arm64_hwcaps[] = { - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, 2, CAP_HWCAP, HWCAP_PMULL), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, 1, CAP_HWCAP, HWCAP_AES), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA1_SHIFT, 1, CAP_HWCAP, HWCAP_SHA1), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, 1, CAP_HWCAP, HWCAP_SHA2), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_CRC32_SHIFT, 1, CAP_HWCAP, HWCAP_CRC32), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, 2, CAP_HWCAP, HWCAP_ATOMICS), - HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, 0, CAP_HWCAP, HWCAP_FP), - HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, 0, CAP_HWCAP, HWCAP_ASIMD), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_PMULL), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_AES), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA1), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA2), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_CRC32), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_ATOMICS), + HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_FP), + HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_ASIMD), #ifdef CONFIG_COMPAT - HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, 2, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_PMULL), - HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_AES), - HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA1_SHIFT, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA1), - HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA2_SHIFT, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA2), - HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_CRC32_SHIFT, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_CRC32), + HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, FTR_UNSIGNED, 2, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_PMULL), + HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_AES_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_AES), + HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA1), + HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_SHA2), + HWCAP_CAP(SYS_ID_ISAR5_EL1, ID_ISAR5_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_COMPAT_HWCAP2, COMPAT_HWCAP2_CRC32), #endif {}, }; -- cgit v1.2.3 From bf0313653f035ae4cf9cc061bdb3a0a769946caa Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Mon, 14 Oct 2019 13:32:54 +0100 Subject: arm64: Rename cpuid_feature field extract routines commit 28c5dcb22f90113dea101b0421bc6971bccb7a74 upstream Now that we have a clear understanding of the sign of a feature, rename the routines to reflect the sign, so that it is not misused. The cpuid_feature_extract_field() now accepts a 'sign' parameter. This makes sure that the arm64_ftr_value() extracts the feature field properly for signed fields. Cc: stable@vger.kernel.org # v4.4 Signed-off-by: Suzuki K. Poulose Acked-by: Will Deacon Acked-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Sasha Levin --- arch/arm64/include/asm/cpufeature.h | 22 ++++++++++++++-------- arch/arm64/kernel/cpufeature.c | 2 +- arch/arm64/kernel/debug-monitors.c | 2 +- arch/arm64/kvm/sys_regs.c | 2 +- arch/arm64/mm/context.c | 3 ++- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 690961a749da..518eaa63e633 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -121,15 +121,15 @@ static inline void cpus_set_cap(unsigned int num) } static inline int __attribute_const__ -cpuid_feature_extract_field_width(u64 features, int field, int width) +cpuid_feature_extract_signed_field_width(u64 features, int field, int width) { return (s64)(features << (64 - width - field)) >> (64 - width); } static inline int __attribute_const__ -cpuid_feature_extract_field(u64 features, int field) +cpuid_feature_extract_signed_field(u64 features, int field) { - return cpuid_feature_extract_field_width(features, field, 4); + return cpuid_feature_extract_signed_field_width(features, field, 4); } static inline unsigned int __attribute_const__ @@ -149,17 +149,23 @@ static inline u64 arm64_ftr_mask(struct arm64_ftr_bits *ftrp) return (u64)GENMASK(ftrp->shift + ftrp->width - 1, ftrp->shift); } +static inline int __attribute_const__ +cpuid_feature_extract_field(u64 features, int field, bool sign) +{ + return (sign) ? + cpuid_feature_extract_signed_field(features, field) : + cpuid_feature_extract_unsigned_field(features, field); +} + static inline s64 arm64_ftr_value(struct arm64_ftr_bits *ftrp, u64 val) { - return ftrp->sign ? - cpuid_feature_extract_field_width(val, ftrp->shift, ftrp->width) : - cpuid_feature_extract_unsigned_field_width(val, ftrp->shift, ftrp->width); + return (s64)cpuid_feature_extract_field(val, ftrp->shift, ftrp->sign); } static inline bool id_aa64mmfr0_mixed_endian_el0(u64 mmfr0) { - return cpuid_feature_extract_field(mmfr0, ID_AA64MMFR0_BIGENDEL_SHIFT) == 0x1 || - cpuid_feature_extract_field(mmfr0, ID_AA64MMFR0_BIGENDEL0_SHIFT) == 0x1; + return cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_BIGENDEL_SHIFT) == 0x1 || + cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_BIGENDEL0_SHIFT) == 0x1; } void __init setup_cpu_features(void); diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 3949991e544b..a0118a07a4a5 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -600,7 +600,7 @@ u64 read_system_reg(u32 id) static bool feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry) { - int val = cpuid_feature_extract_field(reg, entry->field_pos); + int val = cpuid_feature_extract_field(reg, entry->field_pos, entry->sign); return val >= entry->min_field_value; } diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c index c8875b64be90..8e7675e5ce4a 100644 --- a/arch/arm64/kernel/debug-monitors.c +++ b/arch/arm64/kernel/debug-monitors.c @@ -34,7 +34,7 @@ /* Determine debug architecture. */ u8 debug_monitors_arch(void) { - return cpuid_feature_extract_field(read_system_reg(SYS_ID_AA64DFR0_EL1), + return cpuid_feature_extract_unsigned_field(read_system_reg(SYS_ID_AA64DFR0_EL1), ID_AA64DFR0_DEBUGVER_SHIFT); } diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index c2489f62c4fb..0a587e7b9b6e 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -687,7 +687,7 @@ static bool trap_dbgidr(struct kvm_vcpu *vcpu, } else { u64 dfr = read_system_reg(SYS_ID_AA64DFR0_EL1); u64 pfr = read_system_reg(SYS_ID_AA64PFR0_EL1); - u32 el3 = !!cpuid_feature_extract_field(pfr, ID_AA64PFR0_EL3_SHIFT); + u32 el3 = !!cpuid_feature_extract_unsigned_field(pfr, ID_AA64PFR0_EL3_SHIFT); p->regval = ((((dfr >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) << 28) | (((dfr >> ID_AA64DFR0_BRPS_SHIFT) & 0xf) << 24) | diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c index e87f53ff5f58..5c8759cd66f1 100644 --- a/arch/arm64/mm/context.c +++ b/arch/arm64/mm/context.c @@ -187,7 +187,8 @@ switch_mm_fastpath: static int asids_init(void) { - int fld = cpuid_feature_extract_field(read_cpuid(ID_AA64MMFR0_EL1), 4); + int fld = cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64MMFR0_EL1), + ID_AA64MMFR0_ASID_SHIFT); switch (fld) { default: -- cgit v1.2.3 From c712daafe23b79e1d269d66b8cc47bf63a0096b2 Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Sun, 29 Sep 2019 22:09:45 -0500 Subject: Staging: fbtft: fix memory leak in fbtft_framebuffer_alloc [ Upstream commit 5bdea6060618cfcf1459dca137e89aee038ac8b9 ] In fbtft_framebuffer_alloc the error handling path should take care of releasing frame buffer after it is allocated via framebuffer_alloc, too. Therefore, in two failure cases the goto destination is changed to address this issue. Fixes: c296d5f9957c ("staging: fbtft: core support") Signed-off-by: Navid Emamdoost Reviewed-by: Dan Carpenter Cc: stable Link: https://lore.kernel.org/r/20190930030949.28615-1-navid.emamdoost@gmail.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/staging/fbtft/fbtft-core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 18c2b6daf588..15937e0ef4d9 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -813,7 +813,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, if (par->gamma.curves && gamma) { if (fbtft_gamma_parse_str(par, par->gamma.curves, gamma, strlen(gamma))) - goto alloc_fail; + goto release_framebuf; } /* Transmit buffer */ @@ -836,7 +836,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, txbuf = devm_kzalloc(par->info->device, txbuflen, GFP_KERNEL); } if (!txbuf) - goto alloc_fail; + goto release_framebuf; par->txbuf.buf = txbuf; par->txbuf.len = txbuflen; } @@ -872,6 +872,9 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, return info; +release_framebuf: + framebuffer_release(info); + alloc_fail: vfree(vmem); -- cgit v1.2.3 From 4701063a62a69fbdef49a25e505c510040dab1bd Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Wed, 2 Dec 2015 14:46:08 +0000 Subject: cifs: Check uniqueid for SMB2+ and return -ESTALE if necessary [ Upstream commit a108471b5730b52017e73b58c9f486319d2ac308 ] Commit 7196ac113a4f ("Fix to check Unique id and FileType when client refer file directly.") checks whether the uniqueid of an inode has changed when getting the inode info, but only when using the UNIX extensions. Add a similar check for SMB2+, since this can be done without an extra network roundtrip. Signed-off-by: Ross Lagerwall Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/cifs/inode.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 0f210cb5038a..3d3c66fcb5ee 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -829,8 +829,21 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, } } else fattr.cf_uniqueid = iunique(sb, ROOT_I); - } else - fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; + } else { + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && + validinum == false && server->ops->get_srv_inum) { + /* + * Pass a NULL tcon to ensure we don't make a round + * trip to the server. This only works for SMB2+. + */ + tmprc = server->ops->get_srv_inum(xid, + NULL, cifs_sb, full_path, + &fattr.cf_uniqueid, data); + if (tmprc) + fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; + } else + fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; + } /* query for SFU type info if supported and needed */ if (fattr.cf_cifsattrs & ATTR_SYSTEM && @@ -871,6 +884,13 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, } else { /* we already have inode, update it */ + /* if uniqueid is different, return error */ + if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && + CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) { + rc = -ESTALE; + goto cgii_exit; + } + /* if filetype is different, return error */ if (unlikely(((*inode)->i_mode & S_IFMT) != (fattr.cf_mode & S_IFMT))) { -- cgit v1.2.3 From 91fdb3cf4cf50c13dfb8dca7824f17aceec68a73 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Mon, 30 Sep 2019 10:06:19 -0700 Subject: CIFS: Force revalidate inode when dentry is stale [ Upstream commit c82e5ac7fe3570a269c0929bf7899f62048e7dbc ] Currently the client indicates that a dentry is stale when inode numbers or type types between a local inode and a remote file don't match. If this is the case attributes is not being copied from remote to local, so, it is already known that the local copy has stale metadata. That's why the inode needs to be marked for revalidation in order to tell the VFS to lookup the dentry again before openning a file. This prevents unexpected stale errors to be returned to the user space when openning a file. Cc: Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Sasha Levin --- fs/cifs/inode.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 3d3c66fcb5ee..0a219545940d 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -405,6 +405,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, /* if uniqueid is different, return error */ if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && CIFS_I(*pinode)->uniqueid != fattr.cf_uniqueid)) { + CIFS_I(*pinode)->time = 0; /* force reval */ rc = -ESTALE; goto cgiiu_exit; } @@ -412,6 +413,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, /* if filetype is different, return error */ if (unlikely(((*pinode)->i_mode & S_IFMT) != (fattr.cf_mode & S_IFMT))) { + CIFS_I(*pinode)->time = 0; /* force reval */ rc = -ESTALE; goto cgiiu_exit; } @@ -887,6 +889,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, /* if uniqueid is different, return error */ if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) { + CIFS_I(*inode)->time = 0; /* force reval */ rc = -ESTALE; goto cgii_exit; } @@ -894,6 +897,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, /* if filetype is different, return error */ if (unlikely(((*inode)->i_mode & S_IFMT) != (fattr.cf_mode & S_IFMT))) { + CIFS_I(*inode)->time = 0; /* force reval */ rc = -ESTALE; goto cgii_exit; } -- cgit v1.2.3 From d1de6f689d8204ac66818767707ec140f997c8fd Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 1 Oct 2019 10:49:08 +0200 Subject: media: stkwebcam: fix runtime PM after driver unbind commit 30045f2174aab7fb4db7a9cf902d0aa6c75856a7 upstream. Since commit c2b71462d294 ("USB: core: Fix bug caused by duplicate interface PM usage counter") USB drivers must always balance their runtime PM gets and puts, including when the driver has already been unbound from the interface. Leaving the interface with a positive PM usage counter would prevent a later bound driver from suspending the device. Note that runtime PM has never actually been enabled for this driver since the support_autosuspend flag in its usb_driver struct is not set. Fixes: c2b71462d294 ("USB: core: Fix bug caused by duplicate interface PM usage counter") Cc: stable Acked-by: Mauro Carvalho Chehab Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191001084908.2003-5-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/stkwebcam/stk-webcam.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index c21c4c004f97..17ee9cde4156 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -642,8 +642,7 @@ static int v4l_stk_release(struct file *fp) dev->owner = NULL; } - if (is_present(dev)) - usb_autopm_put_interface(dev->interface); + usb_autopm_put_interface(dev->interface); mutex_unlock(&dev->lock); return v4l2_fh_release(fp); } -- cgit v1.2.3 From 35fa86e42bf407879a8b496f3dab9535cada813c Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Fri, 11 Oct 2019 18:19:17 -0400 Subject: tracing: Get trace_array reference for available_tracers files commit 194c2c74f5532e62c218adeb8e2b683119503907 upstream. As instances may have different tracers available, we need to look at the trace_array descriptor that shows the list of the available tracers for the instance. But there's a race between opening the file and an admin deleting the instance. The trace_array_get() needs to be called before accessing the trace_array. Cc: stable@vger.kernel.org Fixes: 607e2ea167e56 ("tracing: Set up infrastructure to allow tracers for instances") Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index c82ebd11414a..c6e4e3e7f685 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3370,9 +3370,14 @@ static int show_traces_open(struct inode *inode, struct file *file) if (tracing_disabled) return -ENODEV; + if (trace_array_get(tr) < 0) + return -ENODEV; + ret = seq_open(file, &show_traces_seq_ops); - if (ret) + if (ret) { + trace_array_put(tr); return ret; + } m = file->private_data; m->private = tr; @@ -3380,6 +3385,14 @@ static int show_traces_open(struct inode *inode, struct file *file) return 0; } +static int show_traces_release(struct inode *inode, struct file *file) +{ + struct trace_array *tr = inode->i_private; + + trace_array_put(tr); + return seq_release(inode, file); +} + static ssize_t tracing_write_stub(struct file *filp, const char __user *ubuf, size_t count, loff_t *ppos) @@ -3410,8 +3423,8 @@ static const struct file_operations tracing_fops = { static const struct file_operations show_traces_fops = { .open = show_traces_open, .read = seq_read, - .release = seq_release, .llseek = seq_lseek, + .release = show_traces_release, }; static ssize_t -- cgit v1.2.3 From f9c94a02d4c5abccecb893a42247dfe24da8bdad Mon Sep 17 00:00:00 2001 From: Janakarajan Natarajan Date: Mon, 7 Oct 2019 19:00:22 +0000 Subject: x86/asm: Fix MWAITX C-state hint value commit 454de1e7d970d6bc567686052329e4814842867c upstream. As per "AMD64 Architecture Programmer's Manual Volume 3: General-Purpose and System Instructions", MWAITX EAX[7:4]+1 specifies the optional hint of the optimized C-state. For C0 state, EAX[7:4] should be set to 0xf. Currently, a value of 0xf is set for EAX[3:0] instead of EAX[7:4]. Fix this by changing MWAITX_DISABLE_CSTATES from 0xf to 0xf0. This hasn't had any implications so far because setting reserved bits in EAX is simply ignored by the CPU. [ bp: Fixup comment in delay_mwaitx() and massage. ] Signed-off-by: Janakarajan Natarajan Signed-off-by: Borislav Petkov Cc: Frederic Weisbecker Cc: Greg Kroah-Hartman Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Thomas Gleixner Cc: "x86@kernel.org" Cc: Zhenzhong Duan Cc: Link: https://lkml.kernel.org/r/20191007190011.4859-1-Janakarajan.Natarajan@amd.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/mwait.h | 2 +- arch/x86/lib/delay.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/mwait.h b/arch/x86/include/asm/mwait.h index b98dbdaee8ac..1ab7f37150d2 100644 --- a/arch/x86/include/asm/mwait.h +++ b/arch/x86/include/asm/mwait.h @@ -19,7 +19,7 @@ #define MWAIT_ECX_INTERRUPT_BREAK 0x1 #define MWAITX_ECX_TIMER_ENABLE BIT(1) #define MWAITX_MAX_LOOPS ((u32)-1) -#define MWAITX_DISABLE_CSTATES 0xf +#define MWAITX_DISABLE_CSTATES 0xf0 static inline void __monitor(const void *eax, unsigned long ecx, unsigned long edx) diff --git a/arch/x86/lib/delay.c b/arch/x86/lib/delay.c index 45772560aceb..fc0cc6d08157 100644 --- a/arch/x86/lib/delay.c +++ b/arch/x86/lib/delay.c @@ -112,8 +112,8 @@ static void delay_mwaitx(unsigned long __loops) __monitorx(this_cpu_ptr(&cpu_tss), 0, 0); /* - * AMD, like Intel, supports the EAX hint and EAX=0xf - * means, do not enter any deep C-state and we use it + * AMD, like Intel's MWAIT version, supports the EAX hint and + * EAX=0xf0 means, do not enter any deep C-state and we use it * here in delay() to minimize wakeup latency. */ __mwaitx(MWAITX_DISABLE_CSTATES, delay, MWAITX_ECX_TIMER_ENABLE); -- cgit v1.2.3 From 748edae843c30f41fdcb320f1a8335bc2238b961 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Thu, 10 May 2018 21:50:23 -0700 Subject: xfs: clear sb->s_fs_info on mount failure commit c9fbd7bbc23dbdd73364be4d045e5d3612cf6e82 upstream. We recently had an oops reported on a 4.14 kernel in xfs_reclaim_inodes_count() where sb->s_fs_info pointed to garbage and so the m_perag_tree lookup walked into lala land. Essentially, the machine was under memory pressure when the mount was being run, xfs_fs_fill_super() failed after allocating the xfs_mount and attaching it to sb->s_fs_info. It then cleaned up and freed the xfs_mount, but the sb->s_fs_info field still pointed to the freed memory. Hence when the superblock shrinker then ran it fell off the bad pointer. With the superblock shrinker problem fixed at teh VFS level, this stale s_fs_info pointer is still a problem - we use it unconditionally in ->put_super when the superblock is being torn down, and hence we can still trip over it after a ->fill_super call failure. Hence we need to clear s_fs_info if xfs-fs_fill_super() fails, and we need to check if it's valid in the places it can potentially be dereferenced after a ->fill_super failure. Signed-Off-By: Dave Chinner Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong Signed-off-by: Ajay Kaher Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_super.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index ef64a1e1a66a..ff3f5812c0fd 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1572,6 +1572,7 @@ xfs_fs_fill_super( out_close_devices: xfs_close_devices(mp); out_free_fsname: + sb->s_fs_info = NULL; xfs_free_fsname(mp); kfree(mp); out: @@ -1589,6 +1590,10 @@ xfs_fs_put_super( { struct xfs_mount *mp = XFS_M(sb); + /* if ->fill_super failed, we have no mount to tear down */ + if (!sb->s_fs_info) + return; + xfs_notice(mp, "Unmounting Filesystem"); xfs_filestream_unmount(mp); xfs_unmountfs(mp); @@ -1598,6 +1603,8 @@ xfs_fs_put_super( xfs_destroy_percpu_counters(mp); xfs_destroy_mount_workqueues(mp); xfs_close_devices(mp); + + sb->s_fs_info = NULL; xfs_free_fsname(mp); kfree(mp); } @@ -1617,6 +1624,9 @@ xfs_fs_nr_cached_objects( struct super_block *sb, struct shrink_control *sc) { + /* Paranoia: catch incorrect calls during mount setup or teardown */ + if (WARN_ON_ONCE(!sb->s_fs_info)) + return 0; return xfs_reclaim_inodes_count(XFS_M(sb)); } -- cgit v1.2.3 From 04858540ca8435e52654680dabfd769056ad9eb0 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 17 Oct 2019 13:41:06 -0700 Subject: Linux 4.4.197 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9eaf50527883..5c150d32cae7 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 196 +SUBLEVEL = 197 EXTRAVERSION = NAME = Blurry Fish Butt -- cgit v1.2.3 From 61fd8755a707acbdb697499ea265d9676294ffc7 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Wed, 27 Mar 2019 11:18:48 +0100 Subject: HID: core: move Usage Page concatenation to Main item [ Upstream commit 58e75155009cc800005629955d3482f36a1e0eec ] As seen on some USB wireless keyboards manufactured by Primax, the HID parser was using some assumptions that are not always true. In this case it's s the fact that, inside the scope of a main item, an Usage Page will always precede an Usage. The spec is not pretty clear as 6.2.2.7 states "Any usage that follows is interpreted as a Usage ID and concatenated with the Usage Page". While 6.2.2.8 states "When the parser encounters a main item it concatenates the last declared Usage Page with a Usage to form a complete usage value." Being somewhat contradictory it was decided to match Window's implementation, which follows 6.2.2.8. In summary, the patch moves the Usage Page concatenation from the local item parsing function to the main item parsing function. Change-Id: Id25c0c7e11712501d117fb715b64db7772ac2066 Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Terry Junge Signed-off-by: Benjamin Tissoires Signed-off-by: Sasha Levin Git-commit: 5db3c5adf44ad3166472b009b122df5ef1144c9c Git-repo: https://android.googlesource.com/kernel/common/ Signed-off-by: Rahul Shahare --- drivers/hid/hid-core.c | 36 ++++++++++++++++++++++++------------ include/linux/hid.h | 1 + 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 7f6c13740f4f..fd8cd41e6377 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -200,13 +200,14 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) * Add a usage to the temporary parser table. */ -static int hid_add_usage(struct hid_parser *parser, unsigned usage) +static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size) { if (parser->local.usage_index >= HID_MAX_USAGES) { hid_err(parser->device, "usage index exceeded\n"); return -1; } parser->local.usage[parser->local.usage_index] = usage; + parser->local.usage_size[parser->local.usage_index] = size; parser->local.collection_index[parser->local.usage_index] = parser->collection_stack_ptr ? parser->collection_stack[parser->collection_stack_ptr - 1] : 0; @@ -463,10 +464,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) return 0; } - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - return hid_add_usage(parser, data); + return hid_add_usage(parser, data, item->size); case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: @@ -475,9 +473,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) return 0; } - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - parser->local.usage_minimum = data; return 0; @@ -488,9 +483,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) return 0; } - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - count = data - parser->local.usage_minimum; if (count + parser->local.usage_index >= HID_MAX_USAGES) { /* @@ -510,7 +502,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) } for (n = parser->local.usage_minimum; n <= data; n++) - if (hid_add_usage(parser, n)) { + if (hid_add_usage(parser, n, item->size)) { dbg_hid("hid_add_usage failed\n"); return -1; } @@ -524,6 +516,22 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) return 0; } +/* + * Concatenate Usage Pages into Usages where relevant: + * As per specification, 6.2.2.8: "When the parser encounters a main item it + * concatenates the last declared Usage Page with a Usage to form a complete + * usage value." + */ + +static void hid_concatenate_usage_page(struct hid_parser *parser) +{ + int i; + + for (i = 0; i < parser->local.usage_index; i++) + if (parser->local.usage_size[i] <= 2) + parser->local.usage[i] += parser->global.usage_page << 16; +} + /* * Process a main item. */ @@ -533,6 +541,8 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) __u32 data; int ret; + hid_concatenate_usage_page(parser); + data = item_udata(item); switch (item->tag) { @@ -746,6 +756,8 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) __u32 data; int i; + hid_concatenate_usage_page(parser); + data = item_udata(item); switch (item->tag) { diff --git a/include/linux/hid.h b/include/linux/hid.h index d16de62231d3..5f1e901353ed 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -378,6 +378,7 @@ struct hid_global { struct hid_local { unsigned usage[HID_MAX_USAGES]; /* usage array */ + u8 usage_size[HID_MAX_USAGES]; /* usage size array */ unsigned collection_index[HID_MAX_USAGES]; /* collection index array */ unsigned usage_index; unsigned usage_minimum; -- cgit v1.2.3 From 8ba522499fbf84fb956c194badcee35c4478d4cd Mon Sep 17 00:00:00 2001 From: Candle Sun Date: Mon, 30 Sep 2019 16:09:09 +0800 Subject: HID: core: add usage_page_preceding flag for hid_concatenate_usage_page() Upstream commit 58e75155009c ("HID: core: move Usage Page concatenation to Main item") adds support for Usage Page item following Usage items (such as keyboards manufactured by Primax). Usage Page concatenation in Main item works well for following report descriptor patterns: USAGE_PAGE (Keyboard) 05 07 USAGE_MINIMUM (Keyboard LeftControl) 19 E0 USAGE_MAXIMUM (Keyboard Right GUI) 29 E7 LOGICAL_MINIMUM (0) 15 00 LOGICAL_MAXIMUM (1) 25 01 REPORT_SIZE (1) 75 01 REPORT_COUNT (8) 95 08 INPUT (Data,Var,Abs) 81 02 ------------- USAGE_MINIMUM (Keyboard LeftControl) 19 E0 USAGE_MAXIMUM (Keyboard Right GUI) 29 E7 LOGICAL_MINIMUM (0) 15 00 LOGICAL_MAXIMUM (1) 25 01 REPORT_SIZE (1) 75 01 REPORT_COUNT (8) 95 08 USAGE_PAGE (Keyboard) 05 07 INPUT (Data,Var,Abs) 81 02 But it makes the parser act wrong for the following report descriptor pattern(such as some Gamepads): USAGE_PAGE (Button) 05 09 USAGE (Button 1) 09 01 USAGE (Button 2) 09 02 USAGE (Button 4) 09 04 USAGE (Button 5) 09 05 USAGE (Button 7) 09 07 USAGE (Button 8) 09 08 USAGE (Button 14) 09 0E USAGE (Button 15) 09 0F USAGE (Button 13) 09 0D USAGE_PAGE (Consumer Devices) 05 0C USAGE (Back) 0a 24 02 USAGE (HomePage) 0a 23 02 LOGICAL_MINIMUM (0) 15 00 LOGICAL_MAXIMUM (1) 25 01 REPORT_SIZE (1) 75 01 REPORT_COUNT (11) 95 0B INPUT (Data,Var,Abs) 81 02 With Usage Page concatenation in Main item, parser recognizes all the 11 Usages as consumer keys, it is not the HID device's real intention. This patch adds usage_page_preceding flag to detect the third pattern. Usage Page concatenation is done in both Local and Main parsing. If usage_page_preceding equals 3(the third pattern encountered), hid_concatenate_usage_page() is jumped. Change-Id: Ieba9bcae85c49619b0abbafb55ce26d72a24f086 Signed-off-by: Candle Sun Signed-off-by: Nianfu Bai Fixes: 58e75155009c ("HID: core: move Usage Page concatenation to Main item") Link: https://lore.kernel.org/lkml/1569830949-10771-1-git-send-email-candlesea@gmail.com/ Patch-mainline: linux-kernel @ 30/09/2019, 16:09 Signed-off-by: Rahul Shahare --- drivers/hid/hid-core.c | 21 +++++++++++++++++++-- include/linux/hid.h | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index fd8cd41e6377..a22881befa27 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -206,7 +206,15 @@ static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size) hid_err(parser->device, "usage index exceeded\n"); return -1; } - parser->local.usage[parser->local.usage_index] = usage; + if (!parser->local.usage_index && parser->global.usage_page) + parser->local.usage_page_preceding = 1; + if (parser->local.usage_page_preceding == 2) + parser->local.usage_page_preceding = 3; + if (size <= 2 && parser->global.usage_page) + parser->local.usage[parser->local.usage_index] = + (usage & 0xffff) + (parser->global.usage_page << 16); + else + parser->local.usage[parser->local.usage_index] = usage; parser->local.usage_size[parser->local.usage_index] = size; parser->local.collection_index[parser->local.usage_index] = parser->collection_stack_ptr ? @@ -346,6 +354,8 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: parser->global.usage_page = item_udata(item); + if (parser->local.usage_page_preceding == 1) + parser->local.usage_page_preceding = 2; return 0; case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: @@ -527,9 +537,16 @@ static void hid_concatenate_usage_page(struct hid_parser *parser) { int i; + if (parser->local.usage_page_preceding == 3) { + dbg_hid("Using preceding usage page for final usage\n"); + return; + } + for (i = 0; i < parser->local.usage_index; i++) if (parser->local.usage_size[i] <= 2) - parser->local.usage[i] += parser->global.usage_page << 16; + parser->local.usage[i] = + (parser->global.usage_page << 16) + + (parser->local.usage[i] & 0xffff); } /* diff --git a/include/linux/hid.h b/include/linux/hid.h index 5f1e901353ed..e558919bd86a 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -384,6 +384,7 @@ struct hid_local { unsigned usage_minimum; unsigned delimiter_depth; unsigned delimiter_branch; + unsigned int usage_page_preceding; }; /* -- cgit v1.2.3 From c5ca3ffaa4083d01d395c76b16650793c078f869 Mon Sep 17 00:00:00 2001 From: jitendrathakare Date: Thu, 12 Sep 2019 19:46:48 +0530 Subject: qseecom : Clear client handle after unmap the resources When unloading the app, reset all client members to NULL to protect from accessing the memory after being freed. Change-Id: I573b9c6fde03539522d2b04724a2246660c62518 Signed-off-by: jitendra thakare --- drivers/misc/qseecom.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index dfa3bb6b186f..d50144e0fed9 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -2533,7 +2533,8 @@ static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data) if (!IS_ERR_OR_NULL(data->client.ihandle)) { ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle); ion_free(qseecom.ion_clnt, data->client.ihandle); - data->client.ihandle = NULL; + memset((void *)&data->client, + 0, sizeof(struct qseecom_client_handle)); } return ret; } -- cgit v1.2.3 From 5ff3c8e36617ec6a80c3b4b79e30bff9b127627a Mon Sep 17 00:00:00 2001 From: Yue Ma Date: Thu, 17 Oct 2019 12:30:26 -0700 Subject: cnss2: Expose PCIe window register lock related APIs The register window needs to be configed properly before accessing any larger than 4K range PCIe registers. Expose the lock to WLAN driver to avoid race condition when both drivers try to config it. Change-Id: I94ccd963d4fd0a9715330d2e5733346ccd993ae1 Signed-off-by: Yue Ma --- drivers/net/wireless/cnss2/pci.c | 13 +++++++++++++ include/net/cnss2.h | 3 +++ 2 files changed, 16 insertions(+) diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 7dc419753a80..099aa9d38bb8 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -56,6 +56,7 @@ #ifdef CONFIG_PCI_MSM static DEFINE_SPINLOCK(pci_link_down_lock); #endif +static DEFINE_SPINLOCK(pci_reg_window_lock); static unsigned int pci_link_down_panic; module_param(pci_link_down_panic, uint, 0600); @@ -268,6 +269,18 @@ int cnss_pci_is_device_down(struct device *dev) } EXPORT_SYMBOL(cnss_pci_is_device_down); +void cnss_pci_lock_reg_window(struct device *dev, unsigned long *flags) +{ + spin_lock_bh(&pci_reg_window_lock); +} +EXPORT_SYMBOL(cnss_pci_lock_reg_window); + +void cnss_pci_unlock_reg_window(struct device *dev, unsigned long *flags) +{ + spin_unlock_bh(&pci_reg_window_lock); +} +EXPORT_SYMBOL(cnss_pci_unlock_reg_window); + int cnss_pci_recovery_update_status(struct cnss_pci_data *pci_priv) { struct cnss_plat_data *plat_priv; diff --git a/include/net/cnss2.h b/include/net/cnss2.h index 5ed1b05277b1..4a541581f9d7 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -245,6 +245,9 @@ extern void cnss_request_pm_qos(struct device *dev, u32 qos_val); extern void cnss_remove_pm_qos(struct device *dev); extern void cnss_lock_pm_sem(struct device *dev); extern void cnss_release_pm_sem(struct device *dev); +extern void cnss_pci_lock_reg_window(struct device *dev, unsigned long *flags); +extern void cnss_pci_unlock_reg_window(struct device *dev, + unsigned long *flags); extern int cnss_auto_suspend(struct device *dev); extern int cnss_auto_resume(struct device *dev); extern int cnss_pci_is_drv_connected(struct device *dev); -- cgit v1.2.3 From b6aeea3bff1f63618d1c55803ce96297e023114d Mon Sep 17 00:00:00 2001 From: Matthias Maennich Date: Thu, 29 Aug 2019 12:34:52 +0100 Subject: ANDROID: refactor build.config files to remove duplication The build.config.* files largely contain duplicate information by their nature. Reorganize them reduce duplication and to allow adding new configurations without copying the definitions again. Bug: 140224784 Change-Id: I6a3810a125b0ed48591690ca33bb5c02be58218a Signed-off-by: Matthias Maennich (cherry picked from commit 7d642373db4c6c1c6ed8af02492047896beb4a47) --- build.config.aarch64 | 11 +++++++++++ build.config.common | 9 +++++++++ build.config.cuttlefish.aarch64 | 17 +++-------------- build.config.cuttlefish.x86_64 | 17 +++-------------- build.config.x86_64 | 11 +++++++++++ 5 files changed, 37 insertions(+), 28 deletions(-) create mode 100644 build.config.aarch64 create mode 100644 build.config.common create mode 100644 build.config.x86_64 diff --git a/build.config.aarch64 b/build.config.aarch64 new file mode 100644 index 000000000000..523bbc0449f7 --- /dev/null +++ b/build.config.aarch64 @@ -0,0 +1,11 @@ +ARCH=arm64 + +CLANG_TRIPLE=aarch64-linux-gnu- +CROSS_COMPILE=aarch64-linux-androidkernel- +LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin + +FILES=" +arch/arm64/boot/Image.gz +vmlinux +System.map +" diff --git a/build.config.common b/build.config.common new file mode 100644 index 000000000000..fd58f76a938b --- /dev/null +++ b/build.config.common @@ -0,0 +1,9 @@ +BRANCH=android-4.4-p +KERNEL_DIR=common + +CC=clang +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r353983c/bin +BUILDTOOLS_PREBUILT_BIN=build/build-tools/path/linux-x86 + +EXTRA_CMDS='' +STOP_SHIP_TRACEPRINTK=1 diff --git a/build.config.cuttlefish.aarch64 b/build.config.cuttlefish.aarch64 index 818b3dc1b3a3..0cb601958972 100644 --- a/build.config.cuttlefish.aarch64 +++ b/build.config.cuttlefish.aarch64 @@ -1,16 +1,5 @@ -ARCH=arm64 -BRANCH=android-4.4 -CLANG_TRIPLE=aarch64-linux-gnu- -CROSS_COMPILE=aarch64-linux-androidkernel- +. ${ROOT_DIR}/common/build.config.common +. ${ROOT_DIR}/common/build.config.aarch64 + DEFCONFIG=cuttlefish_defconfig -EXTRA_CMDS='' -KERNEL_DIR=common POST_DEFCONFIG_CMDS="check_defconfig" -CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r353983c/bin -LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin -FILES=" -arch/arm64/boot/Image.gz -vmlinux -System.map -" -STOP_SHIP_TRACEPRINTK=1 diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64 index 84556472221d..fed773ccc64a 100644 --- a/build.config.cuttlefish.x86_64 +++ b/build.config.cuttlefish.x86_64 @@ -1,16 +1,5 @@ -ARCH=x86_64 -BRANCH=android-4.4 -CLANG_TRIPLE=x86_64-linux-gnu- -CROSS_COMPILE=x86_64-linux-androidkernel- +. ${ROOT_DIR}/common/build.config.common +. ${ROOT_DIR}/common/build.config.x86_64 + DEFCONFIG=x86_64_cuttlefish_defconfig -EXTRA_CMDS='' -KERNEL_DIR=common POST_DEFCONFIG_CMDS="check_defconfig" -CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r353983c/bin -LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin -FILES=" -arch/x86/boot/bzImage -vmlinux -System.map -" -STOP_SHIP_TRACEPRINTK=1 diff --git a/build.config.x86_64 b/build.config.x86_64 new file mode 100644 index 000000000000..df73a47e7220 --- /dev/null +++ b/build.config.x86_64 @@ -0,0 +1,11 @@ +ARCH=x86_64 + +CLANG_TRIPLE=x86_64-linux-gnu- +CROSS_COMPILE=x86_64-linux-androidkernel- +LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin + +FILES=" +arch/x86/boot/bzImage +vmlinux +System.map +" -- cgit v1.2.3 From 2af9b2a1e8327d2ffff9f344d25d3cb0124e4fc3 Mon Sep 17 00:00:00 2001 From: Archana Sriram Date: Tue, 15 Oct 2019 10:36:26 +0530 Subject: msm: kgsl: Check user generated timestamp before queuing drawobjs In ioctls like kgsl_ioctl_submit_commands(), if both syncobj type and cmd/marker/sparseobj type are submitted, the syncobj is queued first followed by the other obj type. After syncobj is successfully queued, in case of failure in get_timestamp while queuing the other obj, both the command objs are destroyed. As sync obj is already queued, accessing this later would cause a crash. Compare the user generated timestamp with the drawctxt timestamp and return early in case of error. This avoids unnecessary queuing of drawobjs. Change-Id: I336c95c42ab1075d7653cba02772f92c918c884c Signed-off-by: Archana Sriram Signed-off-by: Harshitha Sai Neelati --- drivers/gpu/msm/adreno_dispatch.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 002722f75c6c..49b14fbf439c 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1405,6 +1405,22 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv, user_ts = *timestamp; + /* + * If there is only one drawobj in the array and it is of + * type SYNCOBJ_TYPE, skip comparing user_ts as it can be 0 + */ + if (!(count == 1 && drawobj[0]->type == SYNCOBJ_TYPE) && + (drawctxt->base.flags & KGSL_CONTEXT_USER_GENERATED_TS)) { + /* + * User specified timestamps need to be greater than the last + * issued timestamp in the context + */ + if (timestamp_cmp(drawctxt->timestamp, user_ts) >= 0) { + spin_unlock(&drawctxt->lock); + return -ERANGE; + } + } + for (i = 0; i < count; i++) { switch (drawobj[i]->type) { -- cgit v1.2.3 From 04024ee16495c8cf184c444a0edaf6aa68fda357 Mon Sep 17 00:00:00 2001 From: Harshitha Sai Neelati Date: Wed, 4 Sep 2019 17:32:28 +0530 Subject: adreno_tz: Correct acc_relative_busy calculation Current acc_relative_busy calculation is causing integer overflow in 32 bit system. "stats->busy_time * stats->current_frequency" results in a value which is beyond the 32 bit range. Typecasting the value to u64 to avoid overflow. Change-Id: Id97da02bef608787ceb7c9751bbfc203af56deb1 Signed-off-by: Harshitha Sai Neelati --- drivers/devfreq/governor_msm_adreno_tz.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/devfreq/governor_msm_adreno_tz.c b/drivers/devfreq/governor_msm_adreno_tz.c index f31089d63e0c..4c010654204c 100644 --- a/drivers/devfreq/governor_msm_adreno_tz.c +++ b/drivers/devfreq/governor_msm_adreno_tz.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2017, 2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -150,6 +150,8 @@ void compute_work_load(struct devfreq_dev_status *stats, struct devfreq_msm_adreno_tz_data *priv, struct devfreq *devfreq) { + u64 busy; + spin_lock(&sample_lock); /* * Keep collecting the stats till the client @@ -157,8 +159,10 @@ void compute_work_load(struct devfreq_dev_status *stats, * is done when the entry is read */ acc_total += stats->total_time; - acc_relative_busy += (stats->busy_time * stats->current_frequency) / - devfreq->profile->freq_table[0]; + busy = (u64)stats->busy_time * stats->current_frequency; + do_div(busy, devfreq->profile->freq_table[0]); + acc_relative_busy += busy; + spin_unlock(&sample_lock); } -- cgit v1.2.3 From ff02bcf175a16132613cf03a8ee56313123aadd0 Mon Sep 17 00:00:00 2001 From: DongJoo Kim Date: Mon, 21 Oct 2019 11:48:00 +0900 Subject: ANDROID: move up spin_unlock_bh() ahead of remove_proc_entry() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It causes BUG because remove_proc_entry may sleep while holding spinlock. BUG: scheduling while atomic: ip6tables-resto/887/0x00000202 [] (wait_for_completion) from [] (proc_entry_rundown+0x74/0xd0) [] (proc_entry_rundown) from [] (remove_proc_entry+0xc0/0x18c) [] (remove_proc_entry) from [] (quota_mt2_destroy+0x88/0xa8) [] (quota_mt2_destroy) from [] (cleanup_entry+0x6c/0xf0) [] (cleanup_entry) from [] (do_replace.constprop.2+0x314/0x438) [] (do_replace.constprop.2) from [] (do_ip6t_set_ctl+0x11c/0x238) [] (do_ip6t_set_ctl) from [] (nf_setsockopt+0xd4/0xf0) [] (nf_setsockopt) from [] (ipv6_setsockopt+0x90/0xb8) [] (ipv6_setsockopt) from [] (rawv6_setsockopt+0x54/0x22c) [] (rawv6_setsockopt) from [] (sock_common_setsockopt+0x28/0x30) [] (sock_common_setsockopt) from [] (SyS_setsockopt+0xb8/0x110) [] (SyS_setsockopt) from [] (ret_fast_syscall+0x0/0x48) This is a fix for an Android specific feature which was imported from unofficial upstream (xtables-addons), which also has the same issue: https://sourceforge.net/p/xtables-addons/xtables-addons/ci/master/tree/extensions/xt_quota2.c#l235 After this change the proc entry may now be removed later, when we're already adding another one, potentially with the same name, this will simply fail during creation, see error path for this at: https://sourceforge.net/p/xtables-addons/xtables-addons/ci/master/tree/extensions/xt_quota2.c#l179 Bug: 143092160 Signed-off-by: Maciej Żenczykowski Signed-off-by: DongJoo Kim Change-Id: I3ff3883738353785f5792c5f06bf6b72985c4c68 --- net/netfilter/xt_quota2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/xt_quota2.c b/net/netfilter/xt_quota2.c index 834594aa0085..8e1e48c121f1 100644 --- a/net/netfilter/xt_quota2.c +++ b/net/netfilter/xt_quota2.c @@ -296,8 +296,8 @@ static void quota_mt2_destroy(const struct xt_mtdtor_param *par) } list_del(&e->list); - remove_proc_entry(e->name, proc_xt_quota); spin_unlock_bh(&counter_list_lock); + remove_proc_entry(e->name, proc_xt_quota); kfree(e); } -- cgit v1.2.3 From 526f5c9b7a68cf9b42ab8c47142569655ef7a579 Mon Sep 17 00:00:00 2001 From: Ram Muthiah Date: Wed, 23 Oct 2019 13:43:45 -0700 Subject: ANDROID: clang: update to 9.0.8 based on r365631c Bug: 139440459 Change-Id: Ia9d339a9e53ace540f37f90c73781e70a643dc40 Signed-off-by: Ram Muthiah --- build.config.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.config.common b/build.config.common index fd58f76a938b..81cbb76e3aef 100644 --- a/build.config.common +++ b/build.config.common @@ -2,7 +2,7 @@ BRANCH=android-4.4-p KERNEL_DIR=common CC=clang -CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r353983c/bin +CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r365631c/bin BUILDTOOLS_PREBUILT_BIN=build/build-tools/path/linux-x86 EXTRA_CMDS='' -- cgit v1.2.3 From 1c9afab264e3cafa461d746e9dcfd3c0487754cb Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Thu, 3 Oct 2019 18:21:07 +0530 Subject: asoc: msm-pcm: Added lock in controls _put() and _get() callback There is race condition around private data used in put() and get() of few mixer ctls with close() callback. Added global mutex lock and code changes to protect such critical section by accessing such lock. Change-Id: I276c2a234cfcbef88b4272b945e5c3f121e8eb32 Signed-off-by: Soumya Managoli --- sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c | 81 ++++++++++++++++++++++++++++++++--- sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h | 1 + 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index a7aab839e6db..fef0792d52bf 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -880,6 +881,14 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream) pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending); + pdata = (struct msm_plat_data *) + dev_get_drvdata(soc_prtd->platform->dev); + if (!pdata) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&pdata->lock); if (prtd->audio_client) { dir = IN; @@ -922,6 +931,7 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream) msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd); kfree(prtd); runtime->private_data = NULL; + mutex_unlock(&pdata->lock); return 0; } @@ -1016,8 +1026,18 @@ static int msm_pcm_capture_close(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; struct msm_audio *prtd = runtime->private_data; int dir = OUT; + struct msm_plat_data *pdata; pr_debug("%s\n", __func__); + + pdata = (struct msm_plat_data *) + dev_get_drvdata(soc_prtd->platform->dev); + if (!pdata) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&pdata->lock); if (prtd->audio_client) { q6asm_cmd(prtd->audio_client, CMD_CLOSE); q6asm_audio_client_buf_free_contiguous(dir, @@ -1029,6 +1049,7 @@ static int msm_pcm_capture_close(struct snd_pcm_substream *substream) SNDRV_PCM_STREAM_CAPTURE); kfree(prtd); runtime->private_data = NULL; + mutex_unlock(&pdata->lock); return 0; } @@ -1197,6 +1218,7 @@ static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, goto done; } + mutex_lock(&pdata->lock); event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data; if ((event_data->event_type < ADSP_STREAM_PP_EVENT) || (event_data->event_type >= ADSP_STREAM_EVENT_MAX)) { @@ -1228,6 +1250,7 @@ static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, pr_err("%s: failed to send stream event cmd, err = %d\n", __func__, ret); done: + mutex_unlock(&pdata->lock); return ret; } @@ -1393,21 +1416,35 @@ static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol, vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; struct msm_audio *prtd; int volume = ucontrol->value.integer.value[0]; + struct snd_soc_pcm_runtime *soc_prtd = NULL; + struct msm_plat_data *pdata = NULL; pr_debug("%s: volume : 0x%x\n", __func__, volume); if (!substream) { - pr_err("%s substream not found\n", __func__); + pr_err("%s: substream not found\n", __func__); return -ENODEV; } - if (!substream->runtime) { - pr_err("%s substream runtime not found\n", __func__); + soc_prtd = substream->private_data; + if (!substream->runtime || !soc_prtd) { + pr_err("%s: substream runtime or private_data not found\n", + __func__); return 0; } + + pdata = (struct msm_plat_data *) + dev_get_drvdata(soc_prtd->platform->dev); + if (!pdata) { + pr_err("%s: pdata not found\n", __func__); + return -ENODEV; + } + + mutex_lock(&pdata->lock); prtd = substream->runtime->private_data; if (prtd) { rc = msm_pcm_set_volume(prtd, volume); prtd->volume = volume; } + mutex_unlock(&pdata->lock); return rc; } @@ -1572,14 +1609,28 @@ static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol, unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); struct snd_pcm_substream *substream; struct msm_audio *prtd; + struct snd_soc_pcm_runtime *rtd = NULL; + struct msm_plat_data *pdata = NULL; pr_debug("%s", __func__); substream = snd_pcm_chmap_substream(info, idx); if (!substream) return -ENODEV; - if (!substream->runtime) + + rtd = substream->private_data; + if (rtd) { + pdata = (struct msm_plat_data *) + dev_get_drvdata(rtd->platform->dev); + if (!pdata) { + pr_err("%s: pdata not found\n", __func__); + return -ENODEV; + } + } + + if (!substream->runtime || !rtd) return 0; + mutex_lock(&pdata->lock); prtd = substream->runtime->private_data; if (prtd) { prtd->set_channel_map = true; @@ -1587,6 +1638,7 @@ static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol, prtd->channel_map[i] = (char)(ucontrol->value.integer.value[i]); } + mutex_unlock(&pdata->lock); return 0; } @@ -1598,16 +1650,30 @@ static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol, unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); struct snd_pcm_substream *substream; struct msm_audio *prtd; + struct snd_soc_pcm_runtime *rtd = NULL; + struct msm_plat_data *pdata = NULL; pr_debug("%s", __func__); substream = snd_pcm_chmap_substream(info, idx); if (!substream) return -ENODEV; + + rtd = substream->private_data; + if (rtd) { + pdata = (struct msm_plat_data *) + dev_get_drvdata(rtd->platform->dev); + if (!pdata) { + pr_err("%s: pdata not found\n", __func__); + return -ENODEV; + } + } + memset(ucontrol->value.integer.value, 0, sizeof(ucontrol->value.integer.value)); - if (!substream->runtime) + if (!substream->runtime || !rtd) return 0; /* no channels set */ + mutex_lock(&pdata->lock); prtd = substream->runtime->private_data; if (prtd && prtd->set_channel_map == true) { @@ -1619,6 +1685,7 @@ static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[i] = 0; } + mutex_unlock(&pdata->lock); return 0; } @@ -2244,6 +2311,7 @@ static int msm_pcm_channel_mixer_cfg_ctl_put(struct snd_kcontrol *kcontrol, chmixer_pspd->output_channel = ucontrol->value.integer.value[3]; chmixer_pspd->port_idx = ucontrol->value.integer.value[4]; + mutex_lock(&pdata->lock); /* cache value and take effect during adm_open stage */ msm_pcm_routing_set_channel_mixer_cfg(fe_id, session_type, @@ -2266,6 +2334,7 @@ static int msm_pcm_channel_mixer_cfg_ctl_put(struct snd_kcontrol *kcontrol, } } done: + mutex_unlock(&pdata->lock); return ret; } @@ -3089,6 +3158,7 @@ static int msm_pcm_probe(struct platform_device *pdev) pr_debug("%s: avs_ver = %d\n", __func__, pdata->avs_ver); + mutex_init(&pdata->lock); dev_set_drvdata(&pdev->dev, pdata); dev_dbg(&pdev->dev, "%s: dev name %s\n", @@ -3102,6 +3172,7 @@ static int msm_pcm_remove(struct platform_device *pdev) struct msm_plat_data *pdata; pdata = dev_get_drvdata(&pdev->dev); + mutex_destroy(&pdata->lock); kfree(pdata); snd_soc_unregister_platform(&pdev->dev); return 0; diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h index a90e9f7d4fc9..f0a96484a03b 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h @@ -127,6 +127,7 @@ struct msm_plat_data { struct snd_pcm *pcm; struct snd_pcm *pcm_device[MSM_FRONTEND_DAI_MM_SIZE]; struct msm_pcm_channel_mixer chmixer_pspd[MSM_FRONTEND_DAI_MM_SIZE][2]; + struct mutex lock; }; #endif /*_MSM_PCM_H*/ -- cgit v1.2.3 From 42ffbf03ec54dc14824d078f36c350b24c217f8d Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Fri, 18 Oct 2019 12:30:18 +0530 Subject: soc: msm-pcm: Add mutex lock to protect prvt data Add mutex lock to protect private data in _put() and get() calls. Change-Id: I92f5a6515b6d1c4ad650a7dcf22a0a231a84dd30 Signed-off-by: Prasad Kumpatla Signed-off-by: Soumya Managoli --- sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c | 13 ++++++- sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c | 56 ++++++++++++++++++++++++++--- sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c | 26 +++++++++++--- 3 files changed, 85 insertions(+), 10 deletions(-) diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c index 2fbefa7b42dc..0add46fb979f 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -177,6 +177,7 @@ static int msm_loopback_session_mute_put(struct snd_kcontrol *kcontrol, goto done; } + mutex_lock(&loopback_session_lock); pr_debug("%s: mute=%d\n", __func__, mute); hfp_tx_mute = mute; for (n = 0; n < LOOPBACK_SESSION_MAX; n++) { @@ -189,6 +190,7 @@ static int msm_loopback_session_mute_put(struct snd_kcontrol *kcontrol, pr_err("%s: Send mute command failed rc=%d\n", __func__, ret); } + mutex_unlock(&loopback_session_lock); done: return ret; } @@ -381,6 +383,8 @@ static void stop_pcm(struct msm_pcm_loopback *pcm) if (pcm->audio_client == NULL) return; + + mutex_lock(&loopback_session_lock); q6asm_cmd(pcm->audio_client, CMD_CLOSE); if (pcm->playback_substream != NULL) { @@ -395,6 +399,7 @@ static void stop_pcm(struct msm_pcm_loopback *pcm) } q6asm_audio_client_free(pcm->audio_client); pcm->audio_client = NULL; + mutex_unlock(&loopback_session_lock); } static int msm_pcm_close(struct snd_pcm_substream *substream) @@ -545,6 +550,7 @@ static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol, int volume = ucontrol->value.integer.value[0]; pr_debug("%s: volume : 0x%x\n", __func__, volume); + mutex_lock(&loopback_session_lock); if ((!substream) || (!substream->runtime)) { pr_err("%s substream or runtime not found\n", __func__); rc = -ENODEV; @@ -553,9 +559,11 @@ static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol, prtd = substream->runtime->private_data; if (!prtd) { rc = -ENODEV; + mutex_unlock(&loopback_session_lock); goto exit; } rc = pcm_loopback_set_volume(prtd, volume); + mutex_unlock(&loopback_session_lock); exit: return rc; @@ -576,12 +584,15 @@ static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol, rc = -ENODEV; goto exit; } + mutex_lock(&loopback_session_lock); prtd = substream->runtime->private_data; if (!prtd) { rc = -ENODEV; + mutex_unlock(&loopback_session_lock); goto exit; } ucontrol->value.integer.value[0] = prtd->volume; + mutex_unlock(&loopback_session_lock); exit: return rc; diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c index ce9091b1ca16..5c78349f8d70 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2017, 2019 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -578,6 +579,7 @@ static int msm_pcm_prepare(struct snd_pcm_substream *substream) static int msm_pcm_close(struct snd_pcm_substream *substream) { + struct msm_plat_data *pdata = NULL; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; struct msm_audio *prtd = runtime->private_data; @@ -586,6 +588,20 @@ static int msm_pcm_close(struct snd_pcm_substream *substream) int dir = 0; int ret = 0; + if (!soc_prtd) { + pr_debug("%s private_data not found\n", + __func__); + return 0; + } + + pdata = (struct msm_plat_data *) + dev_get_drvdata(soc_prtd->platform->dev); + if (!pdata) { + pr_err("%s: pdata not found\n", __func__); + return -ENODEV; + } + + mutex_lock(&pdata->lock); if (ac) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) dir = IN; @@ -620,6 +636,7 @@ static int msm_pcm_close(struct snd_pcm_substream *substream) SNDRV_PCM_STREAM_CAPTURE); kfree(prtd); runtime->private_data = NULL; + mutex_unlock(&pdata->lock); return 0; } @@ -644,8 +661,10 @@ static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol); + struct msm_plat_data *pdata = NULL; struct snd_pcm_substream *substream = vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + struct snd_soc_pcm_runtime *soc_prtd = NULL; struct msm_audio *prtd; pr_debug("%s\n", __func__); @@ -653,13 +672,24 @@ static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol, pr_err("%s substream not found\n", __func__); return -ENODEV; } - if (!substream->runtime) { - pr_err("%s substream runtime not found\n", __func__); + soc_prtd = substream->private_data; + if (!substream->runtime || !soc_prtd) { + pr_debug("%s substream runtime or private_data not found\n", + __func__); return 0; } + + pdata = (struct msm_plat_data *) + dev_get_drvdata(soc_prtd->platform->dev); + if (!pdata) { + pr_err("%s: pdata not found\n", __func__); + return -ENODEV; + } + mutex_lock(&pdata->lock); prtd = substream->runtime->private_data; if (prtd) ucontrol->value.integer.value[0] = prtd->volume; + mutex_unlock(&pdata->lock); return 0; } @@ -668,8 +698,10 @@ static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol, { int rc = 0; struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol); + struct msm_plat_data *pdata = NULL; struct snd_pcm_substream *substream = vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + struct snd_soc_pcm_runtime *soc_prtd = NULL; struct msm_audio *prtd; int volume = ucontrol->value.integer.value[0]; @@ -678,15 +710,26 @@ static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol, pr_err("%s substream not found\n", __func__); return -ENODEV; } - if (!substream->runtime) { - pr_err("%s substream runtime not found\n", __func__); + soc_prtd = substream->private_data; + if (!substream->runtime || !soc_prtd) { + pr_err("%s substream runtime or private_data not found\n", + __func__); return 0; } + + pdata = (struct msm_plat_data *) + dev_get_drvdata(soc_prtd->platform->dev); + if (!pdata) { + pr_err("%s: pdata not found\n", __func__); + return -ENODEV; + } + mutex_lock(&pdata->lock); prtd = substream->runtime->private_data; if (prtd) { rc = msm_pcm_set_volume(prtd, volume); prtd->volume = volume; } + mutex_unlock(&pdata->lock); return rc; } @@ -1233,6 +1276,8 @@ static int msm_pcm_probe(struct platform_device *pdev) pdata->perf_mode = perf_mode; + mutex_init(&pdata->lock); + dev_set_drvdata(&pdev->dev, pdata); dev_dbg(&pdev->dev, "%s: dev name %s\n", @@ -1253,6 +1298,7 @@ static int msm_pcm_remove(struct platform_device *pdev) dev_dbg(&pdev->dev, "Pull mode remove\n"); pdata = dev_get_drvdata(&pdev->dev); + mutex_destroy(&pdata->lock); devm_kfree(&pdev->dev, pdata); snd_soc_unregister_platform(&pdev->dev); return 0; diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c index fef0792d52bf..b2154620c8ae 100644 --- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c @@ -1188,10 +1188,10 @@ static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, if (!pdata) { pr_err("%s pdata is NULL\n", __func__); - ret = -ENODEV; - goto done; + return -ENODEV; } + mutex_lock(&pdata->lock); substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; if (!substream) { pr_err("%s substream not found\n", __func__); @@ -1388,8 +1388,10 @@ static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol); + struct msm_plat_data *pdata = NULL; struct snd_pcm_substream *substream = vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + struct snd_soc_pcm_runtime *soc_prtd = NULL; struct msm_audio *prtd; pr_debug("%s\n", __func__); @@ -1397,13 +1399,25 @@ static int msm_pcm_volume_ctl_get(struct snd_kcontrol *kcontrol, pr_err("%s substream not found\n", __func__); return -ENODEV; } - if (!substream->runtime) { - pr_err("%s substream runtime not found\n", __func__); + soc_prtd = substream->private_data; + if (!substream->runtime || !soc_prtd) { + pr_debug("%s substream runtime or private_data not found\n", + __func__); return 0; } + + pdata = (struct msm_plat_data *) + dev_get_drvdata(soc_prtd->platform->dev); + if (!pdata) { + pr_err("%s: pdata not found\n", __func__); + return -ENODEV; + } + + mutex_lock(&pdata->lock); prtd = substream->runtime->private_data; if (prtd) ucontrol->value.integer.value[0] = prtd->volume; + mutex_unlock(&pdata->lock); return 0; } @@ -1502,9 +1516,11 @@ static int msm_pcm_compress_ctl_get(struct snd_kcontrol *kcontrol, pr_err("%s substream runtime not found\n", __func__); return 0; } + mutex_lock(&pdata->lock); prtd = substream->runtime->private_data; if (prtd) ucontrol->value.integer.value[0] = prtd->compress_enable; + mutex_unlock(&pdata->lock); return 0; } @@ -1533,12 +1549,14 @@ static int msm_pcm_compress_ctl_put(struct snd_kcontrol *kcontrol, pr_err("%s substream runtime not found\n", __func__); return 0; } + mutex_lock(&pdata->lock); prtd = substream->runtime->private_data; if (prtd) { pr_debug("%s: setting compress flag to 0x%x\n", __func__, compress); prtd->compress_enable = compress; } + mutex_unlock(&pdata->lock); return rc; } -- cgit v1.2.3 From 13d43fca0c03920648028fd560fb9e575c8f878d Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Fri, 2 Aug 2019 17:53:22 +0530 Subject: drm/msm/hdmi-staging: Fix Buffer Overflow This change is done to check the size of input before doing the buffer copy. Change-Id: I01f8b1f3c3b6e920f186f5f90ea9707bb25bcbbc Signed-off-by: Rahul Sharma --- drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c index 5a9e56b58158..d755ba959c20 100644 --- a/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c +++ b/drivers/gpu/drm/msm/hdmi-staging/sde_hdmi.c @@ -78,7 +78,12 @@ static ssize_t _sde_hdmi_debugfs_dump_info_read(struct file *file, if (!buf) return -ENOMEM; - len += snprintf(buf, SZ_4K, "name = %s\n", display->name); + len += snprintf(buf, SZ_1K, "name = %s\n", display->name); + + if (len > count) { + kfree(buf); + return -ENOMEM; + } if (copy_to_user(buff, buf, len)) { kfree(buf); -- cgit v1.2.3 From fdc5506932b6a6ffad1ea078e88b28ce0d2ff6ba Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Fri, 18 Oct 2019 07:43:21 -0400 Subject: rtlwifi: Fix potential overflow on P2P code commit 8c55dedb795be8ec0cf488f98c03a1c2176f7fb1 upstream. Nicolas Waisman noticed that even though noa_len is checked for a compatible length it's still possible to overrun the buffers of p2pinfo since there's no check on the upper bound of noa_num. Bound noa_num against P2P_MAX_NOA_NUM. Bug: 142967706 Reported-by: Nicolas Waisman Signed-off-by: Laura Abbott Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman Change-Id: I90a9b285feb50b6b5c30e242756d47848902b634 --- drivers/net/wireless/realtek/rtlwifi/ps.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c index 626ff300352b..1fd3f22796a7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/ps.c +++ b/drivers/net/wireless/realtek/rtlwifi/ps.c @@ -781,6 +781,9 @@ static void rtl_p2p_noa_ie(struct ieee80211_hw *hw, void *data, return; } else { noa_num = (noa_len - 2) / 13; + if (noa_num > P2P_MAX_NOA_NUM) + noa_num = P2P_MAX_NOA_NUM; + } noa_index = ie[3]; if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == @@ -875,6 +878,9 @@ static void rtl_p2p_action_ie(struct ieee80211_hw *hw, void *data, return; } else { noa_num = (noa_len - 2) / 13; + if (noa_num > P2P_MAX_NOA_NUM) + noa_num = P2P_MAX_NOA_NUM; + } noa_index = ie[3]; if (rtlpriv->psc.p2p_ps_info.p2p_ps_mode == -- cgit v1.2.3 From aa64c3afcb8c2185e1ed461cb8cee6f784cee1b1 Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Wed, 18 Sep 2019 12:20:38 +0800 Subject: scsi: ufs: skip shutdown if hba is not powered [ Upstream commit f51913eef23f74c3bd07899dc7f1ed6df9e521d8 ] In some cases, hba may go through shutdown flow without successful initialization and then make system hang. For example, if ufshcd_change_power_mode() gets error and leads to ufshcd_hba_exit() to release resources of the host, future shutdown flow may hang the system since the host register will be accessed in unpowered state. To solve this issue, simply add checking to skip shutdown for above kind of situation. Link: https://lore.kernel.org/r/1568780438-28753-1-git-send-email-stanley.chu@mediatek.com Signed-off-by: Stanley Chu Acked-by: Bean Huo Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/ufs/ufshcd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index fd8bbd2b5d0e..504d36796152 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5371,6 +5371,9 @@ int ufshcd_shutdown(struct ufs_hba *hba) { int ret = 0; + if (!hba->is_powered) + goto out; + if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba)) goto out; -- cgit v1.2.3 From b0ba41e0a97778473e15487a4620c205a92dafb6 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Sat, 7 Sep 2019 09:07:30 +0800 Subject: scsi: megaraid: disable device when probe failed after enabled device [ Upstream commit 70054aa39a013fa52eff432f2223b8bd5c0048f8 ] For pci device, need to disable device when probe failed after enabled device. Link: https://lore.kernel.org/r/1567818450-173315-1-git-send-email-chenxiang66@hisilicon.com Signed-off-by: Xiang Chen Reviewed-by: John Garry Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/megaraid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 19bffe0b2cc0..2cbfec6a7466 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4219,11 +4219,11 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) */ if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ && pdev->subsystem_device == 0xC000) - return -ENODEV; + goto out_disable_device; /* Now check the magic signature byte */ pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic); if (magic != HBA_SIGNATURE_471 && magic != HBA_SIGNATURE) - return -ENODEV; + goto out_disable_device; /* Ok it is probably a megaraid */ } -- cgit v1.2.3 From 36f88520f1e9024b1fb3ac69fef6fc14d1079ef1 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Thu, 12 Sep 2019 11:09:06 -0700 Subject: scsi: qla2xxx: Fix unbound sleep in fcport delete path. [ Upstream commit c3b6a1d397420a0fdd97af2f06abfb78adc370df ] There are instances, though rare, where a LOGO request cannot be sent out and the thread in free session done can wait indefinitely. Fix this by putting an upper bound to sleep. Link: https://lore.kernel.org/r/20190912180918.6436-3-hmadhani@marvell.com Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/qla2xxx/qla_target.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 824e27eec7a1..6c4f54aa60df 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -437,6 +437,7 @@ static void qlt_free_session_done(struct work_struct *work) if (logout_started) { bool traced = false; + u16 cnt = 0; while (!ACCESS_ONCE(sess->logout_completed)) { if (!traced) { @@ -446,6 +447,9 @@ static void qlt_free_session_done(struct work_struct *work) traced = true; } msleep(100); + cnt++; + if (cnt > 200) + break; } ql_dbg(ql_dbg_tgt_mgt, vha, 0xf087, -- cgit v1.2.3 From d08c1d7490870c436f4d6caef29312c1b846602c Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 24 Sep 2019 09:25:52 -0700 Subject: ARM: OMAP2+: Fix missing reset done flag for am3 and am43 [ Upstream commit 8ad8041b98c665b6147e607b749586d6e20ba73a ] For ti,sysc-omap4 compatible devices with no sysstatus register, we do have reset done status available in the SOFTRESET bit that clears when the reset is done. This is documented for example in am437x TRM for DMTIMER_TIOCP_CFG register. The am335x TRM just says that SOFTRESET bit value 1 means reset is ongoing, but it behaves the same way clearing after reset is done. With the ti-sysc driver handling this automatically based on no sysstatus register defined, we see warnings if SYSC_HAS_RESET_STATUS is missing in the legacy platform data: ti-sysc 48042000.target-module: sysc_flags 00000222 != 00000022 ti-sysc 48044000.target-module: sysc_flags 00000222 != 00000022 ti-sysc 48046000.target-module: sysc_flags 00000222 != 00000022 ... Let's fix these warnings by adding SYSC_HAS_RESET_STATUS. Let's also remove the useless parentheses while at it. If it turns out we do have ti,sysc-omap4 compatible devices without a working SOFTRESET bit we can set up additional quirk handling for it. Signed-off-by: Tony Lindgren Signed-off-by: Sasha Levin --- arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c index b31ad596be79..6b09debcf484 100644 --- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c @@ -1020,7 +1020,8 @@ static struct omap_hwmod_class_sysconfig am33xx_timer_sysc = { .rev_offs = 0x0000, .sysc_offs = 0x0010, .syss_offs = 0x0014, - .sysc_flags = (SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET), + .sysc_flags = SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET | + SYSC_HAS_RESET_STATUS, .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART | SIDLE_SMART_WKUP), .sysc_fields = &omap_hwmod_sysc_type2, -- cgit v1.2.3 From eb5aa18fbb9cfd363cddea75d4c9c091d879776f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 30 Sep 2019 11:54:50 +0300 Subject: ARM: dts: am4372: Set memory bandwidth limit for DISPC [ Upstream commit f90ec6cdf674248dcad85bf9af6e064bf472b841 ] Set memory bandwidth limit to filter out resolutions above 720p@60Hz to avoid underflow errors due to the bandwidth needs of higher resolutions. am43xx can not provide enough bandwidth to DISPC to correctly handle 'high' resolutions. Signed-off-by: Peter Ujfalusi Signed-off-by: Tomi Valkeinen Signed-off-by: Tony Lindgren Signed-off-by: Sasha Levin --- arch/arm/boot/dts/am4372.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index 3ef1d5a26389..3bb5254a227a 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -1002,6 +1002,8 @@ ti,hwmods = "dss_dispc"; clocks = <&disp_clk>; clock-names = "fck"; + + max-memory-bandwidth = <230000000>; }; rfbi: rfbi@4832a800 { -- cgit v1.2.3 From 4f7a59b56a61018a3e76ef181190e94cdbb99565 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Thu, 26 Sep 2019 16:16:50 +0800 Subject: nl80211: fix null pointer dereference [ Upstream commit b501426cf86e70649c983c52f4c823b3c40d72a3 ] If the interface is not in MESH mode, the command 'iw wlanx mpath del' will cause kernel panic. The root cause is null pointer access in mpp_flush_by_proxy(), as the pointer 'sdata->u.mesh.mpp_paths' is NULL for non MESH interface. Unable to handle kernel NULL pointer dereference at virtual address 00000068 [...] PC is at _raw_spin_lock_bh+0x20/0x5c LR is at mesh_path_del+0x1c/0x17c [mac80211] [...] Process iw (pid: 4537, stack limit = 0xd83e0238) [...] [] (_raw_spin_lock_bh) from [] (mesh_path_del+0x1c/0x17c [mac80211]) [] (mesh_path_del [mac80211]) from [] (extack_doit+0x20/0x68 [compat]) [] (extack_doit [compat]) from [] (genl_rcv_msg+0x274/0x30c) [] (genl_rcv_msg) from [] (netlink_rcv_skb+0x58/0xac) [] (netlink_rcv_skb) from [] (genl_rcv+0x20/0x34) [] (genl_rcv) from [] (netlink_unicast+0x11c/0x204) [] (netlink_unicast) from [] (netlink_sendmsg+0x30c/0x370) [] (netlink_sendmsg) from [] (sock_sendmsg+0x70/0x84) [] (sock_sendmsg) from [] (___sys_sendmsg.part.3+0x188/0x228) [] (___sys_sendmsg.part.3) from [] (__sys_sendmsg+0x4c/0x70) [] (__sys_sendmsg) from [] (ret_fast_syscall+0x0/0x44) Code: e2822c02 e2822001 e5832004 f590f000 (e1902f9f) ---[ end trace bbd717600f8f884d ]--- Signed-off-by: Miaoqing Pan Link: https://lore.kernel.org/r/1569485810-761-1-git-send-email-miaoqing@codeaurora.org [trim useless data from commit message] Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/wireless/nl80211.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 95c8e682b491..2023802b6c77 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4816,6 +4816,9 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->del_mpath) return -EOPNOTSUPP; + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) + return -EOPNOTSUPP; + return rdev_del_mpath(rdev, dev, dst); } -- cgit v1.2.3 From ebc93dc0b776528ca2ad02c8cc04a556897d109f Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 10 Sep 2019 05:59:07 +0200 Subject: mips: Loongson: Fix the link time qualifier of 'serial_exit()' [ Upstream commit 25b69a889b638b0b7e51e2c4fe717a66bec0e566 ] 'exit' functions should be marked as __exit, not __init. Fixes: 85cc028817ef ("mips: make loongsoon serial driver explicitly modular") Signed-off-by: Christophe JAILLET Signed-off-by: Paul Burton Cc: chenhc@lemote.com Cc: ralf@linux-mips.org Cc: jhogan@kernel.org Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: kernel-janitors@vger.kernel.org Signed-off-by: Sasha Levin --- arch/mips/loongson64/common/serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/loongson64/common/serial.c b/arch/mips/loongson64/common/serial.c index ffefc1cb2612..98c3a7feb10f 100644 --- a/arch/mips/loongson64/common/serial.c +++ b/arch/mips/loongson64/common/serial.c @@ -110,7 +110,7 @@ static int __init serial_init(void) } module_init(serial_init); -static void __init serial_exit(void) +static void __exit serial_exit(void) { platform_device_unregister(&uart8250_device); } -- cgit v1.2.3 From 74b2bee56dc05255bbeb520c3619580eaf8a530f Mon Sep 17 00:00:00 2001 From: Yizhuo Date: Tue, 1 Oct 2019 13:24:39 -0700 Subject: net: hisilicon: Fix usage of uninitialized variable in function mdio_sc_cfg_reg_write() [ Upstream commit 53de429f4e88f538f7a8ec2b18be8c0cd9b2c8e1 ] In function mdio_sc_cfg_reg_write(), variable "reg_value" could be uninitialized if regmap_read() fails. However, "reg_value" is used to decide the control flow later in the if statement, which is potentially unsafe. Signed-off-by: Yizhuo Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/hisilicon/hns_mdio.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c b/drivers/net/ethernet/hisilicon/hns_mdio.c index 6ff13c559e52..09fcc821b7da 100644 --- a/drivers/net/ethernet/hisilicon/hns_mdio.c +++ b/drivers/net/ethernet/hisilicon/hns_mdio.c @@ -156,11 +156,15 @@ static int mdio_sc_cfg_reg_write(struct hns_mdio_device *mdio_dev, { u32 time_cnt; u32 reg_value; + int ret; regmap_write(mdio_dev->subctrl_vbase, cfg_reg, set_val); for (time_cnt = MDIO_TIMEOUT; time_cnt; time_cnt--) { - regmap_read(mdio_dev->subctrl_vbase, st_reg, ®_value); + ret = regmap_read(mdio_dev->subctrl_vbase, st_reg, ®_value); + if (ret) + return ret; + reg_value &= st_msk; if ((!!check_st) == (!!reg_value)) break; -- cgit v1.2.3 From 27add8a99692aa0fb6452c35e49db4ae55feb25f Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 27 Sep 2019 16:30:27 -0700 Subject: namespace: fix namespace.pl script to support relative paths [ Upstream commit 82fdd12b95727640c9a8233c09d602e4518e71f7 ] The namespace.pl script does not work properly if objtree is not set to an absolute path. The do_nm function is run from within the find function, which changes directories. Because of this, appending objtree, $File::Find::dir, and $source, will return a path which is not valid from the current directory. This used to work when objtree was set to an absolute path when using "make namespacecheck". It appears to have not worked when calling ./scripts/namespace.pl directly. This behavior was changed in 7e1c04779efd ("kbuild: Use relative path for $(objtree)", 2014-05-14) Rather than fixing the Makefile to set objtree to an absolute path, just fix namespace.pl to work when srctree and objtree are relative. Also fix the script to use an absolute path for these by default. Use the File::Spec module for this purpose. It's been part of perl 5 since 5.005. The curdir() function is used to get the current directory when the objtree and srctree aren't set in the environment. rel2abs() is used to convert possibly relative objtree and srctree environment variables to absolute paths. Finally, the catfile() function is used instead of string appending paths together, since this is more robust when joining paths together. Signed-off-by: Jacob Keller Acked-by: Randy Dunlap Tested-by: Randy Dunlap Signed-off-by: Masahiro Yamada Signed-off-by: Sasha Levin --- scripts/namespace.pl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/namespace.pl b/scripts/namespace.pl index a71be6b7cdec..9a2a32ce8a3b 100755 --- a/scripts/namespace.pl +++ b/scripts/namespace.pl @@ -65,13 +65,14 @@ require 5; # at least perl 5 use strict; use File::Find; +use File::Spec; my $nm = ($ENV{'NM'} || "nm") . " -p"; my $objdump = ($ENV{'OBJDUMP'} || "objdump") . " -s -j .comment"; -my $srctree = ""; -my $objtree = ""; -$srctree = "$ENV{'srctree'}/" if (exists($ENV{'srctree'})); -$objtree = "$ENV{'objtree'}/" if (exists($ENV{'objtree'})); +my $srctree = File::Spec->curdir(); +my $objtree = File::Spec->curdir(); +$srctree = File::Spec->rel2abs($ENV{'srctree'}) if (exists($ENV{'srctree'})); +$objtree = File::Spec->rel2abs($ENV{'objtree'}) if (exists($ENV{'objtree'})); if ($#ARGV != -1) { print STDERR "usage: $0 takes no parameters\n"; @@ -229,9 +230,9 @@ sub do_nm } ($source = $basename) =~ s/\.o$//; if (-e "$source.c" || -e "$source.S") { - $source = "$objtree$File::Find::dir/$source"; + $source = File::Spec->catfile($objtree, $File::Find::dir, $source) } else { - $source = "$srctree$File::Find::dir/$source"; + $source = File::Spec->catfile($srctree, $File::Find::dir, $source) } if (! -e "$source.c" && ! -e "$source.S") { # No obvious source, exclude the object if it is conglomerate -- cgit v1.2.3 From 896bb98754dca4ee08e20a6eb2457f1710258ee8 Mon Sep 17 00:00:00 2001 From: Alessio Balsini Date: Wed, 23 Oct 2019 18:17:36 +0100 Subject: loop: Add LOOP_SET_DIRECT_IO to compat ioctl [ Upstream commit fdbe4eeeb1aac219b14f10c0ed31ae5d1123e9b8 ] Enabling Direct I/O with loop devices helps reducing memory usage by avoiding double caching. 32 bit applications running on 64 bits systems are currently not able to request direct I/O because is missing from the lo_compat_ioctl. This patch fixes the compatibility issue mentioned above by exporting LOOP_SET_DIRECT_IO as additional lo_compat_ioctl() entry. The input argument for this ioctl is a single long converted to a 1-bit boolean, so compatibility is preserved. Cc: Jens Axboe Signed-off-by: Alessio Balsini Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/block/loop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index da3902ac16c8..8aadd4d0c3a8 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1557,6 +1557,7 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode, arg = (unsigned long) compat_ptr(arg); case LOOP_SET_FD: case LOOP_CHANGE_FD: + case LOOP_SET_DIRECT_IO: err = lo_ioctl(bdev, mode, cmd, arg); break; default: -- cgit v1.2.3 From 571e5f93e7566e8178b928881b80f4a9d245fb65 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 15 Oct 2019 10:45:47 -0700 Subject: net: bcmgenet: Fix RGMII_MODE_EN value for GENET v1/2/3 [ Upstream commit efb86fede98cdc70b674692ff617b1162f642c49 ] The RGMII_MODE_EN bit value was 0 for GENET versions 1 through 3, and became 6 for GENET v4 and above, account for that difference. Fixes: aa09677cba42 ("net: bcmgenet: add MDIO routines") Signed-off-by: Florian Fainelli Acked-by: Doug Berger Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 1 + drivers/net/ethernet/broadcom/genet/bcmmii.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index ce20bc939b38..e651845c6605 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -362,6 +362,7 @@ struct bcmgenet_mib_counters { #define EXT_ENERGY_DET_MASK (1 << 12) #define EXT_RGMII_OOB_CTRL 0x0C +#define RGMII_MODE_EN_V123 (1 << 0) #define RGMII_LINK (1 << 4) #define OOB_DISABLE (1 << 5) #define RGMII_MODE_EN (1 << 6) diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 0565efad6e6e..01e6e6a36b9c 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -328,7 +328,11 @@ int bcmgenet_mii_config(struct net_device *dev) */ if (priv->ext_phy) { reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL); - reg |= RGMII_MODE_EN | id_mode_dis; + reg |= id_mode_dis; + if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv)) + reg |= RGMII_MODE_EN_V123; + else + reg |= RGMII_MODE_EN; bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL); } -- cgit v1.2.3 From 0ed0978c29dbec456efdab4aa2f463799d1886ae Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 11 Oct 2019 12:53:49 -0700 Subject: net: bcmgenet: Set phydev->dev_flags only for internal PHYs [ Upstream commit 92696286f3bb37ba50e4bd8d1beb24afb759a799 ] phydev->dev_flags is entirely dependent on the PHY device driver which is going to be used, setting the internal GENET PHY revision in those bits only makes sense when drivers/net/phy/bcm7xxx.c is the PHY driver being used. Fixes: 487320c54143 ("net: bcmgenet: communicate integrated PHY revision to PHY driver") Signed-off-by: Florian Fainelli Acked-by: Doug Berger Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/genet/bcmmii.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 01e6e6a36b9c..3ad016f500b5 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -346,11 +346,12 @@ int bcmgenet_mii_probe(struct net_device *dev) struct bcmgenet_priv *priv = netdev_priv(dev); struct device_node *dn = priv->pdev->dev.of_node; struct phy_device *phydev; - u32 phy_flags; + u32 phy_flags = 0; int ret; /* Communicate the integrated PHY revision */ - phy_flags = priv->gphy_rev; + if (priv->internal_phy) + phy_flags = priv->gphy_rev; /* Initialize link state variables that bcmgenet_mii_setup() uses */ priv->old_link = -1; -- cgit v1.2.3 From 9befdc6645ac7ac16c5c72b3e608ea730efed602 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Tue, 15 Oct 2019 15:24:38 +0800 Subject: sctp: change sctp_prot .no_autobind with true [ Upstream commit 63dfb7938b13fa2c2fbcb45f34d065769eb09414 ] syzbot reported a memory leak: BUG: memory leak, unreferenced object 0xffff888120b3d380 (size 64): backtrace: [...] slab_alloc mm/slab.c:3319 [inline] [...] kmem_cache_alloc+0x13f/0x2c0 mm/slab.c:3483 [...] sctp_bucket_create net/sctp/socket.c:8523 [inline] [...] sctp_get_port_local+0x189/0x5a0 net/sctp/socket.c:8270 [...] sctp_do_bind+0xcc/0x200 net/sctp/socket.c:402 [...] sctp_bindx_add+0x4b/0xd0 net/sctp/socket.c:497 [...] sctp_setsockopt_bindx+0x156/0x1b0 net/sctp/socket.c:1022 [...] sctp_setsockopt net/sctp/socket.c:4641 [inline] [...] sctp_setsockopt+0xaea/0x2dc0 net/sctp/socket.c:4611 [...] sock_common_setsockopt+0x38/0x50 net/core/sock.c:3147 [...] __sys_setsockopt+0x10f/0x220 net/socket.c:2084 [...] __do_sys_setsockopt net/socket.c:2100 [inline] It was caused by when sending msgs without binding a port, in the path: inet_sendmsg() -> inet_send_prepare() -> inet_autobind() -> .get_port/sctp_get_port(), sp->bind_hash will be set while bp->port is not. Later when binding another port by sctp_setsockopt_bindx(), a new bucket will be created as bp->port is not set. sctp's autobind is supposed to call sctp_autobind() where it does all things including setting bp->port. Since sctp_autobind() is called in sctp_sendmsg() if the sk is not yet bound, it should have skipped the auto bind. THis patch is to avoid calling inet_autobind() in inet_send_prepare() by changing sctp_prot .no_autobind with true, also remove the unused .get_port. Reported-by: syzbot+d44f7bbebdea49dbc84a@syzkaller.appspotmail.com Signed-off-by: Xin Long Acked-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 53f1b33bca4e..191fd251e8a0 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -7443,7 +7443,7 @@ struct proto sctp_prot = { .backlog_rcv = sctp_backlog_rcv, .hash = sctp_hash, .unhash = sctp_unhash, - .get_port = sctp_get_port, + .no_autobind = true, .obj_size = sizeof(struct sctp_sock), .sysctl_mem = sysctl_sctp_mem, .sysctl_rmem = sysctl_sctp_rmem, @@ -7482,7 +7482,7 @@ struct proto sctpv6_prot = { .backlog_rcv = sctp_backlog_rcv, .hash = sctp_hash, .unhash = sctp_unhash, - .get_port = sctp_get_port, + .no_autobind = true, .obj_size = sizeof(struct sctp6_sock), .sysctl_mem = sysctl_sctp_mem, .sysctl_rmem = sysctl_sctp_rmem, -- cgit v1.2.3 From ca0cd16becccb44b724ad35e523d820b40a14599 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 14 Oct 2019 11:22:30 -0700 Subject: net: avoid potential infinite loop in tc_ctl_action() [ Upstream commit 39f13ea2f61b439ebe0060393e9c39925c9ee28c ] tc_ctl_action() has the ability to loop forever if tcf_action_add() returns -EAGAIN. This special case has been done in case a module needed to be loaded, but it turns out that tcf_add_notify() could also return -EAGAIN if the socket sk_rcvbuf limit is hit. We need to separate the two cases, and only loop for the module loading case. While we are at it, add a limit of 10 attempts since unbounded loops are always scary. syzbot repro was something like : socket(PF_NETLINK, SOCK_RAW|SOCK_NONBLOCK, NETLINK_ROUTE) = 3 write(3, ..., 38) = 38 setsockopt(3, SOL_SOCKET, SO_RCVBUF, [0], 4) = 0 sendmsg(3, {msg_name(0)=NULL, msg_iov(1)=[{..., 388}], msg_controllen=0, msg_flags=0x10}, ...) NMI backtrace for cpu 0 CPU: 0 PID: 1054 Comm: khungtaskd Not tainted 5.4.0-rc1+ #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x172/0x1f0 lib/dump_stack.c:113 nmi_cpu_backtrace.cold+0x70/0xb2 lib/nmi_backtrace.c:101 nmi_trigger_cpumask_backtrace+0x23b/0x28b lib/nmi_backtrace.c:62 arch_trigger_cpumask_backtrace+0x14/0x20 arch/x86/kernel/apic/hw_nmi.c:38 trigger_all_cpu_backtrace include/linux/nmi.h:146 [inline] check_hung_uninterruptible_tasks kernel/hung_task.c:205 [inline] watchdog+0x9d0/0xef0 kernel/hung_task.c:289 kthread+0x361/0x430 kernel/kthread.c:255 ret_from_fork+0x24/0x30 arch/x86/entry/entry_64.S:352 Sending NMI from CPU 0 to CPUs 1: NMI backtrace for cpu 1 CPU: 1 PID: 8859 Comm: syz-executor910 Not tainted 5.4.0-rc1+ #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:arch_local_save_flags arch/x86/include/asm/paravirt.h:751 [inline] RIP: 0010:lockdep_hardirqs_off+0x1df/0x2e0 kernel/locking/lockdep.c:3453 Code: 5c 08 00 00 5b 41 5c 41 5d 5d c3 48 c7 c0 58 1d f3 88 48 ba 00 00 00 00 00 fc ff df 48 c1 e8 03 80 3c 10 00 0f 85 d3 00 00 00 <48> 83 3d 21 9e 99 07 00 0f 84 b9 00 00 00 9c 58 0f 1f 44 00 00 f6 RSP: 0018:ffff8880a6f3f1b8 EFLAGS: 00000046 RAX: 1ffffffff11e63ab RBX: ffff88808c9c6080 RCX: 0000000000000000 RDX: dffffc0000000000 RSI: 0000000000000000 RDI: ffff88808c9c6914 RBP: ffff8880a6f3f1d0 R08: ffff88808c9c6080 R09: fffffbfff16be5d1 R10: fffffbfff16be5d0 R11: 0000000000000003 R12: ffffffff8746591f R13: ffff88808c9c6080 R14: ffffffff8746591f R15: 0000000000000003 FS: 00000000011e4880(0000) GS:ffff8880ae900000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffffffffff600400 CR3: 00000000a8920000 CR4: 00000000001406e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: trace_hardirqs_off+0x62/0x240 kernel/trace/trace_preemptirq.c:45 __raw_spin_lock_irqsave include/linux/spinlock_api_smp.h:108 [inline] _raw_spin_lock_irqsave+0x6f/0xcd kernel/locking/spinlock.c:159 __wake_up_common_lock+0xc8/0x150 kernel/sched/wait.c:122 __wake_up+0xe/0x10 kernel/sched/wait.c:142 netlink_unlock_table net/netlink/af_netlink.c:466 [inline] netlink_unlock_table net/netlink/af_netlink.c:463 [inline] netlink_broadcast_filtered+0x705/0xb80 net/netlink/af_netlink.c:1514 netlink_broadcast+0x3a/0x50 net/netlink/af_netlink.c:1534 rtnetlink_send+0xdd/0x110 net/core/rtnetlink.c:714 tcf_add_notify net/sched/act_api.c:1343 [inline] tcf_action_add+0x243/0x370 net/sched/act_api.c:1362 tc_ctl_action+0x3b5/0x4bc net/sched/act_api.c:1410 rtnetlink_rcv_msg+0x463/0xb00 net/core/rtnetlink.c:5386 netlink_rcv_skb+0x177/0x450 net/netlink/af_netlink.c:2477 rtnetlink_rcv+0x1d/0x30 net/core/rtnetlink.c:5404 netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline] netlink_unicast+0x531/0x710 net/netlink/af_netlink.c:1328 netlink_sendmsg+0x8a5/0xd60 net/netlink/af_netlink.c:1917 sock_sendmsg_nosec net/socket.c:637 [inline] sock_sendmsg+0xd7/0x130 net/socket.c:657 ___sys_sendmsg+0x803/0x920 net/socket.c:2311 __sys_sendmsg+0x105/0x1d0 net/socket.c:2356 __do_sys_sendmsg net/socket.c:2365 [inline] __se_sys_sendmsg net/socket.c:2363 [inline] __x64_sys_sendmsg+0x78/0xb0 net/socket.c:2363 do_syscall_64+0xfa/0x760 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x440939 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Reported-by: syzbot+cf0adbb9c28c8866c788@syzkaller.appspotmail.com Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_api.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index f44fea22d69c..b3a165cb63ee 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -946,10 +946,15 @@ static int tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n, u32 portid, int ovr) { - int ret = 0; + int loop, ret; LIST_HEAD(actions); - ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions); + for (loop = 0; loop < 10; loop++) { + ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions); + if (ret != -EAGAIN) + break; + } + if (ret) goto done; @@ -992,10 +997,7 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n) */ if (n->nlmsg_flags & NLM_F_REPLACE) ovr = 1; -replay: ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, portid, ovr); - if (ret == -EAGAIN) - goto replay; break; case RTM_DELACTION: ret = tca_action_gd(net, tca[TCA_ACT_TAB], n, -- cgit v1.2.3 From 85088e38708c97e619e04c118c39ab341a2ba2b3 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Wed, 16 Oct 2019 20:52:09 +0200 Subject: ipv4: Return -ENETUNREACH if we can't create route but saddr is valid [ Upstream commit 595e0651d0296bad2491a4a29a7a43eae6328b02 ] ...instead of -EINVAL. An issue was found with older kernel versions while unplugging a NFS client with pending RPCs, and the wrong error code here prevented it from recovering once link is back up with a configured address. Incidentally, this is not an issue anymore since commit 4f8943f80883 ("SUNRPC: Replace direct task wakeups from softirq context"), included in 5.2-rc7, had the effect of decoupling the forwarding of this error by using SO_ERROR in xs_wake_error(), as pointed out by Benjamin Coddington. To the best of my knowledge, this isn't currently causing any further issue, but the error code doesn't look appropriate anyway, and we might hit this in other paths as well. In detail, as analysed by Gonzalo Siero, once the route is deleted because the interface is down, and can't be resolved and we return -EINVAL here, this ends up, courtesy of inet_sk_rebuild_header(), as the socket error seen by tcp_write_err(), called by tcp_retransmit_timer(). In turn, tcp_write_err() indirectly calls xs_error_report(), which wakes up the RPC pending tasks with a status of -EINVAL. This is then seen by call_status() in the SUN RPC implementation, which aborts the RPC call calling rpc_exit(), instead of handling this as a potentially temporary condition, i.e. as a timeout. Return -EINVAL only if the input parameters passed to ip_route_output_key_hash_rcu() are actually invalid (this is the case if the specified source address is multicast, limited broadcast or all zeroes), but return -ENETUNREACH in all cases where, at the given moment, the given source address doesn't allow resolving the route. While at it, drop the initialisation of err to -ENETUNREACH, which was added to __ip_route_output_key() back then by commit 0315e3827048 ("net: Fix behaviour of unreachable, blackhole and prohibit routes"), but actually had no effect, as it was, and is, overwritten by the fib_lookup() return code assignment, and anyway ignored in all other branches, including the if (fl4->saddr) one: I find this rather confusing, as it would look like -ENETUNREACH is the "default" error, while that statement has no effect. Also note that after commit fc75fc8339e7 ("ipv4: dont create routes on down devices"), we would get -ENETUNREACH if the device is down, but -EINVAL if the source address is specified and we can't resolve the route, and this appears to be rather inconsistent. Reported-by: Stefan Walter Analysed-by: Benjamin Coddington Analysed-by: Gonzalo Siero Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/route.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index a60078de1191..42132ac2c497 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2209,7 +2209,7 @@ struct rtable *__ip_route_output_key_hash(struct net *net, struct flowi4 *fl4, struct fib_result res; struct rtable *rth; int orig_oif; - int err = -ENETUNREACH; + int err; res.tclassid = 0; res.fi = NULL; @@ -2224,11 +2224,14 @@ struct rtable *__ip_route_output_key_hash(struct net *net, struct flowi4 *fl4, rcu_read_lock(); if (fl4->saddr) { - rth = ERR_PTR(-EINVAL); if (ipv4_is_multicast(fl4->saddr) || ipv4_is_lbcast(fl4->saddr) || - ipv4_is_zeronet(fl4->saddr)) + ipv4_is_zeronet(fl4->saddr)) { + rth = ERR_PTR(-EINVAL); goto out; + } + + rth = ERR_PTR(-ENETUNREACH); /* I removed check for oif == dev_out->oif here. It was wrong for two reasons: -- cgit v1.2.3 From eb4058d8daf846b1abaaa6cfba6e2faeb5cfdc3f Mon Sep 17 00:00:00 2001 From: "Matthew Wilcox (Oracle)" Date: Fri, 25 Oct 2019 09:58:37 -0700 Subject: memfd: Fix locking when tagging pins The RCU lock is insufficient to protect the radix tree iteration as a deletion from the tree can occur before we take the spinlock to tag the entry. In 4.19, this has manifested as a bug with the following trace: kernel BUG at lib/radix-tree.c:1429! invalid opcode: 0000 [#1] SMP KASAN PTI CPU: 7 PID: 6935 Comm: syz-executor.2 Not tainted 4.19.36 #25 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 RIP: 0010:radix_tree_tag_set+0x200/0x2f0 lib/radix-tree.c:1429 Code: 00 00 5b 5d 41 5c 41 5d 41 5e 41 5f c3 48 89 44 24 10 e8 a3 29 7e fe 48 8b 44 24 10 48 0f ab 03 e9 d2 fe ff ff e8 90 29 7e fe <0f> 0b 48 c7 c7 e0 5a 87 84 e8 f0 e7 08 ff 4c 89 ef e8 4a ff ac fe RSP: 0018:ffff88837b13fb60 EFLAGS: 00010016 RAX: 0000000000040000 RBX: ffff8883c5515d58 RCX: ffffffff82cb2ef0 RDX: 0000000000000b72 RSI: ffffc90004cf2000 RDI: ffff8883c5515d98 RBP: ffff88837b13fb98 R08: ffffed106f627f7e R09: ffffed106f627f7e R10: 0000000000000001 R11: ffffed106f627f7d R12: 0000000000000004 R13: ffffea000d7fea80 R14: 1ffff1106f627f6f R15: 0000000000000002 FS: 00007fa1b8df2700(0000) GS:ffff8883e2fc0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fa1b8df1db8 CR3: 000000037d4d2001 CR4: 0000000000160ee0 Call Trace: memfd_tag_pins mm/memfd.c:51 [inline] memfd_wait_for_pins+0x2c5/0x12d0 mm/memfd.c:81 memfd_add_seals mm/memfd.c:215 [inline] memfd_fcntl+0x33d/0x4a0 mm/memfd.c:247 do_fcntl+0x589/0xeb0 fs/fcntl.c:421 __do_sys_fcntl fs/fcntl.c:463 [inline] __se_sys_fcntl fs/fcntl.c:448 [inline] __x64_sys_fcntl+0x12d/0x180 fs/fcntl.c:448 do_syscall_64+0xc8/0x580 arch/x86/entry/common.c:293 The problem does not occur in mainline due to the XArray rewrite which changed the locking to exclude modification of the tree during iteration. At the time, nobody realised this was a bugfix. Backport the locking changes to stable. Cc: stable@vger.kernel.org Reported-by: zhong jiang Signed-off-by: Matthew Wilcox (Oracle) Signed-off-by: Sasha Levin --- mm/shmem.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/mm/shmem.c b/mm/shmem.c index f11aec40f2e1..62668379623b 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1854,11 +1854,12 @@ static void shmem_tag_pins(struct address_space *mapping) void **slot; pgoff_t start; struct page *page; + unsigned int tagged = 0; lru_add_drain(); start = 0; - rcu_read_lock(); + spin_lock_irq(&mapping->tree_lock); restart: radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) { page = radix_tree_deref_slot(slot); @@ -1866,19 +1867,20 @@ restart: if (radix_tree_deref_retry(page)) goto restart; } else if (page_count(page) - page_mapcount(page) > 1) { - spin_lock_irq(&mapping->tree_lock); radix_tree_tag_set(&mapping->page_tree, iter.index, SHMEM_TAG_PINNED); - spin_unlock_irq(&mapping->tree_lock); } - if (need_resched()) { - cond_resched_rcu(); - start = iter.index + 1; - goto restart; - } + if (++tagged % 1024) + continue; + + spin_unlock_irq(&mapping->tree_lock); + cond_resched(); + start = iter.index + 1; + spin_lock_irq(&mapping->tree_lock); + goto restart; } - rcu_read_unlock(); + spin_unlock_irq(&mapping->tree_lock); } /* -- cgit v1.2.3 From 5610f75e5ba8315fb9c267fdeccfe6fa17c22a44 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 10 Oct 2019 14:58:35 +0200 Subject: USB: legousbtower: fix memleak on disconnect commit b6c03e5f7b463efcafd1ce141bd5a8fc4e583ae2 upstream. If disconnect() races with release() after a process has been interrupted, release() could end up returning early and the driver would fail to free its driver data. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191010125835.27031-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/legousbtower.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 20e3d577ae5d..32b41eb07f00 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -425,10 +425,7 @@ static int tower_release (struct inode *inode, struct file *file) goto exit; } - if (mutex_lock_interruptible(&dev->lock)) { - retval = -ERESTARTSYS; - goto exit; - } + mutex_lock(&dev->lock); if (dev->open_count != 1) { dev_dbg(&dev->udev->dev, "%s: device not opened exactly once\n", -- cgit v1.2.3 From ebcfd766cde61695c444e1b0e723b4bb4426c0fc Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 14 Oct 2019 14:18:30 -0500 Subject: usb: udc: lpc32xx: fix bad bit shift operation commit b987b66ac3a2bc2f7b03a0ba48a07dc553100c07 upstream. It seems that the right variable to use in this case is *i*, instead of *n*, otherwise there is an undefined behavior when right shifiting by more than 31 bits when multiplying n by 8; notice that *n* can take values equal or greater than 4 (4, 8, 16, ...). Also, notice that under the current conditions (bl = 3), we are skiping the handling of bytes 3, 7, 31... So, fix this by updating this logic and limit *bl* up to 4 instead of up to 3. This fix is based on function udc_stuff_fifo(). Addresses-Coverity-ID: 1454834 ("Bad bit shift operation") Fixes: 24a28e428351 ("USB: gadget driver for LPC32xx") Cc: stable@vger.kernel.org Signed-off-by: Gustavo A. R. Silva Link: https://lore.kernel.org/r/20191014191830.GA10721@embeddedor Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/lpc32xx_udc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 90d24f62bd81..ea43cb74a6f2 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -1225,11 +1225,11 @@ static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes) tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); bl = bytes - n; - if (bl > 3) - bl = 3; + if (bl > 4) + bl = 4; for (i = 0; i < bl; i++) - data[n + i] = (u8) ((tmp >> (n * 8)) & 0xFF); + data[n + i] = (u8) ((tmp >> (i * 8)) & 0xFF); } break; -- cgit v1.2.3 From be742b0bd9e9ab91cc1c08cf2da1bf9d34693858 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 11 Oct 2019 11:57:35 +0200 Subject: USB: serial: ti_usb_3410_5052: fix port-close races commit 6f1d1dc8d540a9aa6e39b9cb86d3a67bbc1c8d8d upstream. Fix races between closing a port and opening or closing another port on the same device which could lead to a failure to start or stop the shared interrupt URB. The latter could potentially cause a use-after-free or worse in the completion handler on driver unbind. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ti_usb_3410_5052.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index fe7f5ace6064..a33acb8c16d3 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -542,7 +542,6 @@ static void ti_close(struct usb_serial_port *port) struct ti_port *tport; int port_number; int status; - int do_unlock; unsigned long flags; tdev = usb_get_serial_data(port->serial); @@ -569,16 +568,13 @@ static void ti_close(struct usb_serial_port *port) "%s - cannot send close port command, %d\n" , __func__, status); - /* if mutex_lock is interrupted, continue anyway */ - do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock); + mutex_lock(&tdev->td_open_close_lock); --tport->tp_tdev->td_open_port_count; - if (tport->tp_tdev->td_open_port_count <= 0) { + if (tport->tp_tdev->td_open_port_count == 0) { /* last port is closed, shut down interrupt urb */ usb_kill_urb(port->serial->port[0]->interrupt_in_urb); - tport->tp_tdev->td_open_port_count = 0; } - if (do_unlock) - mutex_unlock(&tdev->td_open_close_lock); + mutex_unlock(&tdev->td_open_close_lock); } -- cgit v1.2.3 From a81304eb043c05c00efe43d2bf600e32caa95053 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 10 Oct 2019 14:58:34 +0200 Subject: USB: ldusb: fix memleak on disconnect commit b14a39048c1156cfee76228bf449852da2f14df8 upstream. If disconnect() races with release() after a process has been interrupted, release() could end up returning early and the driver would fail to free its driver data. Fixes: 2824bd250f0b ("[PATCH] USB: add ldusb driver") Cc: stable # 2.6.13 Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191010125835.27031-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ldusb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 84f12c1bf9e6..31aecbcf0413 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -384,10 +384,7 @@ static int ld_usb_release(struct inode *inode, struct file *file) goto exit; } - if (mutex_lock_interruptible(&dev->mutex)) { - retval = -ERESTARTSYS; - goto exit; - } + mutex_lock(&dev->mutex); if (dev->open_count != 1) { retval = -ENODEV; -- cgit v1.2.3 From 3e4cf06e1938a358b05048726a341b98852eadb1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 15 Oct 2019 19:55:22 +0200 Subject: USB: usblp: fix use-after-free on disconnect commit 7a759197974894213621aa65f0571b51904733d6 upstream. A recent commit addressing a runtime PM use-count regression, introduced a use-after-free by not making sure we held a reference to the struct usb_interface for the lifetime of the driver data. Fixes: 9a31535859bf ("USB: usblp: fix runtime PM after driver unbind") Cc: stable Reported-by: syzbot+cd24df4d075c319ebfc5@syzkaller.appspotmail.com Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191015175522.18490-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/usblp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 0669fbb0ec25..07c3c3449147 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -458,6 +458,7 @@ static void usblp_cleanup(struct usblp *usblp) kfree(usblp->readbuf); kfree(usblp->device_id_string); kfree(usblp->statusbuf); + usb_put_intf(usblp->intf); kfree(usblp); } @@ -1120,7 +1121,7 @@ static int usblp_probe(struct usb_interface *intf, init_waitqueue_head(&usblp->wwait); init_usb_anchor(&usblp->urbs); usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; - usblp->intf = intf; + usblp->intf = usb_get_intf(intf); /* Malloc device ID string buffer to the largest expected length, * since we can re-query it on an ioctl and a dynamic string @@ -1209,6 +1210,7 @@ abort: kfree(usblp->readbuf); kfree(usblp->statusbuf); kfree(usblp->device_id_string); + usb_put_intf(usblp->intf); kfree(usblp); abort_ret: return retval; -- cgit v1.2.3 From 44d3e9852350e7797096097f47fd3972b94fb657 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 18 Oct 2019 17:19:54 +0200 Subject: USB: ldusb: fix read info leaks commit 7a6f22d7479b7a0b68eadd308a997dd64dda7dae upstream. Fix broken read implementation, which could be used to trigger slab info leaks. The driver failed to check if the custom ring buffer was still empty when waking up after having waited for more data. This would happen on every interrupt-in completion, even if no data had been added to the ring buffer (e.g. on disconnect events). Due to missing sanity checks and uninitialised (kmalloced) ring-buffer entries, this meant that huge slab info leaks could easily be triggered. Note that the empty-buffer check after wakeup is enough to fix the info leak on disconnect, but let's clear the buffer on allocation and add a sanity check to read() to prevent further leaks. Fixes: 2824bd250f0b ("[PATCH] USB: add ldusb driver") Cc: stable # 2.6.13 Reported-by: syzbot+6fe95b826644f7f12b0b@syzkaller.appspotmail.com Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20191018151955.25135-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ldusb.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 31aecbcf0413..7da242bbe37b 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -468,7 +468,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, /* wait for data */ spin_lock_irq(&dev->rbsl); - if (dev->ring_head == dev->ring_tail) { + while (dev->ring_head == dev->ring_tail) { dev->interrupt_in_done = 0; spin_unlock_irq(&dev->rbsl); if (file->f_flags & O_NONBLOCK) { @@ -478,12 +478,17 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done); if (retval < 0) goto unlock_exit; - } else { - spin_unlock_irq(&dev->rbsl); + + spin_lock_irq(&dev->rbsl); } + spin_unlock_irq(&dev->rbsl); /* actual_buffer contains actual_length + interrupt_in_buffer */ actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_tail*(sizeof(size_t)+dev->interrupt_in_endpoint_size)); + if (*actual_buffer > dev->interrupt_in_endpoint_size) { + retval = -EIO; + goto unlock_exit; + } bytes_to_read = min(count, *actual_buffer); if (bytes_to_read < *actual_buffer) dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n", @@ -703,7 +708,9 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n"); dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint); - dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL); + dev->ring_buffer = kcalloc(ring_buffer_size, + sizeof(size_t) + dev->interrupt_in_endpoint_size, + GFP_KERNEL); if (!dev->ring_buffer) { dev_err(&intf->dev, "Couldn't allocate ring_buffer\n"); goto error; -- cgit v1.2.3 From a7d04d58621dfc33afc4ef8c7be4b8e59962bef9 Mon Sep 17 00:00:00 2001 From: Yufen Yu Date: Tue, 15 Oct 2019 21:05:56 +0800 Subject: scsi: core: try to get module before removing device commit 77c301287ebae86cc71d03eb3806f271cb14da79 upstream. We have a test case like block/001 in blktests, which will create a scsi device by loading scsi_debug module and then try to delete the device by sysfs interface. At the same time, it may remove the scsi_debug module. And getting a invalid paging request BUG_ON as following: [ 34.625854] BUG: unable to handle page fault for address: ffffffffa0016bb8 [ 34.629189] Oops: 0000 [#1] SMP PTI [ 34.629618] CPU: 1 PID: 450 Comm: bash Tainted: G W 5.4.0-rc3+ #473 [ 34.632524] RIP: 0010:scsi_proc_hostdir_rm+0x5/0xa0 [ 34.643555] CR2: ffffffffa0016bb8 CR3: 000000012cd88000 CR4: 00000000000006e0 [ 34.644545] Call Trace: [ 34.644907] scsi_host_dev_release+0x6b/0x1f0 [ 34.645511] device_release+0x74/0x110 [ 34.646046] kobject_put+0x116/0x390 [ 34.646559] put_device+0x17/0x30 [ 34.647041] scsi_target_dev_release+0x2b/0x40 [ 34.647652] device_release+0x74/0x110 [ 34.648186] kobject_put+0x116/0x390 [ 34.648691] put_device+0x17/0x30 [ 34.649157] scsi_device_dev_release_usercontext+0x2e8/0x360 [ 34.649953] execute_in_process_context+0x29/0x80 [ 34.650603] scsi_device_dev_release+0x20/0x30 [ 34.651221] device_release+0x74/0x110 [ 34.651732] kobject_put+0x116/0x390 [ 34.652230] sysfs_unbreak_active_protection+0x3f/0x50 [ 34.652935] sdev_store_delete.cold.4+0x71/0x8f [ 34.653579] dev_attr_store+0x1b/0x40 [ 34.654103] sysfs_kf_write+0x3d/0x60 [ 34.654603] kernfs_fop_write+0x174/0x250 [ 34.655165] __vfs_write+0x1f/0x60 [ 34.655639] vfs_write+0xc7/0x280 [ 34.656117] ksys_write+0x6d/0x140 [ 34.656591] __x64_sys_write+0x1e/0x30 [ 34.657114] do_syscall_64+0xb1/0x400 [ 34.657627] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 34.658335] RIP: 0033:0x7f156f337130 During deleting scsi target, the scsi_debug module have been removed. Then, sdebug_driver_template belonged to the module cannot be accessd, resulting in scsi_proc_hostdir_rm() BUG_ON. To fix the bug, we add scsi_device_get() in sdev_store_delete() to try to increase refcount of module, avoiding the module been removed. Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20191015130556.18061-1-yuyufen@huawei.com Signed-off-by: Yufen Yu Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_sysfs.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 085e470d1c49..b89af3841e44 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -679,6 +679,14 @@ sdev_store_delete(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kernfs_node *kn; + struct scsi_device *sdev = to_scsi_device(dev); + + /* + * We need to try to get module, avoiding the module been removed + * during delete. + */ + if (scsi_device_get(sdev)) + return -ENODEV; kn = sysfs_break_active_protection(&dev->kobj, &attr->attr); WARN_ON_ONCE(!kn); @@ -693,9 +701,10 @@ sdev_store_delete(struct device *dev, struct device_attribute *attr, * state into SDEV_DEL. */ device_remove_file(dev, attr); - scsi_remove_device(to_scsi_device(dev)); + scsi_remove_device(sdev); if (kn) sysfs_unbreak_active_protection(kn); + scsi_device_put(sdev); return count; }; static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete); -- cgit v1.2.3 From 65ac31fb6e6dad1a9a469fe009a87e401e8fbed3 Mon Sep 17 00:00:00 2001 From: Junya Monden Date: Wed, 16 Oct 2019 14:42:55 +0200 Subject: ASoC: rsnd: Reinitialize bit clock inversion flag for every format setting commit 22e58665a01006d05f0239621f7d41cacca96cc4 upstream. Unlike other format-related DAI parameters, rdai->bit_clk_inv flag is not properly re-initialized when setting format for new stream processing. The inversion, if requested, is then applied not to default, but to a previous value, which leads to SCKP bit in SSICR register being set incorrectly. Fix this by re-setting the flag to its initial value, determined by format. Fixes: 1a7889ca8aba3 ("ASoC: rsnd: fixup SND_SOC_DAIFMT_xB_xF behavior") Cc: Andrew Gabbasov Cc: Jiada Wang Cc: Timo Wischer Cc: stable@vger.kernel.org # v3.17+ Signed-off-by: Junya Monden Signed-off-by: Eugeniu Rosca Acked-by: Kuninori Morimoto Link: https://lore.kernel.org/r/20191016124255.7442-1-erosca@de.adit-jv.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/sh/rcar/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index e00dfbec22c5..f18485c6a5d8 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -524,6 +524,7 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) } /* set format */ + rdai->bit_clk_inv = 0; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: rdai->sys_delay = 0; -- cgit v1.2.3 From 3ca40f2f6015580caf11a4fd23503ea7529ed861 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 4 Oct 2019 10:51:32 +0100 Subject: cfg80211: wext: avoid copying malformed SSIDs commit 4ac2813cc867ae563a1ba5a9414bfb554e5796fa upstream. Ensure the SSID element is bounds-checked prior to invoking memcpy() with its length field, when copying to userspace. Cc: Cc: Kees Cook Reported-by: Nicolas Waisman Signed-off-by: Will Deacon Link: https://lore.kernel.org/r/20191004095132.15777-2-will@kernel.org [adjust commit log a bit] Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/wireless/wext-sme.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index a4e8af3321d2..98ff9d9e1aa9 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -225,6 +225,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, struct iw_point *data, char *ssid) { struct wireless_dev *wdev = dev->ieee80211_ptr; + int ret = 0; /* call only for station! */ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) @@ -242,7 +243,10 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, if (ie) { data->flags = 1; data->length = ie[1]; - memcpy(ssid, ie + 2, data->length); + if (data->length > IW_ESSID_MAX_SIZE) + ret = -EINVAL; + else + memcpy(ssid, ie + 2, data->length); } rcu_read_unlock(); } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { @@ -252,7 +256,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, } wdev_unlock(wdev); - return 0; + return ret; } int cfg80211_mgd_wext_siwap(struct net_device *dev, -- cgit v1.2.3 From 86962d9a79b04ee585758c6ecb01772bd02c5cb0 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 4 Oct 2019 10:51:31 +0100 Subject: mac80211: Reject malformed SSID elements commit 4152561f5da3fca92af7179dd538ea89e248f9d0 upstream. Although this shouldn't occur in practice, it's a good idea to bounds check the length field of the SSID element prior to using it for things like allocations or memcpy operations. Cc: Cc: Kees Cook Reported-by: Nicolas Waisman Signed-off-by: Will Deacon Link: https://lore.kernel.org/r/20191004095132.15777-1-will@kernel.org Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/mlme.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 24eec3cb922d..031fbfd36d58 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2431,7 +2431,8 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, rcu_read_lock(); ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID); - if (WARN_ON_ONCE(ssid == NULL)) + if (WARN_ONCE(!ssid || ssid[1] > IEEE80211_MAX_SSID_LEN, + "invalid SSID element (len=%d)", ssid ? ssid[1] : -1)) ssid_len = 0; else ssid_len = ssid[1]; @@ -4669,7 +4670,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); ssidie = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); - if (!ssidie) { + if (!ssidie || ssidie[1] > sizeof(assoc_data->ssid)) { rcu_read_unlock(); kfree(assoc_data); return -EINVAL; -- cgit v1.2.3 From b5b88cda3e8f4fffb97ec8bbe8ead8ac99f6f46f Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 2 Apr 2019 11:30:37 +0800 Subject: drm/edid: Add 6 bpc quirk for SDC panel in Lenovo G50 commit 11bcf5f78905b90baae8fb01e16650664ed0cb00 upstream. Another panel that needs 6BPC quirk. BugLink: https://bugs.launchpad.net/bugs/1819968 Cc: # v4.8+ Reviewed-by: Alex Deucher Signed-off-by: Kai-Heng Feng Signed-off-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20190402033037.21877-1-kai.heng.feng@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_edid.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 724f7cf52253..b439e2f8ee00 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -150,6 +150,9 @@ static struct edid_quirk { /* Medion MD 30217 PG */ { "MED", 0x7b8, EDID_QUIRK_PREFER_LARGE_75 }, + /* Lenovo G50 */ + { "SDC", 18514, EDID_QUIRK_FORCE_6BPC }, + /* Panel in Samsung NP700G7A-S01PL notebook reports 6bpc */ { "SEC", 0xd033, EDID_QUIRK_FORCE_8BPC }, -- cgit v1.2.3 From 8af008849fe5d50190e75cb91a39240452f6db31 Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Tue, 1 Oct 2019 12:49:49 +0200 Subject: scsi: zfcp: fix reaction on bit error threshold notification [ Upstream commit 2190168aaea42c31bff7b9a967e7b045f07df095 ] On excessive bit errors for the FCP channel ingress fibre path, the channel notifies us. Previously, we only emitted a kernel message and a trace record. Since performance can become suboptimal with I/O timeouts due to bit errors, we now stop using an FCP device by default on channel notification so multipath on top can timely failover to other paths. A new module parameter zfcp.ber_stop can be used to get zfcp old behavior. User explanation of new kernel message: * Description: * The FCP channel reported that its bit error threshold has been exceeded. * These errors might result from a problem with the physical components * of the local fibre link into the FCP channel. * The problem might be damage or malfunction of the cable or * cable connection between the FCP channel and * the adjacent fabric switch port or the point-to-point peer. * Find details about the errors in the HBA trace for the FCP device. * The zfcp device driver closed down the FCP device * to limit the performance impact from possible I/O command timeouts. * User action: * Check for problems on the local fibre link, ensure that fibre optics are * clean and functional, and all cables are properly plugged. * After the repair action, you can manually recover the FCP device by * writing "0" into its "failed" sysfs attribute. * If recovery through sysfs is not possible, set the CHPID of the device * offline and back online on the service element. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: #2.6.30+ Link: https://lore.kernel.org/r/20191001104949.42810-1-maier@linux.ibm.com Reviewed-by: Jens Remus Reviewed-by: Benjamin Block Signed-off-by: Steffen Maier Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/s390/scsi/zfcp_fsf.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 1964391db904..a3aaef4c53a3 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -20,6 +20,11 @@ struct kmem_cache *zfcp_fsf_qtcb_cache; +static bool ber_stop = true; +module_param(ber_stop, bool, 0600); +MODULE_PARM_DESC(ber_stop, + "Shuts down FCP devices for FCP channels that report a bit-error count in excess of its threshold (default on)"); + static void zfcp_fsf_request_timeout_handler(unsigned long data) { struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; @@ -231,10 +236,15 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) case FSF_STATUS_READ_SENSE_DATA_AVAIL: break; case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: - dev_warn(&adapter->ccw_device->dev, - "The error threshold for checksum statistics " - "has been exceeded\n"); zfcp_dbf_hba_bit_err("fssrh_3", req); + if (ber_stop) { + dev_warn(&adapter->ccw_device->dev, + "All paths over this FCP device are disused because of excessive bit errors\n"); + zfcp_erp_adapter_shutdown(adapter, 0, "fssrh_b"); + } else { + dev_warn(&adapter->ccw_device->dev, + "The error threshold for checksum statistics has been exceeded\n"); + } break; case FSF_STATUS_READ_LINK_DOWN: zfcp_fsf_status_read_link_down(req); -- cgit v1.2.3 From cff989b79e3d73cacde79006b5a21dac8d0b60a3 Mon Sep 17 00:00:00 2001 From: Qian Cai Date: Mon, 14 Oct 2019 14:11:51 -0700 Subject: mm/slub: fix a deadlock in show_slab_objects() commit e4f8e513c3d353c134ad4eef9fd0bba12406c7c8 upstream. A long time ago we fixed a similar deadlock in show_slab_objects() [1]. However, it is apparently due to the commits like 01fb58bcba63 ("slab: remove synchronous synchronize_sched() from memcg cache deactivation path") and 03afc0e25f7f ("slab: get_online_mems for kmem_cache_{create,destroy,shrink}"), this kind of deadlock is back by just reading files in /sys/kernel/slab which will generate a lockdep splat below. Since the "mem_hotplug_lock" here is only to obtain a stable online node mask while racing with NUMA node hotplug, in the worst case, the results may me miscalculated while doing NUMA node hotplug, but they shall be corrected by later reads of the same files. WARNING: possible circular locking dependency detected ------------------------------------------------------ cat/5224 is trying to acquire lock: ffff900012ac3120 (mem_hotplug_lock.rw_sem){++++}, at: show_slab_objects+0x94/0x3a8 but task is already holding lock: b8ff009693eee398 (kn->count#45){++++}, at: kernfs_seq_start+0x44/0xf0 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #2 (kn->count#45){++++}: lock_acquire+0x31c/0x360 __kernfs_remove+0x290/0x490 kernfs_remove+0x30/0x44 sysfs_remove_dir+0x70/0x88 kobject_del+0x50/0xb0 sysfs_slab_unlink+0x2c/0x38 shutdown_cache+0xa0/0xf0 kmemcg_cache_shutdown_fn+0x1c/0x34 kmemcg_workfn+0x44/0x64 process_one_work+0x4f4/0x950 worker_thread+0x390/0x4bc kthread+0x1cc/0x1e8 ret_from_fork+0x10/0x18 -> #1 (slab_mutex){+.+.}: lock_acquire+0x31c/0x360 __mutex_lock_common+0x16c/0xf78 mutex_lock_nested+0x40/0x50 memcg_create_kmem_cache+0x38/0x16c memcg_kmem_cache_create_func+0x3c/0x70 process_one_work+0x4f4/0x950 worker_thread+0x390/0x4bc kthread+0x1cc/0x1e8 ret_from_fork+0x10/0x18 -> #0 (mem_hotplug_lock.rw_sem){++++}: validate_chain+0xd10/0x2bcc __lock_acquire+0x7f4/0xb8c lock_acquire+0x31c/0x360 get_online_mems+0x54/0x150 show_slab_objects+0x94/0x3a8 total_objects_show+0x28/0x34 slab_attr_show+0x38/0x54 sysfs_kf_seq_show+0x198/0x2d4 kernfs_seq_show+0xa4/0xcc seq_read+0x30c/0x8a8 kernfs_fop_read+0xa8/0x314 __vfs_read+0x88/0x20c vfs_read+0xd8/0x10c ksys_read+0xb0/0x120 __arm64_sys_read+0x54/0x88 el0_svc_handler+0x170/0x240 el0_svc+0x8/0xc other info that might help us debug this: Chain exists of: mem_hotplug_lock.rw_sem --> slab_mutex --> kn->count#45 Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(kn->count#45); lock(slab_mutex); lock(kn->count#45); lock(mem_hotplug_lock.rw_sem); *** DEADLOCK *** 3 locks held by cat/5224: #0: 9eff00095b14b2a0 (&p->lock){+.+.}, at: seq_read+0x4c/0x8a8 #1: 0eff008997041480 (&of->mutex){+.+.}, at: kernfs_seq_start+0x34/0xf0 #2: b8ff009693eee398 (kn->count#45){++++}, at: kernfs_seq_start+0x44/0xf0 stack backtrace: Call trace: dump_backtrace+0x0/0x248 show_stack+0x20/0x2c dump_stack+0xd0/0x140 print_circular_bug+0x368/0x380 check_noncircular+0x248/0x250 validate_chain+0xd10/0x2bcc __lock_acquire+0x7f4/0xb8c lock_acquire+0x31c/0x360 get_online_mems+0x54/0x150 show_slab_objects+0x94/0x3a8 total_objects_show+0x28/0x34 slab_attr_show+0x38/0x54 sysfs_kf_seq_show+0x198/0x2d4 kernfs_seq_show+0xa4/0xcc seq_read+0x30c/0x8a8 kernfs_fop_read+0xa8/0x314 __vfs_read+0x88/0x20c vfs_read+0xd8/0x10c ksys_read+0xb0/0x120 __arm64_sys_read+0x54/0x88 el0_svc_handler+0x170/0x240 el0_svc+0x8/0xc I think it is important to mention that this doesn't expose the show_slab_objects to use-after-free. There is only a single path that might really race here and that is the slab hotplug notifier callback __kmem_cache_shrink (via slab_mem_going_offline_callback) but that path doesn't really destroy kmem_cache_node data structures. [1] http://lkml.iu.edu/hypermail/linux/kernel/1101.0/02850.html [akpm@linux-foundation.org: add comment explaining why we don't need mem_hotplug_lock] Link: http://lkml.kernel.org/r/1570192309-10132-1-git-send-email-cai@lca.pw Fixes: 01fb58bcba63 ("slab: remove synchronous synchronize_sched() from memcg cache deactivation path") Fixes: 03afc0e25f7f ("slab: get_online_mems for kmem_cache_{create,destroy,shrink}") Signed-off-by: Qian Cai Acked-by: Michal Hocko Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Cc: Tejun Heo Cc: Vladimir Davydov Cc: Roman Gushchin Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/slub.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index c33b0e13cca7..8f5dcb0ac24f 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -4522,7 +4522,17 @@ static ssize_t show_slab_objects(struct kmem_cache *s, } } - get_online_mems(); + /* + * It is impossible to take "mem_hotplug_lock" here with "kernfs_mutex" + * already held which will conflict with an existing lock order: + * + * mem_hotplug_lock->slab_mutex->kernfs_mutex + * + * We don't really need mem_hotplug_lock (to hold off + * slab_mem_going_offline_callback) here because slab's memory hot + * unplug code doesn't destroy the kmem_cache->node[] data. + */ + #ifdef CONFIG_SLUB_DEBUG if (flags & SO_ALL) { struct kmem_cache_node *n; @@ -4563,7 +4573,6 @@ static ssize_t show_slab_objects(struct kmem_cache *s, x += sprintf(buf + x, " N%d=%lu", node, nodes[node]); #endif - put_online_mems(); kfree(nodes); return x + sprintf(buf + x, "\n"); } -- cgit v1.2.3 From e1eccccb24b87d37f1123b69d2ebb3c26f2ff11d Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Mon, 14 Oct 2019 15:48:19 -0700 Subject: xtensa: drop EXPORT_SYMBOL for outs*/ins* commit 8b39da985194aac2998dd9e3a22d00b596cebf1e upstream. Custom outs*/ins* implementations are long gone from the xtensa port, remove matching EXPORT_SYMBOLs. This fixes the following build warnings issued by modpost since commit 15bfc2348d54 ("modpost: check for static EXPORT_SYMBOL* functions"): WARNING: "insb" [vmlinux] is a static EXPORT_SYMBOL WARNING: "insw" [vmlinux] is a static EXPORT_SYMBOL WARNING: "insl" [vmlinux] is a static EXPORT_SYMBOL WARNING: "outsb" [vmlinux] is a static EXPORT_SYMBOL WARNING: "outsw" [vmlinux] is a static EXPORT_SYMBOL WARNING: "outsl" [vmlinux] is a static EXPORT_SYMBOL Cc: stable@vger.kernel.org Fixes: d38efc1f150f ("xtensa: adopt generic io routines") Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman --- arch/xtensa/kernel/xtensa_ksyms.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index 4d2872fd9bb5..e2dd9109df63 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c @@ -116,13 +116,6 @@ EXPORT_SYMBOL(__invalidate_icache_range); // FIXME EXPORT_SYMBOL(screen_info); #endif -EXPORT_SYMBOL(outsb); -EXPORT_SYMBOL(outsw); -EXPORT_SYMBOL(outsl); -EXPORT_SYMBOL(insb); -EXPORT_SYMBOL(insw); -EXPORT_SYMBOL(insl); - extern long common_exception_return; EXPORT_SYMBOL(common_exception_return); -- cgit v1.2.3 From b7f9ec253c281a72a99e2ba2c81191f2753d990a Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 4 Oct 2019 19:23:37 +0200 Subject: parisc: Fix vmap memory leak in ioremap()/iounmap() commit 513f7f747e1cba81f28a436911fba0b485878ebd upstream. Sven noticed that calling ioremap() and iounmap() multiple times leads to a vmap memory leak: vmap allocation for size 4198400 failed: use vmalloc= to increase size It seems we missed calling vunmap() in iounmap(). Signed-off-by: Helge Deller Noticed-by: Sven Schnelle Cc: # v3.16+ Signed-off-by: Greg Kroah-Hartman --- arch/parisc/mm/ioremap.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c index 838d0259cd27..3741f91fc186 100644 --- a/arch/parisc/mm/ioremap.c +++ b/arch/parisc/mm/ioremap.c @@ -2,7 +2,7 @@ * arch/parisc/mm/ioremap.c * * (C) Copyright 1995 1996 Linus Torvalds - * (C) Copyright 2001-2006 Helge Deller + * (C) Copyright 2001-2019 Helge Deller * (C) Copyright 2005 Kyle McMartin */ @@ -83,7 +83,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l addr = (void __iomem *) area->addr; if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, phys_addr, pgprot)) { - vfree(addr); + vunmap(addr); return NULL; } @@ -91,9 +91,11 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l } EXPORT_SYMBOL(__ioremap); -void iounmap(const volatile void __iomem *addr) +void iounmap(const volatile void __iomem *io_addr) { - if (addr > high_memory) - return vfree((void *) (PAGE_MASK & (unsigned long __force) addr)); + unsigned long addr = (unsigned long)io_addr & PAGE_MASK; + + if (is_vmalloc_addr((void *)addr)) + vunmap((void *)addr); } EXPORT_SYMBOL(iounmap); -- cgit v1.2.3 From 0fef1c7da4b432dbfadec675fc70c56ae271381d Mon Sep 17 00:00:00 2001 From: Roberto Bergantinos Corpas Date: Mon, 14 Oct 2019 10:59:23 +0200 Subject: CIFS: avoid using MID 0xFFFF commit 03d9a9fe3f3aec508e485dd3dcfa1e99933b4bdb upstream. According to MS-CIFS specification MID 0xFFFF should not be used by the CIFS client, but we actually do. Besides, this has proven to cause races leading to oops between SendReceive2/cifs_demultiplex_thread. On SMB1, MID is a 2 byte value easy to reach in CurrentMid which may conflict with an oplock break notification request coming from server Signed-off-by: Roberto Bergantinos Corpas Reviewed-by: Ronnie Sahlberg Reviewed-by: Aurelien Aptel Signed-off-by: Steve French CC: Stable Signed-off-by: Greg Kroah-Hartman --- fs/cifs/smb1ops.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index f7a9adab0b84..6f5d78b172ba 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -180,6 +180,9 @@ cifs_get_next_mid(struct TCP_Server_Info *server) /* we do not want to loop forever */ last_mid = cur_mid; cur_mid++; + /* avoid 0xFFFF MID */ + if (cur_mid == 0xffff) + cur_mid++; /* * This nested loop looks more expensive than it is. -- cgit v1.2.3 From df514f91210c56ab7a5bc82459e169fed1cce87c Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 10 Oct 2019 10:39:26 +0800 Subject: btrfs: block-group: Fix a memory leak due to missing btrfs_put_block_group() commit 4b654acdae850f48b8250b9a578a4eaa518c7a6f upstream. In btrfs_read_block_groups(), if we have an invalid block group which has mixed type (DATA|METADATA) while the fs doesn't have MIXED_GROUPS feature, we error out without freeing the block group cache. This patch will add the missing btrfs_put_block_group() to prevent memory leak. Note for stable backports: the file to patch in versions <= 5.3 is fs/btrfs/extent-tree.c Fixes: 49303381f19a ("Btrfs: bail out if block group has different mixed flag") CC: stable@vger.kernel.org # 4.9+ Reviewed-by: Anand Jain Reviewed-by: Johannes Thumshirn Signed-off-by: Qu Wenruo Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/extent-tree.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 4c316ca3ee78..34ffc125763f 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -9905,6 +9905,7 @@ int btrfs_read_block_groups(struct btrfs_root *root) btrfs_err(info, "bg %llu is a mixed block group but filesystem hasn't enabled mixed block groups", cache->key.objectid); + btrfs_put_block_group(cache); ret = -EINVAL; goto error; } -- cgit v1.2.3 From 44137b2cfad1a2114467e4c7722c8915e2484529 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 5 Oct 2019 13:21:01 +0200 Subject: memstick: jmb38x_ms: Fix an error handling path in 'jmb38x_ms_probe()' commit 28c9fac09ab0147158db0baeec630407a5e9b892 upstream. If 'jmb38x_ms_count_slots()' returns 0, we must undo the previous 'pci_request_regions()' call. Goto 'err_out_int' to fix it. Fixes: 60fdd931d577 ("memstick: add support for JMicron jmb38x MemoryStick host controller") Cc: stable@vger.kernel.org Signed-off-by: Christophe JAILLET Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/memstick/host/jmb38x_ms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index 48db922075e2..08fa6400d255 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -947,7 +947,7 @@ static int jmb38x_ms_probe(struct pci_dev *pdev, if (!cnt) { rc = -ENODEV; pci_dev_busy = 1; - goto err_out; + goto err_out_int; } jm = kzalloc(sizeof(struct jmb38x_ms) -- cgit v1.2.3 From 8bfa06ea6e81bf08d2132d7e70c2b5313b34caf8 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 9 Oct 2019 01:29:10 +0200 Subject: cpufreq: Avoid cpufreq_suspend() deadlock on system shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 65650b35133ff20f0c9ef0abd5c3c66dbce3ae57 upstream. It is incorrect to set the cpufreq syscore shutdown callback pointer to cpufreq_suspend(), because that function cannot be run in the syscore stage of system shutdown for two reasons: (a) it may attempt to carry out actions depending on devices that have already been shut down at that point and (b) the RCU synchronization carried out by it may not be able to make progress then. The latter issue has been present since commit 45975c7d21a1 ("rcu: Define RCU-sched API in terms of RCU for Tree RCU PREEMPT builds"), but the former one has been there since commit 90de2a4aa9f3 ("cpufreq: suspend cpufreq governors on shutdown") regardless. Fix that by dropping cpufreq_syscore_ops altogether and making device_shutdown() call cpufreq_suspend() directly before shutting down devices, which is along the lines of what system-wide power management does. Fixes: 45975c7d21a1 ("rcu: Define RCU-sched API in terms of RCU for Tree RCU PREEMPT builds") Fixes: 90de2a4aa9f3 ("cpufreq: suspend cpufreq governors on shutdown") Reported-by: Ville Syrjälä Tested-by: Ville Syrjälä Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar Cc: 4.0+ # 4.0+ Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 3 +++ drivers/cpufreq/cpufreq.c | 10 ---------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index af948fedd232..64b59552e744 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -10,6 +10,7 @@ * */ +#include #include #include #include @@ -2124,6 +2125,8 @@ void device_shutdown(void) { struct device *dev, *parent; + cpufreq_suspend(); + spin_lock(&devices_kset->list_lock); /* * Walk the devices list backward, shutting down each in turn. diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 205df72ee873..0836d2939c7a 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2512,14 +2512,6 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) } EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); -/* - * Stop cpufreq at shutdown to make sure it isn't holding any locks - * or mutexes when secondary CPUs are halted. - */ -static struct syscore_ops cpufreq_syscore_ops = { - .shutdown = cpufreq_suspend, -}; - struct kobject *cpufreq_global_kobject; EXPORT_SYMBOL(cpufreq_global_kobject); @@ -2531,8 +2523,6 @@ static int __init cpufreq_core_init(void) cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj); BUG_ON(!cpufreq_global_kobject); - register_syscore_ops(&cpufreq_syscore_ops); - return 0; } core_initcall(cpufreq_core_init); -- cgit v1.2.3 From b3310bf507eecf0ffac51121a1bdadb6cd9ca61d Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Fri, 18 Oct 2019 09:45:49 +0200 Subject: xen/netback: fix error path of xenvif_connect_data() commit 3d5c1a037d37392a6859afbde49be5ba6a70a6b3 upstream. xenvif_connect_data() calls module_put() in case of error. This is wrong as there is no related module_get(). Remove the superfluous module_put(). Fixes: 279f438e36c0a7 ("xen-netback: Don't destroy the netdev until the vif is shut down") Cc: # 3.12 Signed-off-by: Juergen Gross Reviewed-by: Paul Durrant Reviewed-by: Wei Liu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netback/interface.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 60b26f32d31d..2008c6a02b8a 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -620,7 +620,6 @@ err_tx_unbind: err_unmap: xenvif_unmap_frontend_rings(queue); err: - module_put(THIS_MODULE); return err; } -- cgit v1.2.3 From 439a1962649e935e0769e65209a023ace82c1847 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 14 Oct 2019 13:25:00 +0200 Subject: PCI: PM: Fix pci_power_up() commit 45144d42f299455911cc29366656c7324a3a7c97 upstream. There is an arbitrary difference between the system resume and runtime resume code paths for PCI devices regarding the delay to apply when switching the devices from D3cold to D0. Namely, pci_restore_standard_config() used in the runtime resume code path calls pci_set_power_state() which in turn invokes __pci_start_power_transition() to power up the device through the platform firmware and that function applies the transition delay (as per PCI Express Base Specification Revision 2.0, Section 6.6.1). However, pci_pm_default_resume_early() used in the system resume code path calls pci_power_up() which doesn't apply the delay at all and that causes issues to occur during resume from suspend-to-idle on some systems where the delay is required. Since there is no reason for that difference to exist, modify pci_power_up() to follow pci_set_power_state() more closely and invoke __pci_start_power_transition() from there to call the platform firmware to power up the device (in case that's necessary). Fixes: db288c9c5f9d ("PCI / PM: restore the original behavior of pci_set_power_state()") Reported-by: Daniel Drake Tested-by: Daniel Drake Link: https://lore.kernel.org/linux-pm/CAD8Lp44TYxrMgPLkHCqF9hv6smEurMXvmmvmtyFhZ6Q4SE+dig@mail.gmail.com/T/#m21be74af263c6a34f36e0fc5c77c5449d9406925 Signed-off-by: Rafael J. Wysocki Acked-by: Bjorn Helgaas Cc: 3.10+ # 3.10+ Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 82b0c2cc2fd3..b7f65fc54dc2 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -703,19 +703,6 @@ void pci_update_current_state(struct pci_dev *dev, pci_power_t state) } } -/** - * pci_power_up - Put the given device into D0 forcibly - * @dev: PCI device to power up - */ -void pci_power_up(struct pci_dev *dev) -{ - if (platform_pci_power_manageable(dev)) - platform_pci_set_power_state(dev, PCI_D0); - - pci_raw_set_power_state(dev, PCI_D0); - pci_update_current_state(dev, PCI_D0); -} - /** * pci_platform_power_transition - Use platform to change device power state * @dev: PCI device to handle. @@ -891,6 +878,17 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) } EXPORT_SYMBOL(pci_set_power_state); +/** + * pci_power_up - Put the given device into D0 forcibly + * @dev: PCI device to power up + */ +void pci_power_up(struct pci_dev *dev) +{ + __pci_start_power_transition(dev, PCI_D0); + pci_raw_set_power_state(dev, PCI_D0); + pci_update_current_state(dev, PCI_D0); +} + /** * pci_choose_state - Choose the power state of a PCI device * @dev: PCI device to be suspended -- cgit v1.2.3 From 23e0c38d3099f01f5c44446101a40743faf5ff76 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sat, 25 Aug 2018 22:58:01 -0700 Subject: net: sched: Fix memory exposure from short TCA_U32_SEL commit 98c8f125fd8a6240ea343c1aa50a1be9047791b8 upstream. Via u32_change(), TCA_U32_SEL has an unspecified type in the netlink policy, so max length isn't enforced, only minimum. This means nkeys (from userspace) was being trusted without checking the actual size of nla_len(), which could lead to a memory over-read, and ultimately an exposure via a call to u32_dump(). Reachability is CAP_NET_ADMIN within a namespace. Reported-by: Al Viro Cc: Jamal Hadi Salim Cc: Cong Wang Cc: Jiri Pirko Cc: "David S. Miller" Cc: netdev@vger.kernel.org Signed-off-by: Kees Cook Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller Signed-off-by: Zubin Mithra Signed-off-by: Greg Kroah-Hartman --- net/sched/cls_u32.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 4fbb67430ce4..4d745a2efd20 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -734,6 +734,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, struct nlattr *opt = tca[TCA_OPTIONS]; struct nlattr *tb[TCA_U32_MAX + 1]; u32 htid; + size_t sel_size; int err; #ifdef CONFIG_CLS_U32_PERF size_t size; @@ -827,8 +828,11 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, return -EINVAL; s = nla_data(tb[TCA_U32_SEL]); + sel_size = sizeof(*s) + sizeof(*s->keys) * s->nkeys; + if (nla_len(tb[TCA_U32_SEL]) < sel_size) + return -EINVAL; - n = kzalloc(sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key), GFP_KERNEL); + n = kzalloc(offsetof(typeof(*n), sel) + sel_size, GFP_KERNEL); if (n == NULL) return -ENOBUFS; @@ -841,7 +845,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, } #endif - memcpy(&n->sel, s, sizeof(*s) + s->nkeys*sizeof(struct tc_u32_key)); + memcpy(&n->sel, s, sel_size); RCU_INIT_POINTER(n->ht_up, ht); n->handle = handle; n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0; -- cgit v1.2.3 From 3cd0698561d3e9dcb7c969077932e072fbb4689e Mon Sep 17 00:00:00 2001 From: Greg KH Date: Tue, 1 Oct 2019 18:56:11 +0200 Subject: RDMA/cxgb4: Do not dma memory off of the stack commit 3840c5b78803b2b6cc1ff820100a74a092c40cbb upstream. Nicolas pointed out that the cxgb4 driver is doing dma off of the stack, which is generally considered a very bad thing. On some architectures it could be a security problem, but odds are none of them actually run this driver, so it's just a "normal" bug. Resolve this by allocating the memory for a message off of the heap instead of the stack. kmalloc() always will give us a proper memory location that DMA will work correctly from. Link: https://lore.kernel.org/r/20191001165611.GA3542072@kroah.com Reported-by: Nicolas Waisman Tested-by: Potnuri Bharat Teja Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/cxgb4/mem.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c index 8218d714fa01..4b682375f465 100644 --- a/drivers/infiniband/hw/cxgb4/mem.c +++ b/drivers/infiniband/hw/cxgb4/mem.c @@ -254,13 +254,17 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry, u64 len, u8 page_size, u32 pbl_size, u32 pbl_addr) { int err; - struct fw_ri_tpte tpt; + struct fw_ri_tpte *tpt; u32 stag_idx; static atomic_t key; if (c4iw_fatal_error(rdev)) return -EIO; + tpt = kmalloc(sizeof(*tpt), GFP_KERNEL); + if (!tpt) + return -ENOMEM; + stag_state = stag_state > 0; stag_idx = (*stag) >> 8; @@ -270,6 +274,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry, mutex_lock(&rdev->stats.lock); rdev->stats.stag.fail++; mutex_unlock(&rdev->stats.lock); + kfree(tpt); return -ENOMEM; } mutex_lock(&rdev->stats.lock); @@ -284,28 +289,28 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry, /* write TPT entry */ if (reset_tpt_entry) - memset(&tpt, 0, sizeof(tpt)); + memset(tpt, 0, sizeof(*tpt)); else { - tpt.valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F | + tpt->valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F | FW_RI_TPTE_STAGKEY_V((*stag & FW_RI_TPTE_STAGKEY_M)) | FW_RI_TPTE_STAGSTATE_V(stag_state) | FW_RI_TPTE_STAGTYPE_V(type) | FW_RI_TPTE_PDID_V(pdid)); - tpt.locread_to_qpid = cpu_to_be32(FW_RI_TPTE_PERM_V(perm) | + tpt->locread_to_qpid = cpu_to_be32(FW_RI_TPTE_PERM_V(perm) | (bind_enabled ? FW_RI_TPTE_MWBINDEN_F : 0) | FW_RI_TPTE_ADDRTYPE_V((zbva ? FW_RI_ZERO_BASED_TO : FW_RI_VA_BASED_TO))| FW_RI_TPTE_PS_V(page_size)); - tpt.nosnoop_pbladdr = !pbl_size ? 0 : cpu_to_be32( + tpt->nosnoop_pbladdr = !pbl_size ? 0 : cpu_to_be32( FW_RI_TPTE_PBLADDR_V(PBL_OFF(rdev, pbl_addr)>>3)); - tpt.len_lo = cpu_to_be32((u32)(len & 0xffffffffUL)); - tpt.va_hi = cpu_to_be32((u32)(to >> 32)); - tpt.va_lo_fbo = cpu_to_be32((u32)(to & 0xffffffffUL)); - tpt.dca_mwbcnt_pstag = cpu_to_be32(0); - tpt.len_hi = cpu_to_be32((u32)(len >> 32)); + tpt->len_lo = cpu_to_be32((u32)(len & 0xffffffffUL)); + tpt->va_hi = cpu_to_be32((u32)(to >> 32)); + tpt->va_lo_fbo = cpu_to_be32((u32)(to & 0xffffffffUL)); + tpt->dca_mwbcnt_pstag = cpu_to_be32(0); + tpt->len_hi = cpu_to_be32((u32)(len >> 32)); } err = write_adapter_mem(rdev, stag_idx + (rdev->lldi.vr->stag.start >> 5), - sizeof(tpt), &tpt); + sizeof(*tpt), tpt); if (reset_tpt_entry) { c4iw_put_resource(&rdev->resource.tpt_table, stag_idx); @@ -313,6 +318,7 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry, rdev->stats.stag.cur -= 32; mutex_unlock(&rdev->stats.lock); } + kfree(tpt); return err; } -- cgit v1.2.3 From da259d0284b69e084d65200b69462bed9b86a4c7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 29 Oct 2019 09:13:33 +0100 Subject: Linux 4.4.198 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5c150d32cae7..3de38e5e93d1 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 4 -SUBLEVEL = 197 +SUBLEVEL = 198 EXTRAVERSION = NAME = Blurry Fish Butt -- cgit v1.2.3 From e3e04ee17053f5ed92714e8b584014ce441b0d39 Mon Sep 17 00:00:00 2001 From: Gustavo Solaira Date: Wed, 30 Oct 2019 13:50:49 -0700 Subject: defconfig: Enable serial for msm8996-perf Enable serial support for msm8996-perf. Change-Id: I4935e3df060a7564158b7c4be06ca1643ca4fd50 Signed-off-by: Gustavo Solaira --- arch/arm64/configs/msm-auto-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/msm-auto-perf_defconfig b/arch/arm64/configs/msm-auto-perf_defconfig index 1c83060d2d2f..f5130c4c4611 100644 --- a/arch/arm64/configs/msm-auto-perf_defconfig +++ b/arch/arm64/configs/msm-auto-perf_defconfig @@ -329,6 +329,7 @@ CONFIG_SENSORS_BMG_FIFO=y # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVMEM is not set # CONFIG_DEVKMEM is not set +CONFIG_SERIAL_MSM=y CONFIG_SERIAL_MSM_HS=y CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y -- cgit v1.2.3 From 04c6078424f250aa25cd308f47468a68474bf7cb Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Wed, 30 Oct 2019 12:32:58 +0530 Subject: spi : spi_qsd : Initialise complete signal only once in probe Initialise complete signal only once in driver probe and do reinitialise in the spi transfer function for the later uses of the complete signal. Change-Id: Ia12ada9ce7cf2552c10f5c2a7d90c1f4c7204647 Signed-off-by: Prudhvi Yarlagadda --- drivers/spi/spi_qsd.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c index 799bf2988b30..cf1ea19dbc6a 100644 --- a/drivers/spi/spi_qsd.c +++ b/drivers/spi/spi_qsd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1390,8 +1390,8 @@ static int msm_spi_process_transfer(struct msm_spi *dd) dd->write_buf = dd->cur_transfer->tx_buf; dd->tx_done = false; dd->rx_done = false; - init_completion(&dd->tx_transfer_complete); - init_completion(&dd->rx_transfer_complete); + reinit_completion(&dd->tx_transfer_complete); + reinit_completion(&dd->rx_transfer_complete); if (dd->cur_transfer->bits_per_word) bpw = dd->cur_transfer->bits_per_word; else @@ -2716,6 +2716,8 @@ skip_dma_resources: spin_lock_init(&dd->queue_lock); mutex_init(&dd->core_lock); init_waitqueue_head(&dd->continue_suspend); + init_completion(&dd->tx_transfer_complete); + init_completion(&dd->rx_transfer_complete); if (!devm_request_mem_region(&pdev->dev, dd->mem_phys_addr, dd->mem_size, SPI_DRV_NAME)) { -- cgit v1.2.3 From ad33cbf95e9a5eb256f3d7bc8c9eff3d7d675b34 Mon Sep 17 00:00:00 2001 From: Hardik Arya Date: Fri, 10 May 2019 15:41:24 +0530 Subject: diag: Reallocate dci buffer with proper required capacity DCI command buffer reallocation is not done properly with required capacity. The patch reallocates the same buffer and updated capacity properly with header and response length. Change-Id: I7b5fd132b9241d0f1493bcb602a6b361e4ad9a04 Signed-off-by: Hardik Arya --- drivers/char/diag/diag_dci.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 2301e1e566e0..e9a6711c9990 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -998,6 +998,7 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, unsigned char *temp = buf; int save_req_uid = 0; struct diag_dci_pkt_rsp_header_t pkt_rsp_header; + int header_len = sizeof(struct diag_dci_pkt_rsp_header_t); if (!buf || len <= 0) { pr_err("diag: Invalid pointer in %s\n", __func__); @@ -1066,23 +1067,24 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, mutex_lock(&rsp_buf->data_mutex); /* * Check if we can fit the data in the rsp buffer. The total length of - * the rsp is the rsp length (write_len) + DCI_PKT_RSP_TYPE header (int) - * + field for length (int) + delete_flag (uint8_t) + * the rsp is the rsp length (write_len) + dci response packet header + * length (sizeof(struct diag_dci_pkt_rsp_header_t)) */ - if ((rsp_buf->data_len + 9 + rsp_len) > rsp_buf->capacity) { + if ((rsp_buf->data_len + header_len + rsp_len) > rsp_buf->capacity) { pr_alert("diag: create capacity for pkt rsp\n"); - rsp_buf->capacity += 9 + rsp_len; - temp_buf = krealloc(rsp_buf->data, rsp_buf->capacity, - GFP_KERNEL); + temp_buf = vzalloc(rsp_buf->capacity + header_len + rsp_len); if (!temp_buf) { pr_err("diag: DCI realloc failed\n"); mutex_unlock(&rsp_buf->data_mutex); mutex_unlock(&entry->buffers[data_source].buf_mutex); mutex_unlock(&driver->dci_mutex); return; - } else { - rsp_buf->data = temp_buf; } + rsp_buf->capacity += header_len + rsp_len; + if (rsp_buf->capacity > rsp_buf->data_len) + memcpy(temp_buf, rsp_buf->data, rsp_buf->data_len); + vfree(rsp_buf->data); + rsp_buf->data = temp_buf; } /* Fill in packet response header information */ @@ -1091,9 +1093,8 @@ void extract_dci_pkt_rsp(unsigned char *buf, int len, int data_source, pkt_rsp_header.length = rsp_len + sizeof(int); pkt_rsp_header.delete_flag = delete_flag; pkt_rsp_header.uid = save_req_uid; - memcpy(rsp_buf->data + rsp_buf->data_len, &pkt_rsp_header, - sizeof(struct diag_dci_pkt_rsp_header_t)); - rsp_buf->data_len += sizeof(struct diag_dci_pkt_rsp_header_t); + memcpy(rsp_buf->data + rsp_buf->data_len, &pkt_rsp_header, header_len); + rsp_buf->data_len += header_len; memcpy(rsp_buf->data + rsp_buf->data_len, temp, rsp_len); rsp_buf->data_len += rsp_len; rsp_buf->data_source = data_source; -- cgit v1.2.3 From 9fbd3acbf7d7c4d295f1f9fae508c097ba1dcc9c Mon Sep 17 00:00:00 2001 From: Kaushal Kumar Date: Tue, 27 Mar 2018 18:08:32 +0530 Subject: soc: qcom: scm: Add a noretry variant for scm_call2 scm_call2 can block scm calls up to 2s due to its retry mechanism whenever the secure firmware is busy waiting for certain processing by the client who in turn is waiting upon its scm call to either complete or return with failure. Upon early return, client can process the pending requests to free up secure firmware and unblock processing of all pending scm calls. Add a noretry variant for scm_call2 which can be used by clients who do not intend to wait for 2s for return status. Change-Id: I1f0849464a64c32a4de4510fa5787b0ab328725c Signed-off-by: Kaushal Kumar --- drivers/soc/qcom/scm.c | 70 +++++++++++++++++++++++++++++++------------------- include/soc/qcom/scm.h | 9 ++++++- 2 files changed, 52 insertions(+), 27 deletions(-) diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c index c6bdcee8131e..f4125113efff 100644 --- a/drivers/soc/qcom/scm.c +++ b/drivers/soc/qcom/scm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -635,28 +635,7 @@ static int allocate_extra_arg_buffer(struct scm_desc *desc, gfp_t flags) return 0; } -/** - * scm_call2() - Invoke a syscall in the secure world - * @fn_id: The function ID for this syscall - * @desc: Descriptor structure containing arguments and return values - * - * Sends a command to the SCM and waits for the command to finish processing. - * This should *only* be called in pre-emptible context. - * - * A note on cache maintenance: - * Note that any buffers that are expected to be accessed by the secure world - * must be flushed before invoking scm_call and invalidated in the cache - * immediately after scm_call returns. An important point that must be noted - * is that on ARMV8 architectures, invalidation actually also causes a dirty - * cache line to be cleaned (flushed + unset-dirty-bit). Therefore it is of - * paramount importance that the buffer be flushed before invoking scm_call2, - * even if you don't care about the contents of that buffer. - * - * Note that cache maintenance on the argument buffer (desc->args) is taken care - * of by scm_call2; however, callers are responsible for any other cached - * buffers passed over to the secure world. -*/ -int scm_call2(u32 fn_id, struct scm_desc *desc) +static int __scm_call2(u32 fn_id, struct scm_desc *desc, bool retry) { int arglen = desc->arginfo & 0xf; int ret, retry_count = 0; @@ -670,7 +649,6 @@ int scm_call2(u32 fn_id, struct scm_desc *desc) return ret; x0 = fn_id | scm_version_mask; - do { mutex_lock(&scm_lock); @@ -700,13 +678,15 @@ int scm_call2(u32 fn_id, struct scm_desc *desc) mutex_unlock(&scm_lmh_lock); mutex_unlock(&scm_lock); + if (!retry) + goto out; if (ret == SCM_V2_EBUSY) msleep(SCM_EBUSY_WAIT_MS); if (retry_count == 33) pr_warn("scm: secure world has been busy for 1 second!\n"); - } while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY)); - + } while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY)); +out: if (ret < 0) pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n", x0, ret, desc->ret[0], desc->ret[1], desc->ret[2]); @@ -717,8 +697,46 @@ int scm_call2(u32 fn_id, struct scm_desc *desc) return scm_remap_error(ret); return 0; } + +/** + * scm_call2() - Invoke a syscall in the secure world + * @fn_id: The function ID for this syscall + * @desc: Descriptor structure containing arguments and return values + * + * Sends a command to the SCM and waits for the command to finish processing. + * This should *only* be called in pre-emptible context. + * + * A note on cache maintenance: + * Note that any buffers that are expected to be accessed by the secure world + * must be flushed before invoking scm_call and invalidated in the cache + * immediately after scm_call returns. An important point that must be noted + * is that on ARMV8 architectures, invalidation actually also causes a dirty + * cache line to be cleaned (flushed + unset-dirty-bit). Therefore it is of + * paramount importance that the buffer be flushed before invoking scm_call2, + * even if you don't care about the contents of that buffer. + * + * Note that cache maintenance on the argument buffer (desc->args) is taken care + * of by scm_call2; however, callers are responsible for any other cached + * buffers passed over to the secure world. + */ +int scm_call2(u32 fn_id, struct scm_desc *desc) +{ + return __scm_call2(fn_id, desc, true); +} EXPORT_SYMBOL(scm_call2); +/** + * scm_call2_noretry() - Invoke a syscall in the secure world + * + * Similar to scm_call2 except that there is no retry mechanism + * implemented. + */ +int scm_call2_noretry(u32 fn_id, struct scm_desc *desc) +{ + return __scm_call2(fn_id, desc, false); +} +EXPORT_SYMBOL(scm_call2_noretry); + /** * scm_call2_atomic() - Invoke a syscall in the secure world * diff --git a/include/soc/qcom/scm.h b/include/soc/qcom/scm.h index f0a3124dae00..e741d540a8d6 100644 --- a/include/soc/qcom/scm.h +++ b/include/soc/qcom/scm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -101,6 +101,8 @@ extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len, extern int scm_call2(u32 cmd_id, struct scm_desc *desc); +extern int scm_call2_noretry(u32 cmd_id, struct scm_desc *desc); + extern int scm_call2_atomic(u32 cmd_id, struct scm_desc *desc); extern int scm_call_noalloc(u32 svc_id, u32 cmd_id, const void *cmd_buf, @@ -150,6 +152,11 @@ static inline int scm_call2(u32 cmd_id, struct scm_desc *desc) return 0; } +static inline int scm_call2_noretry(u32 cmd_id, struct scm_desc *desc) +{ + return 0; +} + static inline int scm_call2_atomic(u32 cmd_id, struct scm_desc *desc) { return 0; -- cgit v1.2.3 From 195b2497d11037a2cd921b9c8aa54907ac343d11 Mon Sep 17 00:00:00 2001 From: Mohamed Sunfeer Date: Fri, 25 Oct 2019 23:53:01 +0530 Subject: qseecom: Fix compilation errors While porting the changes from 4.9 kernel version to 4.4 version, there are few function prototype got changed which leads to compilation error, this patch fixes those errors by using the appropriate functions and added some definitions. Change-Id: I525e84f25912377cad72f72b6d451702f9afd2c6 Signed-off-by: Mohamed Sunfeer --- drivers/misc/qseecom.c | 1607 +++++++++++++++++++++++++++--------------- include/soc/qcom/qseecomi.h | 151 ++-- include/uapi/linux/qseecom.h | 5 + 3 files changed, 1108 insertions(+), 655 deletions(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index d50144e0fed9..21ad3dc3abaa 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1,4 +1,5 @@ -/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver +/* + * QTI Secure Execution Environment Communicator (QSEECOM) driver * * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. * @@ -43,13 +44,13 @@ #include #include #include -#include "qseecom_legacy.h" #include "qseecom_kernel.h" #include #include #include #include "compat_qseecom.h" +#include #define QSEECOM_DEV "qseecom" #define QSEOS_VERSION_14 0x14 @@ -65,7 +66,7 @@ #define QSEE_CE_CLK_100MHZ 100000000 #define CE_CLK_DIV 1000000 -#define QSEECOM_MAX_SG_ENTRY 512 +#define QSEECOM_MAX_SG_ENTRY 4096 #define QSEECOM_SG_ENTRY_MSG_BUF_SZ_64BIT \ (QSEECOM_MAX_SG_ENTRY * SG_ENTRY_SZ_64BIT) @@ -100,6 +101,10 @@ #define QSEECOM_STATE_READY 2 #define QSEECOM_ICE_FDE_KEY_SIZE_MASK 2 +#define QSEECOM_SCM_EBUSY_WAIT_MS 30 +#define QSEECOM_SCM_EBUSY_MAX_RETRY 67 +#define QSEECOM_SCM_SECURE_WORLD_BUSY_COUNT 33 + /* * default ce info unit to 0 for * services which @@ -109,6 +114,9 @@ #define DEFAULT_CE_INFO_UNIT 0 #define DEFAULT_NUM_CE_INFO_UNIT 1 +#define FDE_FLAG_POS 4 +#define ENABLE_KEY_WRAP_IN_KS (1 << FDE_FLAG_POS) + enum qseecom_clk_definitions { CLK_DFAB = 0, CLK_SFPB, @@ -137,12 +145,25 @@ enum qseecom_ce_hw_instance { CLK_INVALID, }; +enum qseecom_listener_unregister_kthread_state { + LSNR_UNREG_KT_SLEEP = 0, + LSNR_UNREG_KT_WAKEUP, +}; + +enum qseecom_unload_app_kthread_state { + UNLOAD_APP_KT_SLEEP = 0, + UNLOAD_APP_KT_WAKEUP, +}; + static struct class *driver_class; static dev_t qseecom_device_no; static DEFINE_MUTEX(qsee_bw_mutex); static DEFINE_MUTEX(app_access_lock); static DEFINE_MUTEX(clk_access_lock); +static DEFINE_MUTEX(listener_access_lock); +static DEFINE_MUTEX(unload_app_pending_list_lock); + struct sglist_info { uint32_t indexAndFlags; @@ -182,13 +203,21 @@ struct qseecom_registered_listener_list { size_t sb_length; struct ion_handle *ihandle; /* Retrieve phy addr */ wait_queue_head_t rcv_req_wq; + /* rcv_req_flag: 0: ready and empty; 1: received req */ int rcv_req_flag; int send_resp_flag; bool listener_in_use; /* wq for thread blocked on this listener*/ wait_queue_head_t listener_block_app_wq; - struct sglist_info sglistinfo_ptr[MAX_ION_FD]; - uint32_t sglist_cnt; + struct sglist_info sglistinfo_ptr[MAX_ION_FD]; + uint32_t sglist_cnt; + int abort; + bool unregister_pending; +}; + +struct qseecom_unregister_pending_list { + struct list_head list; + struct qseecom_dev_handle *data; }; struct qseecom_registered_app_list { @@ -198,6 +227,7 @@ struct qseecom_registered_app_list { char app_name[MAX_APP_NAME_SIZE]; u32 app_arch; bool app_blocked; + u32 check_block; u32 blocked_on_listener_id; }; @@ -235,7 +265,6 @@ struct qseecom_clk { struct qseecom_control { struct ion_client *ion_clnt; /* Ion client */ struct list_head registered_listener_list_head; - spinlock_t registered_listener_list_lock; struct list_head registered_app_list_head; spinlock_t registered_app_list_lock; @@ -275,12 +304,29 @@ struct qseecom_control { unsigned int ce_opp_freq_hz; bool appsbl_qseecom_support; uint32_t qsee_reentrancy_support; + bool enable_key_wrap_in_ks; uint32_t app_block_ref_cnt; wait_queue_head_t app_block_wq; atomic_t qseecom_state; int is_apps_region_protected; bool smcinvoke_support; + + struct list_head unregister_lsnr_pending_list_head; + wait_queue_head_t register_lsnr_pending_wq; + struct task_struct *unregister_lsnr_kthread_task; + wait_queue_head_t unregister_lsnr_kthread_wq; + atomic_t unregister_lsnr_kthread_state; + + struct list_head unload_app_pending_list_head; + struct task_struct *unload_app_kthread_task; + wait_queue_head_t unload_app_kthread_wq; + atomic_t unload_app_kthread_state; +}; + +struct qseecom_unload_app_pending_list { + struct list_head list; + struct qseecom_dev_handle *data; }; struct qseecom_sec_buf_fd_info { @@ -305,10 +351,14 @@ struct qseecom_client_handle { char app_name[MAX_APP_NAME_SIZE]; u32 app_arch; struct qseecom_sec_buf_fd_info sec_buf_fd[MAX_ION_FD]; + bool from_smcinvoke; + bool unload_pending; }; struct qseecom_listener_handle { u32 id; + bool unregister_pending; + bool release_called; }; static struct qseecom_control qseecom; @@ -380,6 +430,8 @@ static int qseecom_free_ce_info(struct qseecom_dev_handle *data, void __user *argp); static int qseecom_query_ce_info(struct qseecom_dev_handle *data, void __user *argp); +static int __qseecom_unload_app(struct qseecom_dev_handle *data, + uint32_t app_id); static int get_qseecom_keymaster_status(char *str) { @@ -388,6 +440,25 @@ static int get_qseecom_keymaster_status(char *str) } __setup("androidboot.keymaster=", get_qseecom_keymaster_status); +static int __qseecom_scm_call2_locked(uint32_t smc_id, struct scm_desc *desc) +{ + int ret = 0; + int retry_count = 0; + + do { + ret = scm_call2_noretry(smc_id, desc); + if (ret == -EBUSY) { + mutex_unlock(&app_access_lock); + msleep(QSEECOM_SCM_EBUSY_WAIT_MS); + mutex_lock(&app_access_lock); + } + if (retry_count == QSEECOM_SCM_SECURE_WORLD_BUSY_COUNT) + pr_warn("secure world has been busy for 1 second!\n"); + } while (ret == -EBUSY && + (retry_count++ < QSEECOM_SCM_EBUSY_MAX_RETRY)); + return ret; +} + static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, const void *req_buf, void *resp_buf) { @@ -415,7 +486,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, svc_id, tz_cmd_id); return -EINVAL; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case SCM_SVC_ES: { @@ -426,10 +497,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, (struct qseecom_save_partition_hash_req *) req_buf; char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL); - if (!tzbuf) { - pr_err("error allocating data\n"); + + if (!tzbuf) return -ENOMEM; - } memset(tzbuf, 0, tzbuflen); memcpy(tzbuf, p_hash_req->digest, SHA256_DIGEST_LENGTH); @@ -439,7 +509,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = p_hash_req->partition_id; desc.args[1] = virt_to_phys(tzbuf); desc.args[2] = SHA256_DIGEST_LENGTH; - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -457,6 +527,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, case QSEOS_APP_START_COMMAND: { struct qseecom_load_app_ireq *req; struct qseecom_load_app_64bit_ireq *req_64bit; + smc_id = TZ_OS_APP_START_ID; desc.arginfo = TZ_OS_APP_START_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -473,11 +544,12 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[2] = req_64bit->phy_addr; } __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_APP_SHUTDOWN_COMMAND: { struct qseecom_unload_app_ireq *req; + req = (struct qseecom_unload_app_ireq *)req_buf; smc_id = TZ_OS_APP_SHUTDOWN_ID; desc.arginfo = TZ_OS_APP_SHUTDOWN_ID_PARAM_ID; @@ -489,11 +561,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, struct qseecom_check_app_ireq *req; u32 tzbuflen = PAGE_ALIGN(sizeof(req->app_name)); char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL); - if (!tzbuf) { - pr_err("Allocate %d bytes buffer failed\n", - tzbuflen); + + if (!tzbuf) return -ENOMEM; - } req = (struct qseecom_check_app_ireq *)req_buf; pr_debug("Lookup app_name = %s\n", req->app_name); strlcpy(tzbuf, req->app_name, sizeof(req->app_name)); @@ -503,13 +573,14 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = strlen(req->app_name); __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } case QSEOS_APP_REGION_NOTIFICATION: { struct qsee_apps_region_info_ireq *req; struct qsee_apps_region_info_64bit_ireq *req_64bit; + smc_id = TZ_OS_APP_REGION_NOTIFICATION_ID; desc.arginfo = TZ_OS_APP_REGION_NOTIFICATION_ID_PARAM_ID; @@ -526,12 +597,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[1] = req_64bit->size; } __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_LOAD_SERV_IMAGE_COMMAND: { struct qseecom_load_lib_image_ireq *req; struct qseecom_load_lib_image_64bit_ireq *req_64bit; + smc_id = TZ_OS_LOAD_SERVICES_IMAGE_ID; desc.arginfo = TZ_OS_LOAD_SERVICES_IMAGE_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -549,19 +621,20 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[2] = req_64bit->phy_addr; } __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_UNLOAD_SERV_IMAGE_COMMAND: { smc_id = TZ_OS_UNLOAD_SERVICES_IMAGE_ID; desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_REGISTER_LISTENER: { struct qseecom_register_listener_ireq *req; struct qseecom_register_listener_64bit_ireq *req_64bit; + desc.arginfo = TZ_OS_REGISTER_LISTENER_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -580,30 +653,29 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, } qseecom.smcinvoke_support = true; smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID; - __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); - if (ret) { + ret = __qseecom_scm_call2_locked(smc_id, &desc); + if (ret == -EIO) { + /* smcinvoke is not supported */ qseecom.smcinvoke_support = false; smc_id = TZ_OS_REGISTER_LISTENER_ID; - __qseecom_reentrancy_check_if_no_app_blocked( - smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); } break; } case QSEOS_DEREGISTER_LISTENER: { struct qseecom_unregister_listener_ireq *req; + req = (struct qseecom_unregister_listener_ireq *) req_buf; smc_id = TZ_OS_DEREGISTER_LISTENER_ID; desc.arginfo = TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID; desc.args[0] = req->listener_id; - __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_LISTENER_DATA_RSP_COMMAND: { struct qseecom_client_listener_data_irsp *req; + req = (struct qseecom_client_listener_data_irsp *) req_buf; smc_id = TZ_OS_LISTENER_RESPONSE_HANDLER_ID; @@ -611,7 +683,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, TZ_OS_LISTENER_RESPONSE_HANDLER_ID_PARAM_ID; desc.args[0] = req->listener_id; desc.args[1] = req->status; - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST: { @@ -639,12 +711,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[2] = req_64->sglistinfo_ptr; desc.args[3] = req_64->sglistinfo_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_LOAD_EXTERNAL_ELF_COMMAND: { struct qseecom_load_app_ireq *req; struct qseecom_load_app_64bit_ireq *req_64bit; + smc_id = TZ_OS_LOAD_EXTERNAL_IMAGE_ID; desc.arginfo = TZ_OS_LOAD_SERVICES_IMAGE_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -660,20 +733,21 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[2] = req_64bit->phy_addr; } __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND: { smc_id = TZ_OS_UNLOAD_EXTERNAL_IMAGE_ID; desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_CLIENT_SEND_DATA_COMMAND: { struct qseecom_client_send_data_ireq *req; struct qseecom_client_send_data_64bit_ireq *req_64bit; + smc_id = TZ_APP_QSAPP_SEND_DATA_ID; desc.arginfo = TZ_APP_QSAPP_SEND_DATA_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -694,7 +768,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->rsp_ptr; desc.args[4] = req_64bit->rsp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST: { @@ -726,32 +800,33 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_RPMB_PROVISION_KEY_COMMAND: { struct qseecom_client_send_service_ireq *req; + req = (struct qseecom_client_send_service_ireq *) req_buf; smc_id = TZ_OS_RPMB_PROVISION_KEY_ID; desc.arginfo = TZ_OS_RPMB_PROVISION_KEY_ID_PARAM_ID; desc.args[0] = req->key_type; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_RPMB_ERASE_COMMAND: { smc_id = TZ_OS_RPMB_ERASE_ID; desc.arginfo = TZ_OS_RPMB_ERASE_ID_PARAM_ID; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_RPMB_CHECK_PROV_STATUS_COMMAND: { smc_id = TZ_OS_RPMB_CHECK_PROV_STATUS_ID; desc.arginfo = TZ_OS_RPMB_CHECK_PROV_STATUS_ID_PARAM_ID; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_GENERATE_KEY: { @@ -759,6 +834,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, (struct qseecom_key_generate_ireq) - sizeof(uint32_t)); char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL); + if (!tzbuf) return -ENOMEM; memset(tzbuf, 0, tzbuflen); @@ -771,7 +847,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = tzbuflen; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -780,11 +856,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, (struct qseecom_key_delete_ireq) - sizeof(uint32_t)); char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL); - if (!tzbuf) { - pr_err("Allocate %d bytes buffer failed\n", - tzbuflen); + + if (!tzbuf) return -ENOMEM; - } memset(tzbuf, 0, tzbuflen); memcpy(tzbuf, req_buf + sizeof(uint32_t), (sizeof(struct qseecom_key_delete_ireq) - @@ -795,7 +869,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = tzbuflen; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -804,11 +878,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, (struct qseecom_key_select_ireq) - sizeof(uint32_t)); char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL); - if (!tzbuf) { - pr_err("Allocate %d bytes buffer failed\n", - tzbuflen); + + if (!tzbuf) return -ENOMEM; - } memset(tzbuf, 0, tzbuflen); memcpy(tzbuf, req_buf + sizeof(uint32_t), (sizeof(struct qseecom_key_select_ireq) - @@ -819,7 +891,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = tzbuflen; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -828,11 +900,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, (struct qseecom_key_userinfo_update_ireq) - sizeof(uint32_t)); char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL); - if (!tzbuf) { - pr_err("Allocate %d bytes buffer failed\n", - tzbuflen); + + if (!tzbuf) return -ENOMEM; - } memset(tzbuf, 0, tzbuflen); memcpy(tzbuf, req_buf + sizeof(uint32_t), (sizeof (struct qseecom_key_userinfo_update_ireq) - @@ -843,13 +913,14 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = tzbuflen; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } case QSEOS_TEE_OPEN_SESSION: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; + smc_id = TZ_APP_GPAPP_OPEN_SESSION_ID; desc.arginfo = TZ_APP_GPAPP_OPEN_SESSION_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -868,7 +939,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_OPEN_SESSION_WHITELIST: { @@ -898,12 +969,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_INVOKE_COMMAND: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; + smc_id = TZ_APP_GPAPP_INVOKE_COMMAND_ID; desc.arginfo = TZ_APP_GPAPP_INVOKE_COMMAND_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -922,7 +994,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_INVOKE_COMMAND_WHITELIST: { @@ -952,12 +1024,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_CLOSE_SESSION: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; + smc_id = TZ_APP_GPAPP_CLOSE_SESSION_ID; desc.arginfo = TZ_APP_GPAPP_CLOSE_SESSION_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { @@ -976,12 +1049,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_REQUEST_CANCELLATION: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; + smc_id = TZ_APP_GPAPP_REQUEST_CANCELLATION_ID; desc.arginfo = TZ_APP_GPAPP_REQUEST_CANCELLATION_ID_PARAM_ID; @@ -1001,7 +1075,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_CONTINUE_BLOCKED_REQ_COMMAND: { @@ -1016,11 +1090,11 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.arginfo = TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID; desc.args[0] = req->app_or_session_id; - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } default: { - pr_err("qseos_cmd_id 0x%d is not supported by armv8 scm_call2.\n", + pr_err("qseos_cmd_id %d is not supported by armv8 scm_call2.\n", qseos_cmd_id); ret = -EINVAL; break; @@ -1056,42 +1130,18 @@ static int qseecom_scm_call(u32 svc_id, u32 tz_cmd_id, const void *cmd_buf, return qseecom_scm_call2(svc_id, tz_cmd_id, cmd_buf, resp_buf); } -static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data, - struct qseecom_register_listener_req *svc) -{ - struct qseecom_registered_listener_list *ptr; - int unique = 1; - unsigned long flags; - - spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags); - list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) { - if (ptr->svc.listener_id == svc->listener_id) { - pr_err("Service id: %u is already registered\n", - ptr->svc.listener_id); - unique = 0; - break; - } - } - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags); - return unique; -} - static struct qseecom_registered_listener_list *__qseecom_find_svc( int32_t listener_id) { struct qseecom_registered_listener_list *entry = NULL; - unsigned long flags; - spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags); - list_for_each_entry(entry, &qseecom.registered_listener_list_head, list) - { + list_for_each_entry(entry, + &qseecom.registered_listener_list_head, list) { if (entry->svc.listener_id == listener_id) break; } - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags); - if ((entry != NULL) && (entry->svc.listener_id != listener_id)) { - pr_err("Service id: %u is not found\n", listener_id); + pr_debug("Service id: %u is not found\n", listener_id); return NULL; } @@ -1151,8 +1201,14 @@ static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc, resp.result = QSEOS_RESULT_INCOMPLETE; + mutex_unlock(&listener_access_lock); + mutex_lock(&app_access_lock); + __qseecom_reentrancy_check_if_no_app_blocked( + TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID); ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, &resp, sizeof(resp)); + mutex_unlock(&app_access_lock); + mutex_lock(&listener_access_lock); if (ret) { pr_err("qseecom_scm_call failed with err: %d\n", ret); return -EINVAL; @@ -1170,9 +1226,9 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, void __user *argp) { int ret = 0; - unsigned long flags; struct qseecom_register_listener_req rcvd_lstnr; struct qseecom_registered_listener_list *new_entry; + struct qseecom_registered_listener_list *ptr_svc; ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr)); if (ret) { @@ -1183,18 +1239,33 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, rcvd_lstnr.sb_size)) return -EFAULT; - data->listener.id = 0; - if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) { - pr_err("Service is not unique and is already registered\n"); - data->released = true; - return -EBUSY; + ptr_svc = __qseecom_find_svc(rcvd_lstnr.listener_id); + if (ptr_svc) { + if (ptr_svc->unregister_pending == false) { + pr_err("Service %d is not unique\n", + rcvd_lstnr.listener_id); + data->released = true; + return -EBUSY; + } + /*wait until listener is unregistered*/ + pr_debug("register %d has to wait\n", + rcvd_lstnr.listener_id); + mutex_unlock(&listener_access_lock); + ret = wait_event_interruptible( + qseecom.register_lsnr_pending_wq, + list_empty( + &qseecom.unregister_lsnr_pending_list_head)); + if (ret) { + pr_err("interrupted register_pending_wq %d\n", + rcvd_lstnr.listener_id); + mutex_lock(&listener_access_lock); + return -ERESTARTSYS; + } + mutex_lock(&listener_access_lock); } - new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); - if (!new_entry) { - pr_err("kmalloc failed\n"); + if (!new_entry) return -ENOMEM; - } memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr)); new_entry->rcv_req_flag = 0; @@ -1202,30 +1273,28 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, new_entry->sb_length = rcvd_lstnr.sb_size; new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base; if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) { - pr_err("qseecom_set_sb_memoryfailed\n"); + pr_err("qseecom_set_sb_memory failed for listener %d, size %d\n", + rcvd_lstnr.listener_id, rcvd_lstnr.sb_size); kzfree(new_entry); return -ENOMEM; } - data->listener.id = rcvd_lstnr.listener_id; init_waitqueue_head(&new_entry->rcv_req_wq); init_waitqueue_head(&new_entry->listener_block_app_wq); new_entry->send_resp_flag = 0; new_entry->listener_in_use = false; - spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags); list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head); - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags); + data->listener.id = rcvd_lstnr.listener_id; + pr_debug("Service %d is registered\n", rcvd_lstnr.listener_id); return ret; } -static int qseecom_unregister_listener(struct qseecom_dev_handle *data) +static int __qseecom_unregister_listener(struct qseecom_dev_handle *data, + struct qseecom_registered_listener_list *ptr_svc) { int ret = 0; - unsigned long flags; - uint32_t unmap_mem = 0; struct qseecom_register_listener_ireq req; - struct qseecom_registered_listener_list *ptr_svc = NULL; struct qseecom_command_scm_resp resp; struct ion_handle *ihandle = NULL; /* Retrieve phy addr */ @@ -1233,68 +1302,157 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data) req.listener_id = data->listener.id; resp.result = QSEOS_RESULT_INCOMPLETE; + mutex_unlock(&listener_access_lock); + mutex_lock(&app_access_lock); + __qseecom_reentrancy_check_if_no_app_blocked( + TZ_OS_DEREGISTER_LISTENER_ID); ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req), &resp, sizeof(resp)); + mutex_unlock(&app_access_lock); + mutex_lock(&listener_access_lock); if (ret) { pr_err("scm_call() failed with err: %d (lstnr id=%d)\n", ret, data->listener.id); - return ret; + if (ret == -EBUSY) + return ret; + goto exit; } if (resp.result != QSEOS_RESULT_SUCCESS) { pr_err("Failed resp.result=%d,(lstnr id=%d)\n", resp.result, data->listener.id); - return -EPERM; - } - - data->abort = 1; - spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags); - list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head, - list) { - if (ptr_svc->svc.listener_id == data->listener.id) { - wake_up_all(&ptr_svc->rcv_req_wq); - break; - } + ret = -EPERM; + goto exit; } - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags); while (atomic_read(&data->ioctl_count) > 1) { - if (wait_event_freezable(data->abort_wq, + if (wait_event_interruptible(data->abort_wq, atomic_read(&data->ioctl_count) <= 1)) { pr_err("Interrupted from abort\n"); ret = -ERESTARTSYS; - return ret; } } - spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags); - list_for_each_entry(ptr_svc, - &qseecom.registered_listener_list_head, - list) - { - if (ptr_svc->svc.listener_id == data->listener.id) { - if (ptr_svc->sb_virt) { - unmap_mem = 1; - ihandle = ptr_svc->ihandle; - } - list_del(&ptr_svc->list); - kzfree(ptr_svc); - break; - } - } - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags); - - /* Unmap the memory */ - if (unmap_mem) { +exit: + if (ptr_svc->sb_virt) { + ihandle = ptr_svc->ihandle; if (!IS_ERR_OR_NULL(ihandle)) { ion_unmap_kernel(qseecom.ion_clnt, ihandle); ion_free(qseecom.ion_clnt, ihandle); - } + } } + list_del(&ptr_svc->list); + kzfree(ptr_svc); + data->released = true; + pr_debug("Service %d is unregistered\n", data->listener.id); return ret; } +static int qseecom_unregister_listener(struct qseecom_dev_handle *data) +{ + struct qseecom_registered_listener_list *ptr_svc = NULL; + struct qseecom_unregister_pending_list *entry = NULL; + + if (data->released) { + pr_err("Don't unregister lsnr %d\n", data->listener.id); + return -EINVAL; + } + + ptr_svc = __qseecom_find_svc(data->listener.id); + if (!ptr_svc) { + pr_err("Unregiser invalid listener ID %d\n", data->listener.id); + return -ENODATA; + } + /* stop CA thread waiting for listener response */ + ptr_svc->abort = 1; + wake_up_interruptible_all(&qseecom.send_resp_wq); + + /* stop listener thread waiting for listener request */ + data->abort = 1; + wake_up_all(&ptr_svc->rcv_req_wq); + + /* return directly if pending*/ + if (ptr_svc->unregister_pending) + return 0; + + /*add unregistration into pending list*/ + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + entry->data = data; + list_add_tail(&entry->list, + &qseecom.unregister_lsnr_pending_list_head); + ptr_svc->unregister_pending = true; + pr_debug("unregister %d pending\n", data->listener.id); + return 0; +} + +static void __qseecom_processing_pending_lsnr_unregister(void) +{ + struct qseecom_unregister_pending_list *entry = NULL; + struct qseecom_registered_listener_list *ptr_svc = NULL; + struct list_head *pos; + int ret = 0; + + mutex_lock(&listener_access_lock); + while (!list_empty(&qseecom.unregister_lsnr_pending_list_head)) { + pos = qseecom.unregister_lsnr_pending_list_head.next; + entry = list_entry(pos, + struct qseecom_unregister_pending_list, list); + if (entry && entry->data) { + pr_debug("process pending unregister %d\n", + entry->data->listener.id); + /* don't process if qseecom_release is not called*/ + if (!entry->data->listener.release_called) + break; + ptr_svc = __qseecom_find_svc( + entry->data->listener.id); + if (ptr_svc) { + ret = __qseecom_unregister_listener( + entry->data, ptr_svc); + if (ret == -EBUSY) { + pr_debug("unregister %d pending again\n", + entry->data->listener.id); + mutex_unlock(&listener_access_lock); + return; + } + } else + pr_err("invalid listener %d\n", + entry->data->listener.id); + kzfree(entry->data); + } + list_del(pos); + kzfree(entry); + } + mutex_unlock(&listener_access_lock); + wake_up_interruptible(&qseecom.register_lsnr_pending_wq); +} + +static void __wakeup_unregister_listener_kthread(void) +{ + atomic_set(&qseecom.unregister_lsnr_kthread_state, + LSNR_UNREG_KT_WAKEUP); + wake_up_interruptible(&qseecom.unregister_lsnr_kthread_wq); +} + +static int __qseecom_unregister_listener_kthread_func(void *data) +{ + while (!kthread_should_stop()) { + wait_event_interruptible( + qseecom.unregister_lsnr_kthread_wq, + atomic_read(&qseecom.unregister_lsnr_kthread_state) + == LSNR_UNREG_KT_WAKEUP); + pr_debug("kthread to unregister listener is called %d\n", + atomic_read(&qseecom.unregister_lsnr_kthread_state)); + __qseecom_processing_pending_lsnr_unregister(); + atomic_set(&qseecom.unregister_lsnr_kthread_state, + LSNR_UNREG_KT_SLEEP); + } + pr_warn("kthread to unregister listener stopped\n"); + return 0; +} + static int __qseecom_set_msm_bus_request(uint32_t mode) { int ret = 0; @@ -1343,39 +1501,35 @@ static void qseecom_bw_inactive_req_work(struct work_struct *work) qseecom.timer_running = false; mutex_unlock(&qsee_bw_mutex); mutex_unlock(&app_access_lock); - return; } static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data) { schedule_work(&qseecom.bw_inactive_req_ws); - return; } static int __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce) { struct qseecom_clk *qclk; int ret = 0; + mutex_lock(&clk_access_lock); if (ce == CLK_QSEE) qclk = &qseecom.qsee; else qclk = &qseecom.ce_drv; - if (qclk->clk_access_cnt > 2) { + if (qclk->clk_access_cnt > 0) { + qclk->clk_access_cnt--; + } else { pr_err("Invalid clock ref count %d\n", qclk->clk_access_cnt); ret = -EINVAL; - goto err_dec_ref_cnt; } - if (qclk->clk_access_cnt == 2) - qclk->clk_access_cnt--; -err_dec_ref_cnt: mutex_unlock(&clk_access_lock); return ret; } - static int qseecom_scale_bus_bandwidth_timer(uint32_t mode) { int32_t ret = 0; @@ -1445,6 +1599,7 @@ static int __qseecom_register_bus_bandwidth_needs( static int qseecom_perf_enable(struct qseecom_dev_handle *data) { int ret = 0; + ret = qsee_vote_for_clock(data, CLK_DFAB); if (ret) { pr_err("Failed to vote for DFAB clock with err %d\n", ret); @@ -1481,9 +1636,9 @@ static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data, } /* - * Register bus bandwidth needs if bus scaling feature is enabled; - * otherwise, qseecom enable/disable clocks for the client directly. - */ + * Register bus bandwidth needs if bus scaling feature is enabled; + * otherwise, qseecom enable/disable clocks for the client directly. + */ if (qseecom.support_bus_scaling) { mutex_lock(&qsee_bw_mutex); ret = __qseecom_register_bus_bandwidth_needs(data, req_mode); @@ -1526,12 +1681,12 @@ static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data) else __qseecom_add_bw_scale_down_timer( QSEECOM_LOAD_APP_CRYPTO_TIMEOUT); - return; } static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data) { int ret = 0; + if (qseecom.support_bus_scaling) { ret = qseecom_scale_bus_bandwidth_timer(MEDIUM); if (ret) @@ -1583,7 +1738,7 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data, } if (len < req.sb_len) { - pr_err("Requested length (0x%x) is > allocated (0x%zu)\n", + pr_err("Requested length (0x%x) is > allocated (%zu)\n", req.sb_len, len); return -EINVAL; } @@ -1600,11 +1755,13 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data, return 0; } -static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data) +static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data, + struct qseecom_registered_listener_list *ptr_svc) { int ret; + ret = (qseecom.send_resp_flag != 0); - return ret || data->abort; + return ret || data->abort || ptr_svc->abort; } static int __qseecom_reentrancy_listener_has_sent_rsp( @@ -1614,56 +1771,7 @@ static int __qseecom_reentrancy_listener_has_sent_rsp( int ret; ret = (ptr_svc->send_resp_flag != 0); - return ret || data->abort; -} - -static int __qseecom_qseos_fail_return_resp_tz(struct qseecom_dev_handle *data, - struct qseecom_command_scm_resp *resp, - struct qseecom_client_listener_data_irsp *send_data_rsp, - struct qseecom_registered_listener_list *ptr_svc, - uint32_t lstnr) { - int ret = 0; - - send_data_rsp->status = QSEOS_RESULT_FAILURE; - qseecom.send_resp_flag = 0; - send_data_rsp->qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND; - send_data_rsp->listener_id = lstnr; - if (ptr_svc) - pr_warn("listener_id:%x, lstnr: %x\n", - ptr_svc->svc.listener_id, lstnr); - if (ptr_svc && ptr_svc->ihandle) { - ret = msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, - ptr_svc->sb_virt, ptr_svc->sb_length, - ION_IOC_CLEAN_INV_CACHES); - if (ret) { - pr_err("cache operation failed %d\n", ret); - return ret; - } - } - - if (lstnr == RPMB_SERVICE) { - ret = __qseecom_enable_clk(CLK_QSEE); - if (ret) - return ret; - } - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, send_data_rsp, - sizeof(send_data_rsp), resp, sizeof(*resp)); - if (ret) { - pr_err("scm_call() failed with err: %d (app_id = %d)\n", - ret, data->client.app_id); - if (lstnr == RPMB_SERVICE) - __qseecom_disable_clk(CLK_QSEE); - return ret; - } - if ((resp->result != QSEOS_RESULT_SUCCESS) && - (resp->result != QSEOS_RESULT_INCOMPLETE)) { - pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n", - resp->result, data->client.app_id, lstnr); - ret = -EINVAL; - } - if (lstnr == RPMB_SERVICE) - __qseecom_disable_clk(CLK_QSEE); - return ret; + return ret || data->abort || ptr_svc->abort; } static void __qseecom_clean_listener_sglistinfo( @@ -1682,9 +1790,9 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, int ret = 0; int rc = 0; uint32_t lstnr; - unsigned long flags; - struct qseecom_client_listener_data_irsp send_data_rsp; - struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit; + struct qseecom_client_listener_data_irsp send_data_rsp = {0}; + struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit + = {0}; struct qseecom_registered_listener_list *ptr_svc = NULL; sigset_t new_sigset; sigset_t old_sigset; @@ -1693,13 +1801,13 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, size_t cmd_len; struct sglist_info *table = NULL; + qseecom.app_block_ref_cnt++; while (resp->result == QSEOS_RESULT_INCOMPLETE) { lstnr = resp->data; /* * Wake up blocking lsitener service with the lstnr id */ - spin_lock_irqsave(&qseecom.registered_listener_list_lock, - flags); + mutex_lock(&listener_access_lock); list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head, list) { if (ptr_svc->svc.listener_id == lstnr) { @@ -1709,29 +1817,38 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, break; } } - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, - flags); if (ptr_svc == NULL) { pr_err("Listener Svc %d does not exist\n", lstnr); - __qseecom_qseos_fail_return_resp_tz(data, resp, - &send_data_rsp, ptr_svc, lstnr); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (!ptr_svc->ihandle) { pr_err("Client handle is not initialized\n"); - __qseecom_qseos_fail_return_resp_tz(data, resp, - &send_data_rsp, ptr_svc, lstnr); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (ptr_svc->svc.listener_id != lstnr) { - pr_warn("Service requested does not exist\n"); - __qseecom_qseos_fail_return_resp_tz(data, resp, - &send_data_rsp, NULL, lstnr); - return -ERESTARTSYS; + pr_err("Service %d does not exist\n", + lstnr); + rc = -ERESTARTSYS; + ptr_svc = NULL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } + + if (ptr_svc->abort == 1) { + pr_debug("Service %d abort %d\n", + lstnr, ptr_svc->abort); + rc = -ENODEV; + status = QSEOS_RESULT_FAILURE; + goto err_resp; + } + pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n"); /* initialize the new signal mask with all signals*/ @@ -1739,6 +1856,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, /* block all signals */ sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); + mutex_unlock(&listener_access_lock); do { /* * When reentrancy is not supported, check global @@ -1746,22 +1864,23 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, * send_resp_flag. */ if (!qseecom.qsee_reentrancy_support && - !wait_event_freezable(qseecom.send_resp_wq, - __qseecom_listener_has_sent_rsp(data))) { - break; + !wait_event_interruptible(qseecom.send_resp_wq, + __qseecom_listener_has_sent_rsp( + data, ptr_svc))) { + break; } if (qseecom.qsee_reentrancy_support && - !wait_event_freezable(qseecom.send_resp_wq, + !wait_event_interruptible(qseecom.send_resp_wq, __qseecom_reentrancy_listener_has_sent_rsp( data, ptr_svc))) { - break; + break; } } while (1); - + mutex_lock(&listener_access_lock); /* restore signal mask */ sigprocmask(SIG_SETMASK, &old_sigset, NULL); - if (data->abort) { + if (data->abort || ptr_svc->abort) { pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d", data->client.app_id, lstnr, ret); rc = -ENODEV; @@ -1769,76 +1888,91 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, } else { status = QSEOS_RESULT_SUCCESS; } - +err_resp: qseecom.send_resp_flag = 0; - ptr_svc->send_resp_flag = 0; - table = ptr_svc->sglistinfo_ptr; + if (ptr_svc) { + ptr_svc->send_resp_flag = 0; + table = ptr_svc->sglistinfo_ptr; + } if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_rsp.listener_id = lstnr; send_data_rsp.status = status; - send_data_rsp.sglistinfo_ptr = - (uint32_t)virt_to_phys(table); - send_data_rsp.sglistinfo_len = - SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp.sglistinfo_ptr = + (uint32_t)virt_to_phys(table); + send_data_rsp.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp; cmd_len = sizeof(send_data_rsp); } else { send_data_rsp_64bit.listener_id = lstnr; send_data_rsp_64bit.status = status; - send_data_rsp_64bit.sglistinfo_ptr = - virt_to_phys(table); - send_data_rsp_64bit.sglistinfo_len = - SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp_64bit.sglistinfo_ptr = + virt_to_phys(table); + send_data_rsp_64bit.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp_64bit; cmd_len = sizeof(send_data_rsp_64bit); } - if (qseecom.whitelist_support == false) + if (qseecom.whitelist_support == false || table == NULL) *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND; else *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST; - if (ptr_svc) { + if (ptr_svc && ptr_svc->ihandle) { ret = msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, ptr_svc->sb_virt, ptr_svc->sb_length, ION_IOC_CLEAN_INV_CACHES); if (ret) { pr_err("cache operation failed %d\n", ret); - return ret; + goto exit; } } if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) { ret = __qseecom_enable_clk(CLK_QSEE); if (ret) - return ret; + goto exit; } ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, resp, sizeof(*resp)); - ptr_svc->listener_in_use = false; - __qseecom_clean_listener_sglistinfo(ptr_svc); + if (ptr_svc) { + ptr_svc->listener_in_use = false; + __qseecom_clean_listener_sglistinfo(ptr_svc); + } if (ret) { pr_err("scm_call() failed with err: %d (app_id = %d)\n", ret, data->client.app_id); if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) __qseecom_disable_clk(CLK_QSEE); - return ret; + goto exit; } + pr_debug("resp status %d, res= %d, app_id = %d, lstr = %d\n", + status, resp->result, data->client.app_id, lstnr); if ((resp->result != QSEOS_RESULT_SUCCESS) && (resp->result != QSEOS_RESULT_INCOMPLETE)) { pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n", resp->result, data->client.app_id, lstnr); ret = -EINVAL; + goto exit; } +exit: + mutex_unlock(&listener_access_lock); if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) __qseecom_disable_clk(CLK_QSEE); } + qseecom.app_block_ref_cnt--; + wake_up_interruptible_all(&qseecom.app_block_wq); if (rc) return rc; @@ -1859,6 +1993,7 @@ static int __qseecom_process_reentrancy_blocked_on_listener( sigset_t old_sigset; unsigned long flags; bool found_app = false; + struct qseecom_registered_app_list dummy_app_entry = { {NULL} }; if (!resp || !data) { pr_err("invalid resp or data pointer\n"); @@ -1868,33 +2003,42 @@ static int __qseecom_process_reentrancy_blocked_on_listener( /* find app_id & img_name from list */ if (!ptr_app) { - spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); - list_for_each_entry(ptr_app, &qseecom.registered_app_list_head, - list) { - if ((ptr_app->app_id == data->client.app_id) && - (!strcmp(ptr_app->app_name, + if (data->client.from_smcinvoke) { + pr_debug("This request is from smcinvoke\n"); + ptr_app = &dummy_app_entry; + ptr_app->app_id = data->client.app_id; + } else { + spin_lock_irqsave(&qseecom.registered_app_list_lock, + flags); + list_for_each_entry(ptr_app, + &qseecom.registered_app_list_head, list) { + if ((ptr_app->app_id == data->client.app_id) && + (!strcmp(ptr_app->app_name, data->client.app_name))) { - found_app = true; - break; + found_app = true; + break; + } + } + spin_unlock_irqrestore( + &qseecom.registered_app_list_lock, flags); + if (!found_app) { + pr_err("app_id %d (%s) is not found\n", + data->client.app_id, + (char *)data->client.app_name); + ret = -ENOENT; + goto exit; } - } - spin_unlock_irqrestore(&qseecom.registered_app_list_lock, - flags); - if (!found_app) { - pr_err("app_id %d (%s) is not found\n", - data->client.app_id, - (char *)data->client.app_name); - ret = -ENOENT; - goto exit; } } do { session_id = resp->resp_type; + mutex_lock(&listener_access_lock); list_ptr = __qseecom_find_svc(resp->data); if (!list_ptr) { pr_err("Invalid listener ID %d\n", resp->data); ret = -ENODATA; + mutex_unlock(&listener_access_lock); goto exit; } ptr_app->blocked_on_listener_id = resp->data; @@ -1910,11 +2054,13 @@ static int __qseecom_process_reentrancy_blocked_on_listener( do { qseecom.app_block_ref_cnt++; ptr_app->app_blocked = true; + mutex_unlock(&listener_access_lock); mutex_unlock(&app_access_lock); - wait_event_freezable( + wait_event_interruptible( list_ptr->listener_block_app_wq, !list_ptr->listener_in_use); mutex_lock(&app_access_lock); + mutex_lock(&listener_access_lock); ptr_app->app_blocked = false; qseecom.app_block_ref_cnt--; } while (list_ptr->listener_in_use); @@ -1947,9 +2093,11 @@ static int __qseecom_process_reentrancy_blocked_on_listener( if (ret) { pr_err("unblock app %d or session %d fail\n", data->client.app_id, session_id); + mutex_unlock(&listener_access_lock); goto exit; } } + mutex_unlock(&listener_access_lock); resp->result = continue_resp.result; resp->resp_type = continue_resp.resp_type; resp->data = continue_resp.data; @@ -1971,9 +2119,9 @@ static int __qseecom_reentrancy_process_incomplete_cmd( int ret = 0; int rc = 0; uint32_t lstnr; - unsigned long flags; - struct qseecom_client_listener_data_irsp send_data_rsp; - struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit; + struct qseecom_client_listener_data_irsp send_data_rsp = {0}; + struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit + = {0}; struct qseecom_registered_listener_list *ptr_svc = NULL; sigset_t new_sigset; sigset_t old_sigset; @@ -1982,13 +2130,12 @@ static int __qseecom_reentrancy_process_incomplete_cmd( size_t cmd_len; struct sglist_info *table = NULL; - while (ret == 0 && rc == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) { + while (ret == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) { lstnr = resp->data; /* * Wake up blocking lsitener service with the lstnr id */ - spin_lock_irqsave(&qseecom.registered_listener_list_lock, - flags); + mutex_lock(&listener_access_lock); list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head, list) { if (ptr_svc->svc.listener_id == lstnr) { @@ -1998,23 +2145,38 @@ static int __qseecom_reentrancy_process_incomplete_cmd( break; } } - spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, - flags); if (ptr_svc == NULL) { pr_err("Listener Svc %d does not exist\n", lstnr); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (!ptr_svc->ihandle) { pr_err("Client handle is not initialized\n"); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (ptr_svc->svc.listener_id != lstnr) { - pr_warn("Service requested does not exist\n"); - return -ERESTARTSYS; + pr_err("Service %d does not exist\n", + lstnr); + rc = -ERESTARTSYS; + ptr_svc = NULL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } + + if (ptr_svc->abort == 1) { + pr_debug("Service %d abort %d\n", + lstnr, ptr_svc->abort); + rc = -ENODEV; + status = QSEOS_RESULT_FAILURE; + goto err_resp; + } + pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n"); /* initialize the new signal mask with all signals*/ @@ -2024,22 +2186,24 @@ static int __qseecom_reentrancy_process_incomplete_cmd( sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); /* unlock mutex btw waking listener and sleep-wait */ + mutex_unlock(&listener_access_lock); mutex_unlock(&app_access_lock); do { - if (!wait_event_freezable(qseecom.send_resp_wq, + if (!wait_event_interruptible(qseecom.send_resp_wq, __qseecom_reentrancy_listener_has_sent_rsp( data, ptr_svc))) { - break; + break; } } while (1); /* lock mutex again after resp sent */ mutex_lock(&app_access_lock); + mutex_lock(&listener_access_lock); ptr_svc->send_resp_flag = 0; qseecom.send_resp_flag = 0; /* restore signal mask */ sigprocmask(SIG_SETMASK, &old_sigset, NULL); - if (data->abort) { + if (data->abort || ptr_svc->abort) { pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d", data->client.app_id, lstnr, ret); rc = -ENODEV; @@ -2047,55 +2211,64 @@ static int __qseecom_reentrancy_process_incomplete_cmd( } else { status = QSEOS_RESULT_SUCCESS; } - table = ptr_svc->sglistinfo_ptr; +err_resp: + if (ptr_svc) + table = ptr_svc->sglistinfo_ptr; if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_rsp.listener_id = lstnr; send_data_rsp.status = status; - send_data_rsp.sglistinfo_ptr = - (uint32_t)virt_to_phys(table); - send_data_rsp.sglistinfo_len = SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp.sglistinfo_ptr = + (uint32_t)virt_to_phys(table); + send_data_rsp.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp; cmd_len = sizeof(send_data_rsp); } else { send_data_rsp_64bit.listener_id = lstnr; send_data_rsp_64bit.status = status; - send_data_rsp_64bit.sglistinfo_ptr = - virt_to_phys(table); - send_data_rsp_64bit.sglistinfo_len = - SGLISTINFO_TABLE_SIZE; - dmac_flush_range((void *)table, - (void *)table + SGLISTINFO_TABLE_SIZE); + if (table) { + send_data_rsp_64bit.sglistinfo_ptr = + virt_to_phys(table); + send_data_rsp_64bit.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + } cmd_buf = (void *)&send_data_rsp_64bit; cmd_len = sizeof(send_data_rsp_64bit); } - if (qseecom.whitelist_support == false) + if (qseecom.whitelist_support == false || table == NULL) *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND; else *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST; - if (ptr_svc) { + if (ptr_svc && ptr_svc->ihandle) { ret = msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, ptr_svc->sb_virt, ptr_svc->sb_length, ION_IOC_CLEAN_INV_CACHES); if (ret) { pr_err("cache operation failed %d\n", ret); - return ret; + goto exit; } } if (lstnr == RPMB_SERVICE) { ret = __qseecom_enable_clk(CLK_QSEE); if (ret) - return ret; + goto exit; } ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, resp, sizeof(*resp)); - ptr_svc->listener_in_use = false; - __qseecom_clean_listener_sglistinfo(ptr_svc); - wake_up_interruptible(&ptr_svc->listener_block_app_wq); + if (ptr_svc) { + ptr_svc->listener_in_use = false; + __qseecom_clean_listener_sglistinfo(ptr_svc); + wake_up_interruptible(&ptr_svc->listener_block_app_wq); + } if (ret) { pr_err("scm_call() failed with err: %d (app_id = %d)\n", @@ -2113,8 +2286,10 @@ static int __qseecom_reentrancy_process_incomplete_cmd( ret = -EINVAL; goto exit; } + mutex_unlock(&listener_access_lock); ret = __qseecom_process_reentrancy_blocked_on_listener( resp, NULL, data); + mutex_lock(&listener_access_lock); if (ret) { pr_err("failed to process App(%d) %s blocked on listener %d\n", data->client.app_id, @@ -2131,6 +2306,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd( goto exit; } exit: + mutex_unlock(&listener_access_lock); if (lstnr == RPMB_SERVICE) __qseecom_disable_clk(CLK_QSEE); @@ -2149,23 +2325,15 @@ exit: */ static void __qseecom_reentrancy_check_if_no_app_blocked(uint32_t smc_id) { - sigset_t new_sigset, old_sigset; - if (qseecom.qsee_reentrancy_support > QSEE_REENTRANCY_PHASE_0 && qseecom.qsee_reentrancy_support < QSEE_REENTRANCY_PHASE_3 && IS_OWNER_TRUSTED_OS(TZ_SYSCALL_OWNER_ID(smc_id))) { /* thread sleep until this app unblocked */ while (qseecom.app_block_ref_cnt > 0) { - sigfillset(&new_sigset); - sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); mutex_unlock(&app_access_lock); - do { - if (!wait_event_freezable(qseecom.app_block_wq, - (qseecom.app_block_ref_cnt == 0))) - break; - } while (1); + wait_event_interruptible(qseecom.app_block_wq, + (!qseecom.app_block_ref_cnt)); mutex_lock(&app_access_lock); - sigprocmask(SIG_SETMASK, &old_sigset, NULL); } } } @@ -2178,22 +2346,17 @@ static void __qseecom_reentrancy_check_if_no_app_blocked(uint32_t smc_id) static void __qseecom_reentrancy_check_if_this_app_blocked( struct qseecom_registered_app_list *ptr_app) { - sigset_t new_sigset, old_sigset; if (qseecom.qsee_reentrancy_support) { + ptr_app->check_block++; while (ptr_app->app_blocked || qseecom.app_block_ref_cnt > 1) { /* thread sleep until this app unblocked */ - sigfillset(&new_sigset); - sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); mutex_unlock(&app_access_lock); - do { - if (!wait_event_freezable(qseecom.app_block_wq, - (!ptr_app->app_blocked && - qseecom.app_block_ref_cnt <= 1))) - break; - } while (1); + wait_event_interruptible(qseecom.app_block_wq, + (!ptr_app->app_blocked && + qseecom.app_block_ref_cnt <= 1)); mutex_lock(&app_access_lock); - sigprocmask(SIG_SETMASK, &old_sigset, NULL); } + ptr_app->check_block--; } } @@ -2420,8 +2583,11 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) if (resp.result == QSEOS_RESULT_INCOMPLETE) { ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) { - pr_err("process_incomplete_cmd failed err: %d\n", - ret); + /* TZ has created app_id, need to unload it */ + pr_err("incomp_cmd err %d, %d, unload %d %s\n", + ret, resp.result, resp.data, + load_img_req.img_name); + __qseecom_unload_app(data, resp.data); if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); ret = -EFAULT; @@ -2442,7 +2608,6 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { - pr_err("kmalloc failed\n"); ret = -ENOMEM; goto loadapp_err; } @@ -2450,11 +2615,11 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) entry->ref_cnt = 1; entry->app_arch = load_img_req.app_arch; /* - * keymaster app may be first loaded as "keymaste" by qseecomd, - * and then used as "keymaster" on some targets. To avoid app - * name checking error, register "keymaster" into app_list and - * thread private data. - */ + * keymaster app may be first loaded as "keymaste" by qseecomd, + * and then used as "keymaster" on some targets. To avoid app + * name checking error, register "keymaster" into app_list and + * thread private data. + */ if (!strcmp(load_img_req.img_name, "keymaste")) strlcpy(entry->app_name, "keymaster", MAX_APP_NAME_SIZE); @@ -2463,6 +2628,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) MAX_APP_NAME_SIZE); entry->app_blocked = false; entry->blocked_on_listener_id = 0; + entry->check_block = 0; /* Deallocate the handle */ if (!IS_ERR_OR_NULL(ihandle)) @@ -2473,7 +2639,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags); - pr_warn("App with id %d (%s) now loaded\n", app_id, + pr_warn("App with id %u (%s) now loaded\n", app_id, (char *)(load_img_req.img_name)); } data->client.app_id = app_id; @@ -2511,11 +2677,12 @@ enable_clk_err: static int __qseecom_cleanup_app(struct qseecom_dev_handle *data) { int ret = 1; /* Set unload app */ + wake_up_all(&qseecom.send_resp_wq); if (qseecom.qsee_reentrancy_support) mutex_unlock(&app_access_lock); while (atomic_read(&data->ioctl_count) > 1) { - if (wait_event_freezable(data->abort_wq, + if (wait_event_interruptible(data->abort_wq, atomic_read(&data->ioctl_count) <= 1)) { pr_err("Interrupted from abort\n"); ret = -ERESTARTSYS; @@ -2530,6 +2697,7 @@ static int __qseecom_cleanup_app(struct qseecom_dev_handle *data) static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data) { int ret = 0; + if (!IS_ERR_OR_NULL(data->client.ihandle)) { ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle); ion_free(qseecom.ion_clnt, data->client.ihandle); @@ -2539,17 +2707,61 @@ static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data) return ret; } +static int __qseecom_unload_app(struct qseecom_dev_handle *data, + uint32_t app_id) +{ + struct qseecom_unload_app_ireq req; + struct qseecom_command_scm_resp resp; + int ret = 0; + + /* Populate the structure for sending scm call to load image */ + req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND; + req.app_id = app_id; + + /* SCM_CALL to unload the app */ + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req, + sizeof(struct qseecom_unload_app_ireq), + &resp, sizeof(resp)); + if (ret) { + pr_err("scm_call to unload app (id = %d) failed\n", app_id); + return -EFAULT; + } + switch (resp.result) { + case QSEOS_RESULT_SUCCESS: + pr_warn("App (%d) is unloaded\n", app_id); + break; + case QSEOS_RESULT_INCOMPLETE: + ret = __qseecom_process_incomplete_cmd(data, &resp); + if (ret) + pr_err("unload app %d fail proc incom cmd: %d,%d,%d\n", + app_id, ret, resp.result, resp.data); + else + pr_warn("App (%d) is unloaded\n", app_id); + break; + case QSEOS_RESULT_FAILURE: + pr_err("app (%d) unload_failed!!\n", app_id); + ret = -EFAULT; + break; + default: + pr_err("unload app %d get unknown resp.result %d\n", + app_id, resp.result); + ret = -EFAULT; + break; + } + return ret; +} + static int qseecom_unload_app(struct qseecom_dev_handle *data, bool app_crash) { unsigned long flags; unsigned long flags1; int ret = 0; - struct qseecom_command_scm_resp resp; struct qseecom_registered_app_list *ptr_app = NULL; bool unload = false; bool found_app = false; bool found_dead_app = false; + bool doublecheck = false; if (!data) { pr_err("Invalid/uninitialized device handle\n"); @@ -2572,15 +2784,15 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, if (!strcmp((void *)ptr_app->app_name, (void *)data->client.app_name)) { found_app = true; - if (ptr_app->app_blocked) + if (ptr_app->app_blocked || + ptr_app->check_block) app_crash = false; if (app_crash || ptr_app->ref_cnt == 1) unload = true; break; - } else { - found_dead_app = true; - break; } + found_dead_app = true; + break; } } spin_unlock_irqrestore(&qseecom.registered_app_list_lock, @@ -2599,42 +2811,30 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, (char *)data->client.app_name); if (unload) { - struct qseecom_unload_app_ireq req; - /* Populate the structure for sending scm call to load image */ - req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND; - req.app_id = data->client.app_id; + ret = __qseecom_unload_app(data, data->client.app_id); - /* SCM_CALL to unload the app */ - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req, - sizeof(struct qseecom_unload_app_ireq), - &resp, sizeof(resp)); - if (ret) { - pr_err("scm_call to unload app (id = %d) failed\n", - req.app_id); - ret = -EFAULT; - goto unload_exit; - } else { - pr_warn("App id %d now unloaded\n", req.app_id); - } - if (resp.result == QSEOS_RESULT_FAILURE) { - pr_err("app (%d) unload_failed!!\n", - data->client.app_id); - ret = -EFAULT; - goto unload_exit; - } - if (resp.result == QSEOS_RESULT_SUCCESS) - pr_debug("App (%d) is unloaded!!\n", - data->client.app_id); - if (resp.result == QSEOS_RESULT_INCOMPLETE) { - ret = __qseecom_process_incomplete_cmd(data, &resp); - if (ret) { - pr_err("process_incomplete_cmd fail err: %d\n", - ret); - goto unload_exit; + /* double check if this app_entry still exists */ + spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); + list_for_each_entry(ptr_app, + &qseecom.registered_app_list_head, list) { + if ((ptr_app->app_id == data->client.app_id) && + (!strcmp((void *)ptr_app->app_name, + (void *)data->client.app_name))) { + doublecheck = true; + break; } } + spin_unlock_irqrestore(&qseecom.registered_app_list_lock, + flags1); + if (!doublecheck) { + pr_warn("app %d(%s) entry is already removed\n", + data->client.app_id, + (char *)data->client.app_name); + found_app = false; + } } +unload_exit: if (found_app) { spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); if (app_crash) { @@ -2657,12 +2857,105 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, spin_unlock_irqrestore(&qseecom.registered_app_list_lock, flags1); } -unload_exit: qseecom_unmap_ion_allocated_memory(data); data->released = true; return ret; } + +static int qseecom_prepare_unload_app(struct qseecom_dev_handle *data) +{ + struct qseecom_unload_app_pending_list *entry = NULL; + + pr_debug("prepare to unload app(%d)(%s), pending %d\n", + data->client.app_id, data->client.app_name, + data->client.unload_pending); + if (data->client.unload_pending) + return 0; + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + entry->data = data; + list_add_tail(&entry->list, + &qseecom.unload_app_pending_list_head); + data->client.unload_pending = true; + pr_debug("unload ta %d pending\n", data->client.app_id); + return 0; +} + +static void __wakeup_unload_app_kthread(void) +{ + atomic_set(&qseecom.unload_app_kthread_state, + UNLOAD_APP_KT_WAKEUP); + wake_up_interruptible(&qseecom.unload_app_kthread_wq); +} + +static bool __qseecom_find_pending_unload_app(uint32_t app_id, char *app_name) +{ + struct qseecom_unload_app_pending_list *entry = NULL; + bool found = false; + + mutex_lock(&unload_app_pending_list_lock); + list_for_each_entry(entry, &qseecom.unload_app_pending_list_head, + list) { + if ((entry->data->client.app_id == app_id) && + (!strcmp(entry->data->client.app_name, app_name))) { + found = true; + break; + } + } + mutex_unlock(&unload_app_pending_list_lock); + return found; +} + +static void __qseecom_processing_pending_unload_app(void) +{ + struct qseecom_unload_app_pending_list *entry = NULL; + struct list_head *pos; + int ret = 0; + + mutex_lock(&unload_app_pending_list_lock); + while (!list_empty(&qseecom.unload_app_pending_list_head)) { + pos = qseecom.unload_app_pending_list_head.next; + entry = list_entry(pos, + struct qseecom_unload_app_pending_list, list); + if (entry && entry->data) { + pr_debug("process pending unload app %d (%s)\n", + entry->data->client.app_id, + entry->data->client.app_name); + mutex_unlock(&unload_app_pending_list_lock); + mutex_lock(&app_access_lock); + ret = qseecom_unload_app(entry->data, true); + if (ret) + pr_err("unload app %d pending failed %d\n", + entry->data->client.app_id, ret); + mutex_unlock(&app_access_lock); + mutex_lock(&unload_app_pending_list_lock); + kzfree(entry->data); + } + list_del(pos); + kzfree(entry); + } + mutex_unlock(&unload_app_pending_list_lock); +} + +static int __qseecom_unload_app_kthread_func(void *data) +{ + while (!kthread_should_stop()) { + wait_event_interruptible( + qseecom.unload_app_kthread_wq, + atomic_read(&qseecom.unload_app_kthread_state) + == UNLOAD_APP_KT_WAKEUP); + pr_debug("kthread to unload app is called, state %d\n", + atomic_read(&qseecom.unload_app_kthread_state)); + __qseecom_processing_pending_unload_app(); + atomic_set(&qseecom.unload_app_kthread_state, + UNLOAD_APP_KT_SLEEP); + } + pr_warn("kthread to unload app stopped\n"); + return 0; +} + static phys_addr_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data, unsigned long virt) { @@ -3066,7 +3359,7 @@ int __qseecom_process_reentrancy(struct qseecom_command_scm_resp *resp, ret = __qseecom_reentrancy_process_incomplete_cmd(data, resp); ptr_app->app_blocked = false; qseecom.app_block_ref_cnt--; - wake_up_interruptible(&qseecom.app_block_wq); + wake_up_interruptible_all(&qseecom.app_block_wq); if (ret) pr_err("process_incomplete_cmd failed err: %d\n", ret); @@ -3115,6 +3408,13 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, return -ENOENT; } + if (__qseecom_find_pending_unload_app(data->client.app_id, + data->client.app_name)) { + pr_err("app %d (%s) unload is pending\n", + data->client.app_id, data->client.app_name); + return -ENOENT; + } + if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_req.app_id = data->client.app_id; send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys( @@ -3246,23 +3546,23 @@ int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *req, if ((data->type != QSEECOM_LISTENER_SERVICE) && (req->ifd_data[i].fd > 0)) { - if ((req->cmd_req_len < sizeof(uint32_t)) || - (req->ifd_data[i].cmd_buf_offset > - req->cmd_req_len - sizeof(uint32_t))) { - pr_err("Invalid offset (req len) 0x%x\n", - req->ifd_data[i].cmd_buf_offset); - return -EINVAL; - } + if ((req->cmd_req_len < sizeof(uint32_t)) || + (req->ifd_data[i].cmd_buf_offset > + req->cmd_req_len - sizeof(uint32_t))) { + pr_err("Invalid offset (req len) 0x%x\n", + req->ifd_data[i].cmd_buf_offset); + return -EINVAL; + } } else if ((data->type == QSEECOM_LISTENER_SERVICE) && (lstnr_resp->ifd_data[i].fd > 0)) { - if ((lstnr_resp->resp_len < sizeof(uint32_t)) || - (lstnr_resp->ifd_data[i].cmd_buf_offset > - lstnr_resp->resp_len - sizeof(uint32_t))) { - pr_err("Invalid offset (lstnr resp len) 0x%x\n", - lstnr_resp->ifd_data[i].cmd_buf_offset); - return -EINVAL; - } + if ((lstnr_resp->resp_len < sizeof(uint32_t)) || + (lstnr_resp->ifd_data[i].cmd_buf_offset > + lstnr_resp->resp_len - sizeof(uint32_t))) { + pr_err("Invalid offset (lstnr resp len) 0x%x\n", + lstnr_resp->ifd_data[i].cmd_buf_offset); + return -EINVAL; } + } return 0; } @@ -3370,6 +3670,7 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup, sg = sg_ptr->sgl; if (sg_ptr->nents == 1) { uint32_t *update; + if (__boundary_checks_offset(req, lstnr_resp, data, i)) goto err; if ((data->type == QSEECOM_CLIENT_APP && @@ -3433,8 +3734,8 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup, update = (struct qseecom_sg_entry *)field; for (j = 0; j < sg_ptr->nents; j++) { /* - * Check if sg list PA is under 4GB - */ + * Check if sg list PA is under 4GB + */ if ((qseecom.qsee_version >= QSEE_VERSION_40) && (!cleanup) && @@ -3650,8 +3951,9 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, sg = sg_ptr->sgl; if (sg_ptr->nents == 1) { uint64_t *update_64bit; + if (__boundary_checks_offset_64(req, lstnr_resp, - data, i)) + data, i)) goto err; /* 64bit app uses 64bit address */ update_64bit = (uint64_t *) field; @@ -3834,7 +4136,8 @@ static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data, struct qseecom_registered_listener_list *svc) { int ret; - ret = (svc->rcv_req_flag != 0); + + ret = (svc->rcv_req_flag == 1); return ret || data->abort; } @@ -3843,14 +4146,17 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data) int ret = 0; struct qseecom_registered_listener_list *this_lstnr; + mutex_lock(&listener_access_lock); this_lstnr = __qseecom_find_svc(data->listener.id); if (!this_lstnr) { pr_err("Invalid listener ID\n"); + mutex_unlock(&listener_access_lock); return -ENODATA; } + mutex_unlock(&listener_access_lock); while (1) { - if (wait_event_freezable(this_lstnr->rcv_req_wq, + if (wait_event_interruptible(this_lstnr->rcv_req_wq, __qseecom_listener_has_rcvd_req(data, this_lstnr))) { pr_debug("Interrupted: exiting Listener Service = %d\n", @@ -3861,10 +4167,12 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data) if (data->abort) { pr_err("Aborting Listener Service = %d\n", - (uint32_t)data->listener.id); + (uint32_t)data->listener.id); return -ENODEV; } + mutex_lock(&listener_access_lock); this_lstnr->rcv_req_flag = 0; + mutex_unlock(&listener_access_lock); break; } return ret; @@ -4080,9 +4388,19 @@ static int __qseecom_allocate_img_data(struct ion_handle **pihandle, ion_phys_addr_t pa; struct ion_handle *ihandle = NULL; u8 *img_data = NULL; + int retry = 0; + int ion_flag = ION_FLAG_CACHED; - ihandle = ion_alloc(qseecom.ion_clnt, fw_size, - SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0); + do { + if (retry++) { + mutex_unlock(&app_access_lock); + msleep(QSEECOM_TA_ION_ALLOCATE_DELAY); + mutex_lock(&app_access_lock); + } + ihandle = ion_alloc(qseecom.ion_clnt, fw_size, + SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), ion_flag); + } while (IS_ERR_OR_NULL(ihandle) && + (retry <= QSEECOM_TA_ION_ALLOCATE_MAX_ATTEMP)); if (IS_ERR_OR_NULL(ihandle)) { pr_err("ION alloc failed\n"); @@ -4228,8 +4546,12 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname, ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, &resp, sizeof(resp)); if (ret) { - pr_err("scm_call to load failed : ret %d\n", ret); - ret = -EIO; + pr_err("scm_call to load failed : ret %d, result %x\n", + ret, resp.result); + if (resp.result == QSEOS_RESULT_FAIL_APP_ALREADY_LOADED) + ret = -EEXIST; + else + ret = -EIO; goto exit_disable_clk_vote; } @@ -4239,10 +4561,14 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname, break; case QSEOS_RESULT_INCOMPLETE: ret = __qseecom_process_incomplete_cmd(data, &resp); - if (ret) - pr_err("process_incomplete_cmd FAILED\n"); - else + if (ret) { + pr_err("incomp_cmd err %d, %d, unload %d %s\n", + ret, resp.result, resp.data, appname); + __qseecom_unload_app(data, resp.data); + ret = -EFAULT; + } else { *app_id = resp.data; + } break; case QSEOS_RESULT_FAILURE: pr_err("scm call failed with response QSEOS_RESULT FAILURE\n"); @@ -4438,6 +4764,9 @@ int qseecom_start_app(struct qseecom_handle **handle, uint32_t fw_size, app_arch; uint32_t app_id = 0; + __wakeup_unregister_listener_kthread(); + __wakeup_unload_app_kthread(); + if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", atomic_read(&qseecom.qseecom_state)); @@ -4455,19 +4784,13 @@ int qseecom_start_app(struct qseecom_handle **handle, } *handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL); - if (!(*handle)) { - pr_err("failed to allocate memory for kernel client handle\n"); + if (!(*handle)) return -ENOMEM; - } data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) { - pr_err("kmalloc failed\n"); - if (ret == 0) { - kfree(*handle); - *handle = NULL; - } - return -ENOMEM; + ret = -ENOMEM; + goto exit_handle_free; } data->abort = 0; data->type = QSEECOM_CLIENT_APP; @@ -4482,18 +4805,17 @@ int qseecom_start_app(struct qseecom_handle **handle, ION_HEAP(ION_QSECOM_HEAP_ID), 0); if (IS_ERR_OR_NULL(data->client.ihandle)) { pr_err("Ion client could not retrieve the handle\n"); - kfree(data); - kfree(*handle); - *handle = NULL; - return -EINVAL; + ret = -ENOMEM; + goto exit_data_free; } mutex_lock(&app_access_lock); +recheck: app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND; strlcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE); ret = __qseecom_check_app_exists(app_ireq, &app_id); if (ret) - goto err; + goto exit_ion_free; strlcpy(data->client.app_name, app_name, MAX_APP_NAME_SIZE); if (app_id) { @@ -4518,28 +4840,31 @@ int qseecom_start_app(struct qseecom_handle **handle, pr_debug("%s: Loading app for the first time'\n", qseecom.pdev->init_name); ret = __qseecom_load_fw(data, app_name, &app_id); - if (ret < 0) - goto err; + if (ret == -EEXIST) { + pr_err("recheck if TA %s is loaded\n", app_name); + goto recheck; + } else if (ret < 0) + goto exit_ion_free; } data->client.app_id = app_id; if (!found_app) { entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) { pr_err("kmalloc for app entry failed\n"); - ret = -ENOMEM; - goto err; + ret = -ENOMEM; + goto exit_ion_free; } entry->app_id = app_id; entry->ref_cnt = 1; strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE); if (__qseecom_get_fw_size(app_name, &fw_size, &app_arch)) { ret = -EIO; - kfree(entry); - goto err; + goto exit_entry_free; } entry->app_arch = app_arch; entry->app_blocked = false; entry->blocked_on_listener_id = 0; + entry->check_block = 0; spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); list_add_tail(&entry->list, &qseecom.registered_app_list_head); spin_unlock_irqrestore(&qseecom.registered_app_list_lock, @@ -4551,7 +4876,7 @@ int qseecom_start_app(struct qseecom_handle **handle, if (ret) { pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n", ret); - goto err; + goto exit_entry_free; } /* Populate the structure for sending scm call to load image */ @@ -4560,7 +4885,7 @@ int qseecom_start_app(struct qseecom_handle **handle, if (IS_ERR_OR_NULL(data->client.sb_virt)) { pr_err("ION memory mapping for client shared buf failed\n"); ret = -ENOMEM; - goto err; + goto exit_entry_free; } data->client.user_virt_sb_base = (uintptr_t)data->client.sb_virt; data->client.sb_phys = (phys_addr_t)pa; @@ -4570,9 +4895,8 @@ int qseecom_start_app(struct qseecom_handle **handle, kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL); if (!kclient_entry) { - pr_err("kmalloc failed\n"); ret = -ENOMEM; - goto err; + goto exit_ion_unmap_kernel; } kclient_entry->handle = *handle; @@ -4582,13 +4906,28 @@ int qseecom_start_app(struct qseecom_handle **handle, spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags); mutex_unlock(&app_access_lock); + __wakeup_unload_app_kthread(); return 0; -err: - kfree(data); - kfree(*handle); - *handle = NULL; +exit_ion_unmap_kernel: + if (!IS_ERR_OR_NULL(data->client.ihandle)) + ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle); +exit_entry_free: + kfree(entry); +exit_ion_free: mutex_unlock(&app_access_lock); + if (!IS_ERR_OR_NULL(data->client.ihandle)) { + ion_free(qseecom.ion_clnt, data->client.ihandle); + data->client.ihandle = NULL; + } +exit_data_free: + kfree(data); +exit_handle_free: + if (*handle) { + kfree(*handle); + *handle = NULL; + } + __wakeup_unload_app_kthread(); return ret; } EXPORT_SYMBOL(qseecom_start_app); @@ -4602,6 +4941,9 @@ int qseecom_shutdown_app(struct qseecom_handle **handle) unsigned long flags = 0; bool found_handle = false; + __wakeup_unregister_listener_kthread(); + __wakeup_unload_app_kthread(); + if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", atomic_read(&qseecom.qseecom_state)); @@ -4637,7 +4979,7 @@ int qseecom_shutdown_app(struct qseecom_handle **handle) kzfree(kclient); *handle = NULL; } - + __wakeup_unload_app_kthread(); return ret; } EXPORT_SYMBOL(qseecom_shutdown_app); @@ -4650,6 +4992,9 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, struct qseecom_dev_handle *data; bool perf_enabled = false; + __wakeup_unregister_listener_kthread(); + __wakeup_unload_app_kthread(); + if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", atomic_read(&qseecom.qseecom_state)); @@ -4680,11 +5025,11 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, } } /* - * On targets where crypto clock is handled by HLOS, - * if clk_access_cnt is zero and perf_enabled is false, - * then the crypto clock was not enabled before sending cmd - * to tz, qseecom will enable the clock to avoid service failure. - */ + * On targets where crypto clock is handled by HLOS, + * if clk_access_cnt is zero and perf_enabled is false, + * then the crypto clock was not enabled before sending cmd + * to tz, qseecom will enable the clock to avoid service failure. + */ if (!qseecom.no_clock_support && !qseecom.qsee.clk_access_cnt && !data->perf_enabled) { pr_debug("ce clock is not enabled!\n"); @@ -4725,6 +5070,7 @@ EXPORT_SYMBOL(qseecom_send_command); int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high) { int ret = 0; + if ((handle == NULL) || (handle->dev == NULL)) { pr_err("No valid kernel client\n"); return -EINVAL; @@ -4772,6 +5118,7 @@ int qseecom_process_listener_from_smcinvoke(struct scm_desc *desc) resp.data = desc->ret[2]; /*listener_id*/ dummy_private_data.client.app_id = desc->ret[1]; + dummy_private_data.client.from_smcinvoke = true; dummy_app_entry.app_id = desc->ret[1]; mutex_lock(&app_access_lock); @@ -5441,6 +5788,7 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data, MAX_APP_NAME_SIZE); entry->app_blocked = false; entry->blocked_on_listener_id = 0; + entry->check_block = 0; spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); list_add_tail(&entry->list, @@ -5722,9 +6070,9 @@ static int __qseecom_update_current_key_user_info( int ret; if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION || - usage >= QSEOS_KM_USAGE_MAX) { - pr_err("Error:: unsupported usage %d\n", usage); - return -EFAULT; + usage >= QSEOS_KM_USAGE_MAX) { + pr_err("Error:: unsupported usage %d\n", usage); + return -EFAULT; } ret = __qseecom_enable_clk(CLK_QSEE); if (ret) @@ -5890,6 +6238,9 @@ static int qseecom_create_key(struct qseecom_dev_handle *data, else flags |= QSEECOM_ICE_FDE_KEY_SIZE_16_BYTE; + if (qseecom.enable_key_wrap_in_ks == true) + flags |= ENABLE_KEY_WRAP_IN_KS; + generate_key_ireq.flags = flags; generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY; memset((void *)generate_key_ireq.key_id, @@ -5938,10 +6289,12 @@ static int qseecom_create_key(struct qseecom_dev_handle *data, memcpy((void *)set_key_ireq.hash32, (void *)create_key_req.hash32, QSEECOM_HASH_SIZE); - - /* It will return false if it is GPCE based crypto instance or - ICE is setup properly */ - if (qseecom_enable_ice_setup(create_key_req.usage)) + /* + * It will return false if it is GPCE based crypto instance or + * ICE is setup properly + */ + ret = qseecom_enable_ice_setup(create_key_req.usage); + if (ret) goto free_buf; do { @@ -6066,9 +6419,12 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data, clear_key_ireq.key_id[i] = QSEECOM_INVALID_KEY_ID; memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE); - /* It will return false if it is GPCE based crypto instance or - ICE is setup properly */ - if (qseecom_enable_ice_setup(wipe_key_req.usage)) + /* + * It will return false if it is GPCE based crypto instance or + * ICE is setup properly + */ + ret = qseecom_enable_ice_setup(wipe_key_req.usage); + if (ret) goto free_buf; ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage, @@ -6149,7 +6505,7 @@ static int qseecom_update_key_user_info(struct qseecom_dev_handle *data, } static int qseecom_is_es_activated(void __user *argp) { - struct qseecom_is_es_activated_req req; + struct qseecom_is_es_activated_req req = {0}; struct qseecom_command_scm_resp resp; int ret; @@ -6240,9 +6596,9 @@ static int qseecom_mdtp_cipher_dip(void __user *argp) req.in_buf_size == 0 || req.in_buf_size > MAX_DIP || req.out_buf_size == 0 || req.out_buf_size > MAX_DIP || req.direction > 1) { - pr_err("invalid parameters\n"); - ret = -EINVAL; - break; + pr_err("invalid parameters\n"); + ret = -EINVAL; + break; } /* Copy the input buffer from userspace to kernel space */ @@ -6285,7 +6641,7 @@ static int qseecom_mdtp_cipher_dip(void __user *argp) if (ret) break; - ret = scm_call2(TZ_MDTP_CIPHER_DIP_ID, &desc); + ret = __qseecom_scm_call2_locked(TZ_MDTP_CIPHER_DIP_ID, &desc); __qseecom_disable_clk(CLK_QSEE); @@ -6400,10 +6756,10 @@ static int __qseecom_qteec_handle_pre_alc_fd(struct qseecom_dev_handle *data, return -ENOMEM; } /* - * Allocate a buffer, populate it with number of entry plus - * each sg entry's phy addr and lenth; then return the - * phy_addr of the buffer. - */ + * Allocate a buffer, populate it with number of entry plus + * each sg entry's phy addr and length; then return the + * phy_addr of the buffer. + */ size = sizeof(uint32_t) + sizeof(struct qseecom_sg_entry) * sg_ptr->nents; size = (size + PAGE_SIZE) & PAGE_MASK; @@ -6604,6 +6960,12 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, (char *)data->client.app_name); return -ENOENT; } + if (__qseecom_find_pending_unload_app(data->client.app_id, + data->client.app_name)) { + pr_err("app %d (%s) unload is pending\n", + data->client.app_id, data->client.app_name); + return -ENOENT; + } req->req_ptr = (void *)__qseecom_uvirt_to_kvirt(data, (uintptr_t)req->req_ptr); @@ -6807,6 +7169,12 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data, (char *)data->client.app_name); return -ENOENT; } + if (__qseecom_find_pending_unload_app(data->client.app_id, + data->client.app_name)) { + pr_err("app %d (%s) unload is pending\n", + data->client.app_id, data->client.app_name); + return -ENOENT; + } /* validate offsets */ for (i = 0; i < MAX_ION_FD; i++) { @@ -6937,61 +7305,8 @@ static void __qseecom_clean_data_sglistinfo(struct qseecom_dev_handle *data) } } - -static int __qseecom_bus_scaling_enable(struct qseecom_dev_handle *data, - bool *perf_enabled) -{ - int ret = 0; - - if (qseecom.support_bus_scaling) { - if (!data->mode) { - mutex_lock(&qsee_bw_mutex); - __qseecom_register_bus_bandwidth_needs( - data, HIGH); - mutex_unlock(&qsee_bw_mutex); - } - ret = qseecom_scale_bus_bandwidth_timer(INACTIVE); - if (ret) { - pr_err("Failed to set bw\n"); - ret = -EINVAL; - goto exit; - } - } - /* - * On targets where crypto clock is handled by HLOS, - * if clk_access_cnt is zero and perf_enabled is false, - * then the crypto clock was not enabled before sending cmd - * to tz, qseecom will enable the clock to avoid service failure. - */ - if (!qseecom.no_clock_support && - !qseecom.qsee.clk_access_cnt && !data->perf_enabled) { - pr_debug("ce clock is not enabled\n"); - ret = qseecom_perf_enable(data); - if (ret) { - pr_err("Failed to vote for clock with err %d\n", - ret); - ret = -EINVAL; - goto exit; - } - *perf_enabled = true; - } -exit: - return ret; -} - -static void __qseecom_bus_scaling_disable(struct qseecom_dev_handle *data, - bool perf_enabled) -{ - if (qseecom.support_bus_scaling) - __qseecom_add_bw_scale_down_timer( - QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); - if (perf_enabled) { - qsee_disable_clock_vote(data, CLK_DFAB); - qsee_disable_clock_vote(data, CLK_SFPB); - } -} - -long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) +long qseecom_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) { int ret = 0; struct qseecom_dev_handle *data = file->private_data; @@ -7007,6 +7322,12 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) pr_err("Aborting qseecom driver\n"); return -ENODEV; } + if (cmd != QSEECOM_IOCTL_RECEIVE_REQ && + cmd != QSEECOM_IOCTL_SEND_RESP_REQ && + cmd != QSEECOM_IOCTL_SEND_MODFD_RESP && + cmd != QSEECOM_IOCTL_SEND_MODFD_RESP_64) + __wakeup_unregister_listener_kthread(); + __wakeup_unload_app_kthread(); switch (cmd) { case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: { @@ -7017,17 +7338,18 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) break; } pr_debug("ioctl register_listener_req()\n"); - mutex_lock(&app_access_lock); + mutex_lock(&listener_access_lock); atomic_inc(&data->ioctl_count); data->type = QSEECOM_LISTENER_SERVICE; ret = qseecom_register_listener(data, argp); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); - mutex_unlock(&app_access_lock); + mutex_unlock(&listener_access_lock); if (ret) pr_err("failed qseecom_register_listener: %d\n", ret); break; } + case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: { if ((data->listener.id == 0) || (data->type != QSEECOM_LISTENER_SERVICE)) { @@ -7037,12 +7359,12 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) break; } pr_debug("ioctl unregister_listener_req()\n"); - mutex_lock(&app_access_lock); + mutex_lock(&listener_access_lock); atomic_inc(&data->ioctl_count); ret = qseecom_unregister_listener(data); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); - mutex_unlock(&app_access_lock); + mutex_unlock(&listener_access_lock); if (ret) pr_err("failed qseecom_unregister_listener: %d\n", ret); break; @@ -7057,14 +7379,50 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) } /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); - ret = __qseecom_bus_scaling_enable(data, &perf_enabled); - if (ret) { - mutex_unlock(&app_access_lock); - break; + if (qseecom.support_bus_scaling) { + /* register bus bw in case the client doesn't do it */ + if (!data->mode) { + mutex_lock(&qsee_bw_mutex); + __qseecom_register_bus_bandwidth_needs( + data, HIGH); + mutex_unlock(&qsee_bw_mutex); + } + ret = qseecom_scale_bus_bandwidth_timer(INACTIVE); + if (ret) { + pr_err("Failed to set bw.\n"); + ret = -EINVAL; + mutex_unlock(&app_access_lock); + break; + } + } + /* + * On targets where crypto clock is handled by HLOS, + * if clk_access_cnt is zero and perf_enabled is false, + * then the crypto clock was not enabled before sending cmd to + * tz, qseecom will enable the clock to avoid service failure. + */ + if (!qseecom.no_clock_support && + !qseecom.qsee.clk_access_cnt && !data->perf_enabled) { + pr_debug("ce clock is not enabled!\n"); + ret = qseecom_perf_enable(data); + if (ret) { + pr_err("Failed to vote for clock with err %d\n", + ret); + mutex_unlock(&app_access_lock); + ret = -EINVAL; + break; + } + perf_enabled = true; } atomic_inc(&data->ioctl_count); ret = qseecom_send_cmd(data, argp); - __qseecom_bus_scaling_disable(data, perf_enabled); + if (qseecom.support_bus_scaling) + __qseecom_add_bw_scale_down_timer( + QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); + if (perf_enabled) { + qsee_disable_clock_vote(data, CLK_DFAB); + qsee_disable_clock_vote(data, CLK_SFPB); + } atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); @@ -7083,17 +7441,52 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) } /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); - ret = __qseecom_bus_scaling_enable(data, &perf_enabled); - if (ret) { - mutex_unlock(&app_access_lock); - break; + if (qseecom.support_bus_scaling) { + if (!data->mode) { + mutex_lock(&qsee_bw_mutex); + __qseecom_register_bus_bandwidth_needs( + data, HIGH); + mutex_unlock(&qsee_bw_mutex); + } + ret = qseecom_scale_bus_bandwidth_timer(INACTIVE); + if (ret) { + pr_err("Failed to set bw.\n"); + mutex_unlock(&app_access_lock); + ret = -EINVAL; + break; + } + } + /* + * On targets where crypto clock is handled by HLOS, + * if clk_access_cnt is zero and perf_enabled is false, + * then the crypto clock was not enabled before sending cmd to + * tz, qseecom will enable the clock to avoid service failure. + */ + if (!qseecom.no_clock_support && + !qseecom.qsee.clk_access_cnt && !data->perf_enabled) { + pr_debug("ce clock is not enabled!\n"); + ret = qseecom_perf_enable(data); + if (ret) { + pr_err("Failed to vote for clock with err %d\n", + ret); + mutex_unlock(&app_access_lock); + ret = -EINVAL; + break; + } + perf_enabled = true; } atomic_inc(&data->ioctl_count); if (cmd == QSEECOM_IOCTL_SEND_MODFD_CMD_REQ) ret = qseecom_send_modfd_cmd(data, argp); else ret = qseecom_send_modfd_cmd_64(data, argp); - __qseecom_bus_scaling_disable(data, perf_enabled); + if (qseecom.support_bus_scaling) + __qseecom_add_bw_scale_down_timer( + QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); + if (perf_enabled) { + qsee_disable_clock_vote(data, CLK_DFAB); + qsee_disable_clock_vote(data, CLK_SFPB); + } atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); @@ -7126,6 +7519,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) ret = -EINVAL; break; } + mutex_lock(&listener_access_lock); atomic_inc(&data->ioctl_count); if (!qseecom.qsee_reentrancy_support) ret = qseecom_send_resp(); @@ -7133,6 +7527,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) ret = qseecom_reentrancy_send_resp(data); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); + mutex_unlock(&listener_access_lock); if (ret) pr_err("failed qseecom_send_resp: %d\n", ret); break; @@ -7174,6 +7569,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&app_access_lock); if (ret) pr_err("failed load_app request: %d\n", ret); + __wakeup_unload_app_kthread(); break; } case QSEECOM_IOCTL_UNLOAD_APP_REQ: { @@ -7192,6 +7588,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&app_access_lock); if (ret) pr_err("failed unload_app request: %d\n", ret); + __wakeup_unload_app_kthread(); break; } case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: { @@ -7475,6 +7872,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) ret = -EINVAL; break; } + mutex_lock(&listener_access_lock); atomic_inc(&data->ioctl_count); if (cmd == QSEECOM_IOCTL_SEND_MODFD_RESP) ret = qseecom_send_modfd_resp(data, argp); @@ -7482,6 +7880,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) ret = qseecom_send_modfd_resp_64(data, argp); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); + mutex_unlock(&listener_access_lock); if (ret) pr_err("failed qseecom_send_mod_resp: %d\n", ret); __qseecom_clean_data_sglistinfo(data); @@ -7502,14 +7901,8 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) } /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); - ret = __qseecom_bus_scaling_enable(data, &perf_enabled); - if (ret) { - mutex_unlock(&app_access_lock); - break; - } atomic_inc(&data->ioctl_count); ret = qseecom_qteec_open_session(data, argp); - __qseecom_bus_scaling_disable(data, perf_enabled); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); @@ -7557,14 +7950,8 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) } /* Only one client allowed here at a time */ mutex_lock(&app_access_lock); - ret = __qseecom_bus_scaling_enable(data, &perf_enabled); - if (ret) { - mutex_unlock(&app_access_lock); - break; - } atomic_inc(&data->ioctl_count); ret = qseecom_qteec_invoke_modfd_cmd(data, argp); - __qseecom_bus_scaling_disable(data, perf_enabled); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); @@ -7634,10 +8021,8 @@ static int qseecom_open(struct inode *inode, struct file *file) struct qseecom_dev_handle *data; data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - pr_err("kmalloc failed\n"); + if (!data) return -ENOMEM; - } file->private_data = data; data->abort = 0; data->type = QSEECOM_GENERIC; @@ -7649,24 +8034,57 @@ static int qseecom_open(struct inode *inode, struct file *file) return ret; } +static void __qseecom_release_disable_clk(struct qseecom_dev_handle *data) +{ + if (qseecom.no_clock_support) + return; + if (qseecom.support_bus_scaling) { + mutex_lock(&qsee_bw_mutex); + if (data->mode != INACTIVE) { + qseecom_unregister_bus_bandwidth_needs(data); + if (qseecom.cumulative_mode == INACTIVE) + __qseecom_set_msm_bus_request(INACTIVE); + } + mutex_unlock(&qsee_bw_mutex); + } else { + if (data->fast_load_enabled) + qsee_disable_clock_vote(data, CLK_SFPB); + if (data->perf_enabled) + qsee_disable_clock_vote(data, CLK_DFAB); + } +} + static int qseecom_release(struct inode *inode, struct file *file) { struct qseecom_dev_handle *data = file->private_data; int ret = 0; + bool free_private_data = true; - if (data->released == false) { + __qseecom_release_disable_clk(data); + if (!data->released) { pr_debug("data: released=false, type=%d, mode=%d, data=0x%pK\n", data->type, data->mode, data); switch (data->type) { case QSEECOM_LISTENER_SERVICE: - mutex_lock(&app_access_lock); + pr_debug("release lsnr svc %d\n", data->listener.id); + mutex_lock(&listener_access_lock); ret = qseecom_unregister_listener(data); - mutex_unlock(&app_access_lock); + if (!ret) + free_private_data = false; + data->listener.release_called = true; + mutex_unlock(&listener_access_lock); + __wakeup_unregister_listener_kthread(); break; case QSEECOM_CLIENT_APP: - mutex_lock(&app_access_lock); - ret = qseecom_unload_app(data, true); - mutex_unlock(&app_access_lock); + pr_debug("release app %d (%s)\n", + data->client.app_id, data->client.app_name); + if (data->client.app_id) { + free_private_data = false; + mutex_lock(&unload_app_pending_list_lock); + ret = qseecom_prepare_unload_app(data); + mutex_unlock(&unload_app_pending_list_lock); + __wakeup_unload_app_kthread(); + } break; case QSEECOM_SECURE_SERVICE: case QSEECOM_GENERIC: @@ -7683,34 +8101,19 @@ static int qseecom_release(struct inode *inode, struct file *file) } } - if (qseecom.support_bus_scaling) { - mutex_lock(&qsee_bw_mutex); - if (data->mode != INACTIVE) { - qseecom_unregister_bus_bandwidth_needs(data); - if (qseecom.cumulative_mode == INACTIVE) { - ret = __qseecom_set_msm_bus_request(INACTIVE); - if (ret) - pr_err("Fail to scale down bus\n"); - } - } - mutex_unlock(&qsee_bw_mutex); - } else { - if (data->fast_load_enabled == true) - qsee_disable_clock_vote(data, CLK_SFPB); - if (data->perf_enabled == true) - qsee_disable_clock_vote(data, CLK_DFAB); - } - kfree(data); - + if (free_private_data) + kfree(data); return ret; } +#ifndef CONFIG_COMPAT +#define compat_qseecom_ioctl NULL +#endif + static const struct file_operations qseecom_fops = { .owner = THIS_MODULE, .unlocked_ioctl = qseecom_ioctl, -#ifdef CONFIG_COMPAT .compat_ioctl = compat_qseecom_ioctl, -#endif .open = qseecom_open, .release = qseecom_release }; @@ -7762,14 +8165,14 @@ static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce) /* Get CE3 src core clk. */ qclk->ce_core_src_clk = clk_get(pdev, core_clk_src); if (!IS_ERR(qclk->ce_core_src_clk)) { - rc = clk_set_rate(qclk->ce_core_src_clk, - qseecom.ce_opp_freq_hz); - if (rc) { - clk_put(qclk->ce_core_src_clk); - qclk->ce_core_src_clk = NULL; - pr_err("Unable to set the core src clk @%uMhz.\n", - qseecom.ce_opp_freq_hz/CE_CLK_DIV); - return -EIO; + rc = clk_set_rate(qclk->ce_core_src_clk, + qseecom.ce_opp_freq_hz); + if (rc) { + clk_put(qclk->ce_core_src_clk); + qclk->ce_core_src_clk = NULL; + pr_err("Unable to set the core src clk @%uMhz.\n", + qseecom.ce_opp_freq_hz/CE_CLK_DIV); + return -EIO; } } else { pr_warn("Unable to get CE core src clk, set to NULL\n"); @@ -8525,17 +8928,23 @@ static int qseecom_probe(struct platform_device *pdev) } INIT_LIST_HEAD(&qseecom.registered_listener_list_head); - spin_lock_init(&qseecom.registered_listener_list_lock); INIT_LIST_HEAD(&qseecom.registered_app_list_head); spin_lock_init(&qseecom.registered_app_list_lock); + INIT_LIST_HEAD(&qseecom.unregister_lsnr_pending_list_head); INIT_LIST_HEAD(&qseecom.registered_kclient_list_head); spin_lock_init(&qseecom.registered_kclient_list_lock); init_waitqueue_head(&qseecom.send_resp_wq); + init_waitqueue_head(&qseecom.register_lsnr_pending_wq); + init_waitqueue_head(&qseecom.unregister_lsnr_kthread_wq); + INIT_LIST_HEAD(&qseecom.unload_app_pending_list_head); + init_waitqueue_head(&qseecom.unload_app_kthread_wq); qseecom.send_resp_flag = 0; qseecom.qsee_version = QSEEE_VERSION_00; + mutex_lock(&app_access_lock); rc = qseecom_scm_call(6, 3, &feature, sizeof(feature), &resp, sizeof(resp)); + mutex_unlock(&app_access_lock); pr_info("qseecom.qsee_version = 0x%x\n", resp.result); if (rc) { pr_err("Failed to get QSEE version info %d\n", rc); @@ -8550,11 +8959,7 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.ion_clnt = msm_ion_client_create("qseecom-kernel"); if (IS_ERR_OR_NULL(qseecom.ion_clnt)) { pr_err("Ion client cannot be created\n"); - - if (qseecom.ion_clnt != ERR_PTR(-EPROBE_DEFER)) - rc = -ENOMEM; - else - rc = -EPROBE_DEFER; + rc = -ENOMEM; goto exit_del_cdev; } @@ -8601,6 +9006,14 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.qsee_reentrancy_support); } + qseecom.enable_key_wrap_in_ks = + of_property_read_bool((&pdev->dev)->of_node, + "qcom,enable-key-wrap-in-ks"); + if (qseecom.enable_key_wrap_in_ks) { + pr_warn("qseecom.enable_key_wrap_in_ks = %d\n", + qseecom.enable_key_wrap_in_ks); + } + /* * The qseecom bus scaling flag can not be enabled when * crypto clock is not handled by HLOS. @@ -8686,9 +9099,11 @@ static int qseecom_probe(struct platform_device *pdev) rc = -EIO; goto exit_deinit_clock; } + mutex_lock(&app_access_lock); rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, &resp, sizeof(resp)); + mutex_unlock(&app_access_lock); __qseecom_disable_clk(CLK_QSEE); if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) { pr_err("send secapp reg fail %d resp.res %d\n", @@ -8727,9 +9142,36 @@ static int qseecom_probe(struct platform_device *pdev) if (!qseecom.qsee_perf_client) pr_err("Unable to register bus client\n"); + /*create a kthread to process pending listener unregister task */ + qseecom.unregister_lsnr_kthread_task = kthread_run( + __qseecom_unregister_listener_kthread_func, + NULL, "qseecom-unreg-lsnr"); + if (IS_ERR(qseecom.unregister_lsnr_kthread_task)) { + pr_err("failed to create kthread to unregister listener\n"); + rc = -EINVAL; + goto exit_deinit_clock; + } + atomic_set(&qseecom.unregister_lsnr_kthread_state, + LSNR_UNREG_KT_SLEEP); + + /*create a kthread to process pending ta unloading task */ + qseecom.unload_app_kthread_task = kthread_run( + __qseecom_unload_app_kthread_func, + NULL, "qseecom-unload-ta"); + if (IS_ERR(qseecom.unload_app_kthread_task)) { + pr_err("failed to create kthread to unload ta\n"); + rc = -EINVAL; + goto exit_kill_unreg_lsnr_kthread; + } + atomic_set(&qseecom.unload_app_kthread_state, + UNLOAD_APP_KT_SLEEP); + atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY); return 0; +exit_kill_unreg_lsnr_kthread: + kthread_stop(qseecom.unregister_lsnr_kthread_task); + exit_deinit_clock: __qseecom_deinit_clk(CLK_QSEE); if ((qseecom.qsee.instance != qseecom.ce_drv.instance) && @@ -8843,6 +9285,10 @@ static int qseecom_remove(struct platform_device *pdev) ion_client_destroy(qseecom.ion_clnt); + kthread_stop(qseecom.unload_app_kthread_task); + + kthread_stop(qseecom.unregister_lsnr_kthread_task); + cdev_del(&qseecom.cdev); device_destroy(driver_class, qseecom_device_no); @@ -8858,8 +9304,8 @@ static int qseecom_suspend(struct platform_device *pdev, pm_message_t state) { int ret = 0; struct qseecom_clk *qclk; - qclk = &qseecom.qsee; + qclk = &qseecom.qsee; atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_SUSPEND); if (qseecom.no_clock_support) return 0; @@ -8900,8 +9346,8 @@ static int qseecom_resume(struct platform_device *pdev) int mode = 0; int ret = 0; struct qseecom_clk *qclk; - qclk = &qseecom.qsee; + qclk = &qseecom.qsee; if (qseecom.no_clock_support) goto exit; @@ -8974,7 +9420,8 @@ exit: atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY); return ret; } -static struct of_device_id qseecom_match[] = { + +static const struct of_device_id qseecom_match[] = { { .compatible = "qcom,qseecom", }, @@ -9004,7 +9451,7 @@ static void qseecom_exit(void) } MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator"); +MODULE_DESCRIPTION("QTI Secure Execution Environment Communicator"); module_init(qseecom_init); module_exit(qseecom_exit); diff --git a/include/soc/qcom/qseecomi.h b/include/soc/qcom/qseecomi.h index e199978302bf..46b1c5da4e90 100644 --- a/include/soc/qcom/qseecomi.h +++ b/include/soc/qcom/qseecomi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -19,6 +19,7 @@ #define QSEECOM_KEY_ID_SIZE 32 #define QSEOS_RESULT_FAIL_SEND_CMD_NO_THREAD -19 /*0xFFFFFFED*/ +#define QSEOS_RESULT_FAIL_APP_ALREADY_LOADED -38 /*0xFFFFFFDA*/ #define QSEOS_RESULT_FAIL_UNSUPPORTED_CE_PIPE -63 #define QSEOS_RESULT_FAIL_KS_OP -64 #define QSEOS_RESULT_FAIL_KEY_ID_EXISTS -65 @@ -104,82 +105,82 @@ enum qseecom_qsee_reentrancy_phase { QSEE_REENTRANCY_PHASE_MAX = 0xFF }; -__packed struct qsee_apps_region_info_ireq { +struct qsee_apps_region_info_ireq { uint32_t qsee_cmd_id; uint32_t addr; uint32_t size; -}; +} __attribute__((__packed__)); -__packed struct qsee_apps_region_info_64bit_ireq { +struct qsee_apps_region_info_64bit_ireq { uint32_t qsee_cmd_id; uint64_t addr; uint32_t size; -}; +} __attribute__((__packed__)); -__packed struct qseecom_check_app_ireq { +struct qseecom_check_app_ireq { uint32_t qsee_cmd_id; char app_name[MAX_APP_NAME_SIZE]; -}; +} __attribute__((__packed__)); -__packed struct qseecom_load_app_ireq { +struct qseecom_load_app_ireq { uint32_t qsee_cmd_id; uint32_t mdt_len; /* Length of the mdt file */ uint32_t img_len; /* Length of .bxx and .mdt files */ uint32_t phy_addr; /* phy addr of the start of image */ char app_name[MAX_APP_NAME_SIZE]; /* application name*/ -}; +} __attribute__((__packed__)); -__packed struct qseecom_load_app_64bit_ireq { +struct qseecom_load_app_64bit_ireq { uint32_t qsee_cmd_id; uint32_t mdt_len; uint32_t img_len; uint64_t phy_addr; char app_name[MAX_APP_NAME_SIZE]; -}; +} __attribute__((__packed__)); -__packed struct qseecom_unload_app_ireq { +struct qseecom_unload_app_ireq { uint32_t qsee_cmd_id; uint32_t app_id; -}; +} __attribute__((__packed__)); -__packed struct qseecom_load_lib_image_ireq { +struct qseecom_load_lib_image_ireq { uint32_t qsee_cmd_id; uint32_t mdt_len; uint32_t img_len; uint32_t phy_addr; -}; +} __attribute__((__packed__)); -__packed struct qseecom_load_lib_image_64bit_ireq { +struct qseecom_load_lib_image_64bit_ireq { uint32_t qsee_cmd_id; uint32_t mdt_len; uint32_t img_len; uint64_t phy_addr; -}; +} __attribute__((__packed__)); -__packed struct qseecom_unload_lib_image_ireq { +struct qseecom_unload_lib_image_ireq { uint32_t qsee_cmd_id; -}; +} __attribute__((__packed__)); -__packed struct qseecom_register_listener_ireq { +struct qseecom_register_listener_ireq { uint32_t qsee_cmd_id; uint32_t listener_id; uint32_t sb_ptr; uint32_t sb_len; -}; +} __attribute__((__packed__)); -__packed struct qseecom_register_listener_64bit_ireq { +struct qseecom_register_listener_64bit_ireq { uint32_t qsee_cmd_id; uint32_t listener_id; uint64_t sb_ptr; uint32_t sb_len; -}; +} __attribute__((__packed__)); -__packed struct qseecom_unregister_listener_ireq { +struct qseecom_unregister_listener_ireq { uint32_t qsee_cmd_id; uint32_t listener_id; -}; +} __attribute__((__packed__)); -__packed struct qseecom_client_send_data_ireq { +struct qseecom_client_send_data_ireq { uint32_t qsee_cmd_id; uint32_t app_id; uint32_t req_ptr; @@ -188,9 +189,9 @@ __packed struct qseecom_client_send_data_ireq { uint32_t rsp_len; uint32_t sglistinfo_ptr; uint32_t sglistinfo_len; -}; +} __attribute__((__packed__)); -__packed struct qseecom_client_send_data_64bit_ireq { +struct qseecom_client_send_data_64bit_ireq { uint32_t qsee_cmd_id; uint32_t app_id; uint64_t req_ptr; @@ -199,36 +200,36 @@ __packed struct qseecom_client_send_data_64bit_ireq { uint32_t rsp_len; uint64_t sglistinfo_ptr; uint32_t sglistinfo_len; -}; +} __attribute__((__packed__)); -__packed struct qseecom_reg_log_buf_ireq { +struct qseecom_reg_log_buf_ireq { uint32_t qsee_cmd_id; uint32_t phy_addr; uint32_t len; -}; +} __attribute__((__packed__)); -__packed struct qseecom_reg_log_buf_64bit_ireq { +struct qseecom_reg_log_buf_64bit_ireq { uint32_t qsee_cmd_id; uint64_t phy_addr; uint32_t len; -}; +} __attribute__((__packed__)); /* send_data resp */ -__packed struct qseecom_client_listener_data_irsp { +struct qseecom_client_listener_data_irsp { uint32_t qsee_cmd_id; uint32_t listener_id; uint32_t status; uint32_t sglistinfo_ptr; uint32_t sglistinfo_len; -}; +} __attribute__((__packed__)); -__packed struct qseecom_client_listener_data_64bit_irsp { +struct qseecom_client_listener_data_64bit_irsp { uint32_t qsee_cmd_id; uint32_t listener_id; uint32_t status; uint64_t sglistinfo_ptr; uint32_t sglistinfo_len; -}; +} __attribute__((__packed__)); /* * struct qseecom_command_scm_resp - qseecom response buffer @@ -237,40 +238,40 @@ __packed struct qseecom_client_listener_data_64bit_irsp { * buffer * @sb_in_rsp_len: length of command response */ -__packed struct qseecom_command_scm_resp { +struct qseecom_command_scm_resp { uint32_t result; enum qseecom_command_scm_resp_type resp_type; unsigned int data; -}; +} __attribute__((__packed__)); struct qseecom_rpmb_provision_key { uint32_t key_type; }; -__packed struct qseecom_client_send_service_ireq { +struct qseecom_client_send_service_ireq { uint32_t qsee_cmd_id; uint32_t key_type; /* in */ unsigned int req_len; /* in */ uint32_t rsp_ptr; /* in/out */ unsigned int rsp_len; /* in/out */ -}; +} __attribute__((__packed__)); -__packed struct qseecom_client_send_service_64bit_ireq { +struct qseecom_client_send_service_64bit_ireq { uint32_t qsee_cmd_id; uint32_t key_type; unsigned int req_len; uint64_t rsp_ptr; unsigned int rsp_len; -}; +} __attribute__((__packed__)); -__packed struct qseecom_key_generate_ireq { +struct qseecom_key_generate_ireq { uint32_t qsee_command_id; uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; uint8_t hash32[QSEECOM_HASH_SIZE]; -}; +} __attribute__((__packed__)); -__packed struct qseecom_key_select_ireq { +struct qseecom_key_select_ireq { uint32_t qsee_command_id; uint32_t ce; uint32_t pipe; @@ -278,33 +279,33 @@ __packed struct qseecom_key_select_ireq { uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; uint8_t hash32[QSEECOM_HASH_SIZE]; -}; +} __attribute__((__packed__)); -__packed struct qseecom_key_delete_ireq { +struct qseecom_key_delete_ireq { uint32_t qsee_command_id; uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; uint8_t hash32[QSEECOM_HASH_SIZE]; -}; +} __attribute__((__packed__)); -__packed struct qseecom_key_userinfo_update_ireq { +struct qseecom_key_userinfo_update_ireq { uint32_t qsee_command_id; uint32_t flags; uint8_t key_id[QSEECOM_KEY_ID_SIZE]; uint8_t current_hash32[QSEECOM_HASH_SIZE]; uint8_t new_hash32[QSEECOM_HASH_SIZE]; -}; +} __attribute__((__packed__)); -__packed struct qseecom_key_max_count_query_ireq { +struct qseecom_key_max_count_query_ireq { uint32_t flags; -}; +} __attribute__((__packed__)); -__packed struct qseecom_key_max_count_query_irsp { +struct qseecom_key_max_count_query_irsp { uint32_t max_key_count; -}; +} __attribute__((__packed__)); -__packed struct qseecom_qteec_ireq { +struct qseecom_qteec_ireq { uint32_t qsee_cmd_id; uint32_t app_id; uint32_t req_ptr; @@ -313,9 +314,9 @@ __packed struct qseecom_qteec_ireq { uint32_t resp_len; uint32_t sglistinfo_ptr; uint32_t sglistinfo_len; -}; +} __attribute__((__packed__)); -__packed struct qseecom_qteec_64bit_ireq { +struct qseecom_qteec_64bit_ireq { uint32_t qsee_cmd_id; uint32_t app_id; uint64_t req_ptr; @@ -324,21 +325,20 @@ __packed struct qseecom_qteec_64bit_ireq { uint32_t resp_len; uint64_t sglistinfo_ptr; uint32_t sglistinfo_len; -}; +} __attribute__((__packed__)); -__packed struct qseecom_client_send_fsm_key_req { +struct qseecom_client_send_fsm_key_req { uint32_t qsee_cmd_id; uint32_t req_ptr; uint32_t req_len; uint32_t rsp_ptr; uint32_t rsp_len; -}; +} __attribute__((__packed__)); -__packed struct qseecom_continue_blocked_request_ireq { +struct qseecom_continue_blocked_request_ireq { uint32_t qsee_cmd_id; uint32_t app_or_session_id; /*legacy: app_id; smcinvoke: session_id*/ -}; - +} __attribute__((__packed__)); /********** ARMV8 SMC INTERFACE TZ MACRO *******************/ @@ -352,7 +352,8 @@ __packed struct qseecom_continue_blocked_request_ireq { /*---------------------------------------------------------------------------- * Owning Entity IDs (defined by ARM SMC doc) - * -------------------------------------------------------------------------*/ + * --------------------------------------------------------------------------- + */ #define TZ_OWNER_ARM 0 /** ARM Architecture call ID */ #define TZ_OWNER_CPU 1 /** CPU service call ID */ #define TZ_OWNER_SIP 2 /** SIP service call ID */ @@ -380,18 +381,18 @@ __packed struct qseecom_continue_blocked_request_ireq { #define TZ_OWNER_OS_RESERVED_13 62 #define TZ_OWNER_OS_RESERVED_14 63 -#define TZ_SVC_INFO 6 /* Misc. information services */ +#define TZ_SVC_INFO 6 /* Misc. information services */ /** Trusted Application call groups */ -#define TZ_SVC_APP_ID_PLACEHOLDER 0 /* SVC bits will contain App ID */ +#define TZ_SVC_APP_ID_PLACEHOLDER 0 /* SVC bits will contain App ID */ /** General helper macro to create a bitmask from bits low to high. */ #define TZ_MASK_BITS(h, l) ((0xffffffff >> (32 - ((h - l) + 1))) << l) -/** - Macro used to define an SMC ID based on the owner ID, - service ID, and function number. -*/ +/* + * Macro used to define an SMC ID based on the owner ID, + * service ID, and function number. + */ #define TZ_SYSCALL_CREATE_SMC_ID(o, s, f) \ ((uint32_t)((((o & 0x3f) << 24) | (s & 0xff) << 8) | (f & 0xff))) @@ -412,8 +413,8 @@ __packed struct qseecom_continue_blocked_request_ireq { ((p9&TZ_SYSCALL_PARAM_TYPE_MASK)<<20)+ \ ((p10&TZ_SYSCALL_PARAM_TYPE_MASK)<<22)) -/** - Macros used to create the Parameter ID associated with the syscall +/* + * Macros used to create the Parameter ID associated with the syscall */ #define TZ_SYSCALL_CREATE_PARAM_ID_0 0 #define TZ_SYSCALL_CREATE_PARAM_ID_1(p1) \ @@ -437,8 +438,8 @@ __packed struct qseecom_continue_blocked_request_ireq { #define TZ_SYSCALL_CREATE_PARAM_ID_10(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) \ TZ_SYSCALL_CREATE_PARAM_ID(10, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) -/** - Macro used to obtain the Parameter ID associated with the syscall +/* + * Macro used to obtain the Parameter ID associated with the syscall */ #define TZ_SYSCALL_GET_PARAM_ID(CMD_ID) CMD_ID ## _PARAM_ID diff --git a/include/uapi/linux/qseecom.h b/include/uapi/linux/qseecom.h index 40c96eef3059..63e2a5f2b671 100644 --- a/include/uapi/linux/qseecom.h +++ b/include/uapi/linux/qseecom.h @@ -7,6 +7,11 @@ #define MAX_ION_FD 4 #define MAX_APP_NAME_SIZE 64 #define QSEECOM_HASH_SIZE 32 + +/* qseecom_ta_heap allocation retry delay (ms) and max attemp count */ +#define QSEECOM_TA_ION_ALLOCATE_DELAY 50 +#define QSEECOM_TA_ION_ALLOCATE_MAX_ATTEMP 20 + /* * struct qseecom_register_listener_req - * for register listener ioctl request -- cgit v1.2.3