From dd47c104533dedb90434a3f142e94a671ac623a6 Mon Sep 17 00:00:00 2001 From: Eugene Syromiatnikov Date: Mon, 13 Sep 2021 17:44:15 +0200 Subject: io-wq: provide IO_WQ_* constants for IORING_REGISTER_IOWQ_MAX_WORKERS arg items The items passed in the array pointed by the arg parameter of IORING_REGISTER_IOWQ_MAX_WORKERS io_uring_register operation carry certain semantics: they refer to different io-wq worker categories; provide IO_WQ_* constants in the UAPI, so these categories can be referenced in the user space code. Suggested-by: Jens Axboe Complements: 2e480058ddc21ec5 ("io-wq: provide a way to limit max number of workers") Signed-off-by: Eugene Syromiatnikov Link: https://lore.kernel.org/r/20210913154415.GA12890@asgard.redhat.com Signed-off-by: Jens Axboe --- include/uapi/linux/io_uring.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'include/uapi') diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h index 59ef35154e3d..b270a07b285e 100644 --- a/include/uapi/linux/io_uring.h +++ b/include/uapi/linux/io_uring.h @@ -317,13 +317,19 @@ enum { IORING_REGISTER_IOWQ_AFF = 17, IORING_UNREGISTER_IOWQ_AFF = 18, - /* set/get max number of workers */ + /* set/get max number of io-wq workers */ IORING_REGISTER_IOWQ_MAX_WORKERS = 19, /* this goes last */ IORING_REGISTER_LAST }; +/* io-wq worker categories */ +enum { + IO_WQ_BOUND, + IO_WQ_UNBOUND, +}; + /* deprecated, see struct io_uring_rsrc_update */ struct io_uring_files_update { __u32 offset; -- cgit v1.2.3 From 099dd788e31b4f426ef49c2785069804925a84e1 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 13 Sep 2021 14:51:10 -0500 Subject: cifs: remove pathname for file from SPDX header checkpatch complains about source files with filenames (e.g. in these cases just below the SPDX header in comments at the top of various files in fs/cifs). It also is helpful to change this now so will be less confusing when the parent directory is renamed e.g. from fs/cifs to fs/smb_client (or fs/smbfs) Reviewed-by: Ronnie Sahlberg Signed-off-by: Steve French --- fs/cifs/cache.c | 2 +- fs/cifs/cifs_debug.c | 1 - fs/cifs/cifs_fs_sb.h | 1 - fs/cifs/cifs_ioctl.h | 1 - fs/cifs/cifs_spnego.c | 2 +- fs/cifs/cifs_spnego.h | 2 +- fs/cifs/cifs_unicode.c | 1 - fs/cifs/cifsacl.c | 1 - fs/cifs/cifsacl.h | 1 - fs/cifs/cifsencrypt.c | 1 - fs/cifs/cifsfs.c | 1 - fs/cifs/cifsfs.h | 1 - fs/cifs/cifsglob.h | 1 - fs/cifs/cifspdu.h | 1 - fs/cifs/cifsproto.h | 1 - fs/cifs/cifssmb.c | 1 - fs/cifs/connect.c | 1 - fs/cifs/dir.c | 1 - fs/cifs/dns_resolve.c | 1 - fs/cifs/dns_resolve.h | 4 ++-- fs/cifs/export.c | 1 - fs/cifs/file.c | 1 - fs/cifs/fscache.c | 2 +- fs/cifs/fscache.h | 2 +- fs/cifs/inode.c | 1 - fs/cifs/ioctl.c | 1 - fs/cifs/link.c | 1 - fs/cifs/misc.c | 1 - fs/cifs/netmisc.c | 1 - fs/cifs/ntlmssp.h | 1 - fs/cifs/readdir.c | 1 - fs/cifs/rfc1002pdu.h | 1 - fs/cifs/sess.c | 1 - fs/cifs/smb2file.c | 1 - fs/cifs/smb2glob.h | 1 - fs/cifs/smb2inode.c | 1 - fs/cifs/smb2misc.c | 1 - fs/cifs/smb2pdu.c | 1 - fs/cifs/smb2pdu.h | 1 - fs/cifs/smb2proto.h | 1 - fs/cifs/smb2status.h | 1 - fs/cifs/smb2transport.c | 1 - fs/cifs/smberr.h | 1 - fs/cifs/transport.c | 1 - fs/cifs/winucase.c | 1 - fs/cifs/xattr.c | 1 - fs/smbfs_common/smbfsctl.h | 2 +- include/uapi/linux/cifs/cifs_mount.h | 1 - 48 files changed, 8 insertions(+), 49 deletions(-) (limited to 'include/uapi') diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c index 8a3b30ec860c..8be57aaedab6 100644 --- a/fs/cifs/cache.c +++ b/fs/cifs/cache.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/cache.c - CIFS filesystem cache index structure definitions + * CIFS filesystem cache index structure definitions * * Copyright (c) 2010 Novell, Inc. * Authors(s): Suresh Jayaraman (sjayaraman@suse.de> diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 51a824fc926a..de2c12bcfa4b 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * fs/cifs_debug.c * * Copyright (C) International Business Machines Corp., 2000,2005 * diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 4fd788586399..f97407520ea1 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/cifs_fs_sb.h * * Copyright (c) International Business Machines Corp., 2002,2004 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/cifs_ioctl.h b/fs/cifs/cifs_ioctl.h index ef723be358af..b87cbbe6d2d4 100644 --- a/fs/cifs/cifs_ioctl.h +++ b/fs/cifs/cifs_ioctl.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/cifs_ioctl.h * * Structure definitions for io control for cifs/smb3 * diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 8fa26a8530f8..353bd0dd7026 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/cifs_spnego.c -- SPNEGO upcall management for CIFS + * SPNEGO upcall management for CIFS * * Copyright (c) 2007 Red Hat, Inc. * Author(s): Jeff Layton (jlayton@redhat.com) diff --git a/fs/cifs/cifs_spnego.h b/fs/cifs/cifs_spnego.h index 31387d0ea32e..e6a0451877d4 100644 --- a/fs/cifs/cifs_spnego.h +++ b/fs/cifs/cifs_spnego.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/cifs_spnego.h -- SPNEGO upcall management for CIFS + * SPNEGO upcall management for CIFS * * Copyright (c) 2007 Red Hat, Inc. * Author(s): Jeff Layton (jlayton@redhat.com) diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 171ad8b42107..e7582dd79179 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * fs/cifs/cifs_unicode.c * * Copyright (c) International Business Machines Corp., 2000,2009 * Modified by Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 388eb536cff1..ee3aab3dd4ac 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/cifsacl.c * * Copyright (C) International Business Machines Corp., 2007,2008 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index f8292bcf8594..ccbfc754bd3c 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/cifsacl.h * * Copyright (c) International Business Machines Corp., 2007 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 2e6f40344037..d118282071b3 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/cifsencrypt.c * * Encryption and hashing operations relating to NTLM, NTLMv2. See MS-NLMP * for more detailed information diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8c20bfa187ac..9fa930dfd78d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/cifsfs.c * * Copyright (C) International Business Machines Corp., 2002,2008 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index d25a4099b32e..b50da1901ebd 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/cifsfs.h * * Copyright (c) International Business Machines Corp., 2002, 2007 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c068f7d8d879..7dd9878e26bf 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/cifsglob.h * * Copyright (C) International Business Machines Corp., 2002,2008 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 98e8e5aa0613..d2ff438fd31f 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/cifspdu.h * * Copyright (c) International Business Machines Corp., 2002,2009 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index f9740c21ca3d..54966c1a8eb6 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/cifsproto.h * * Copyright (c) International Business Machines Corp., 2002,2008 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index a8e41c1e80ca..243d17696f06 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/cifssmb.c * * Copyright (C) International Business Machines Corp., 2002,2010 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0db344807ef1..399a0f084573 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/connect.c * * Copyright (C) International Business Machines Corp., 2002,2011 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 5f8a302ffcb2..6e8e7cc26ae2 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/dir.c * * vfs operations that deal with dentries * diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index 8c616aaeb7c4..0458d28d71aa 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/dns_resolve.c * * Copyright (c) 2007 Igor Mammedov * Author(s): Igor Mammedov (niallain@gmail.com) diff --git a/fs/cifs/dns_resolve.h b/fs/cifs/dns_resolve.h index 9fa2807ef79e..afc0df381246 100644 --- a/fs/cifs/dns_resolve.h +++ b/fs/cifs/dns_resolve.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/dns_resolve.h -- DNS Resolver upcall management for CIFS DFS - * Handles host name to IP address resolution + * DNS Resolver upcall management for CIFS DFS + * Handles host name to IP address resolution * * Copyright (c) International Business Machines Corp., 2008 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/export.c b/fs/cifs/export.c index 747a540db954..37c28415df1e 100644 --- a/fs/cifs/export.c +++ b/fs/cifs/export.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/export.c * * Copyright (C) International Business Machines Corp., 2007 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index d0216472f1c6..4d10c9343890 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/file.c * * vfs operations that deal with files * diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index fab47fa7df74..8eedd20c44ab 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/fscache.c - CIFS filesystem cache interface + * CIFS filesystem cache interface * * Copyright (c) 2010 Novell, Inc. * Author(s): Suresh Jayaraman diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h index 82e856b9cf89..9baa1d0f22bd 100644 --- a/fs/cifs/fscache.h +++ b/fs/cifs/fscache.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/fscache.h - CIFS filesystem cache interface definitions + * CIFS filesystem cache interface definitions * * Copyright (c) 2010 Novell, Inc. * Authors(s): Suresh Jayaraman (sjayaraman@suse.de> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 50c01cff4c84..19af2d0ec8d5 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/inode.c * * Copyright (C) International Business Machines Corp., 2002,2010 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 42c6a0bac6c8..44ae99454fb3 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/ioctl.c * * vfs operations that deal with io control * diff --git a/fs/cifs/link.c b/fs/cifs/link.c index f0a6d63bc08c..852e54ee82c2 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/link.c * * Copyright (C) International Business Machines Corp., 2002,2008 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 9469f1cf0b46..f4313935e734 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/misc.c * * Copyright (C) International Business Machines Corp., 2002,2008 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 0e728aac67e9..fa9fbd6a819c 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * fs/cifs/netmisc.c * * Copyright (c) International Business Machines Corp., 2002,2008 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index 378133ce8869..25a2b8ef88b9 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/ntlmssp.h * * Copyright (c) International Business Machines Corp., 2002,2007 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 54d77c99e21c..1929e80c09ee 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/readdir.c * * Directory search handling * diff --git a/fs/cifs/rfc1002pdu.h b/fs/cifs/rfc1002pdu.h index 137f7c95afd6..ae1d025da294 100644 --- a/fs/cifs/rfc1002pdu.h +++ b/fs/cifs/rfc1002pdu.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/rfc1002pdu.h * * Protocol Data Unit definitions for RFC 1001/1002 support * diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 118403fbeda2..23e02db7923f 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/sess.c * * SMB/CIFS session setup handling routines * diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index c9d8a50062b8..f5dcc4940b6d 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/smb2file.c * * Copyright (C) International Business Machines Corp., 2002, 2011 * Author(s): Steve French (sfrench@us.ibm.com), diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h index d0e9f3782bd9..ca692b2283cd 100644 --- a/fs/cifs/smb2glob.h +++ b/fs/cifs/smb2glob.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/smb2glob.h * * Definitions for various global variables and structures * diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c index 957b2594f02e..8297703492ee 100644 --- a/fs/cifs/smb2inode.c +++ b/fs/cifs/smb2inode.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/smb2inode.c * * Copyright (C) International Business Machines Corp., 2002, 2011 * Etersoft, 2012 diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 668f77108831..29b5554f6263 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/smb2misc.c * * Copyright (C) International Business Machines Corp., 2002,2011 * Etersoft, 2012 diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index b6d2e3591927..672ae78e866a 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/smb2pdu.c * * Copyright (C) International Business Machines Corp., 2009, 2013 * Etersoft, 2012 diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index e9cac7970b66..f32c99c9ba13 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/smb2pdu.h * * Copyright (c) International Business Machines Corp., 2009, 2013 * Etersoft, 2012 diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 263767f644f8..547945443fa7 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/smb2proto.h * * Copyright (c) International Business Machines Corp., 2002, 2011 * Etersoft, 2012 diff --git a/fs/cifs/smb2status.h b/fs/cifs/smb2status.h index 0215ef36e240..a9e958166fc5 100644 --- a/fs/cifs/smb2status.h +++ b/fs/cifs/smb2status.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/smb2status.h * * SMB2 Status code (network error) definitions * Definitions are from MS-ERREF diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 6f7952ea4941..f59b956f9d25 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/smb2transport.c * * Copyright (C) International Business Machines Corp., 2002, 2011 * Etersoft, 2012 diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h index 60189efb3236..aeffdad829e2 100644 --- a/fs/cifs/smberr.h +++ b/fs/cifs/smberr.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1 */ /* - * fs/cifs/smberr.h * * Copyright (c) International Business Machines Corp., 2002,2004 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 75a95de320cf..b7379329b741 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/transport.c * * Copyright (C) International Business Machines Corp., 2002,2008 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/cifs/winucase.c b/fs/cifs/winucase.c index 59b6c577aa0a..2f075b5b50df 100644 --- a/fs/cifs/winucase.c +++ b/fs/cifs/winucase.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * fs/cifs/winucase.c * * Copyright (c) Jeffrey Layton , 2013 * diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 9ed481e79ce0..7d8b72d67c80 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/cifs/xattr.c * * Copyright (c) International Business Machines Corp., 2003, 2007 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/fs/smbfs_common/smbfsctl.h b/fs/smbfs_common/smbfsctl.h index d01e8c9d7a31..926f87cd6af0 100644 --- a/fs/smbfs_common/smbfsctl.h +++ b/fs/smbfs_common/smbfsctl.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ /* - * fs/cifs/smbfsctl.h: SMB, CIFS, SMB2 FSCTL definitions + * SMB, CIFS, SMB2 FSCTL definitions * * Copyright (c) International Business Machines Corp., 2002,2013 * Author(s): Steve French (sfrench@us.ibm.com) diff --git a/include/uapi/linux/cifs/cifs_mount.h b/include/uapi/linux/cifs/cifs_mount.h index 69829205fdb5..8e87d27b0951 100644 --- a/include/uapi/linux/cifs/cifs_mount.h +++ b/include/uapi/linux/cifs/cifs_mount.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ /* - * include/uapi/linux/cifs/cifs_mount.h * * Author(s): Scott Lovenberg (scott.lovenberg@gmail.com) * -- cgit v1.2.3 From b564171ade70570b7f335fa8ed17adb28409e3ac Mon Sep 17 00:00:00 2001 From: Li Li Date: Fri, 10 Sep 2021 09:42:10 -0700 Subject: binder: fix freeze race Currently cgroup freezer is used to freeze the application threads, and BINDER_FREEZE is used to freeze the corresponding binder interface. There's already a mechanism in ioctl(BINDER_FREEZE) to wait for any existing transactions to drain out before actually freezing the binder interface. But freezing an app requires 2 steps, freezing the binder interface with ioctl(BINDER_FREEZE) and then freezing the application main threads with cgroupfs. This is not an atomic operation. The following race issue might happen. 1) Binder interface is frozen by ioctl(BINDER_FREEZE); 2) Main thread A initiates a new sync binder transaction to process B; 3) Main thread A is frozen by "echo 1 > cgroup.freeze"; 4) The response from process B reaches the frozen thread, which will unexpectedly fail. This patch provides a mechanism to check if there's any new pending transaction happening between ioctl(BINDER_FREEZE) and freezing the main thread. If there's any, the main thread freezing operation can be rolled back to finish the pending transaction. Furthermore, the response might reach the binder driver before the rollback actually happens. That will still cause failed transaction. As the other process doesn't wait for another response of the response, the response transaction failure can be fixed by treating the response transaction like an oneway/async one, allowing it to reach the frozen thread. And it will be consumed when the thread gets unfrozen later. NOTE: This patch reuses the existing definition of struct binder_frozen_status_info but expands the bit assignments of __u32 member sync_recv. To ensure backward compatibility, bit 0 of sync_recv still indicates there's an outstanding sync binder transaction. This patch adds new information to bit 1 of sync_recv, indicating the binder transaction happens exactly when there's a race. If an existing userspace app runs on a new kernel, a sync binder call will set bit 0 of sync_recv so ioctl(BINDER_GET_FROZEN_INFO) still return the expected value (true). The app just doesn't check bit 1 intentionally so it doesn't have the ability to tell if there's a race. This behavior is aligned with what happens on an old kernel which doesn't set bit 1 at all. A new userspace app can 1) check bit 0 to know if there's a sync binder transaction happened when being frozen - same as before; and 2) check bit 1 to know if that sync binder transaction happened exactly when there's a race - a new information for rollback decision. the same time, confirmed the pending transactions succeeded. Fixes: 432ff1e91694 ("binder: BINDER_FREEZE ioctl") Acked-by: Todd Kjos Cc: stable Signed-off-by: Li Li Test: stress test with apps being frozen and initiating binder calls at Link: https://lore.kernel.org/r/20210910164210.2282716-2-dualli@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 35 +++++++++++++++++++++++++++++------ drivers/android/binder_internal.h | 2 ++ include/uapi/linux/android/binder.h | 7 +++++++ 3 files changed, 38 insertions(+), 6 deletions(-) (limited to 'include/uapi') diff --git a/drivers/android/binder.c b/drivers/android/binder.c index d9030cb6b1e4..1a68c2f590cf 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3038,9 +3038,8 @@ static void binder_transaction(struct binder_proc *proc, if (reply) { binder_enqueue_thread_work(thread, tcomplete); binder_inner_proc_lock(target_proc); - if (target_thread->is_dead || target_proc->is_frozen) { - return_error = target_thread->is_dead ? - BR_DEAD_REPLY : BR_FROZEN_REPLY; + if (target_thread->is_dead) { + return_error = BR_DEAD_REPLY; binder_inner_proc_unlock(target_proc); goto err_dead_proc_or_thread; } @@ -4648,6 +4647,22 @@ static int binder_ioctl_get_node_debug_info(struct binder_proc *proc, return 0; } +static bool binder_txns_pending_ilocked(struct binder_proc *proc) +{ + struct rb_node *n; + struct binder_thread *thread; + + if (proc->outstanding_txns > 0) + return true; + + for (n = rb_first(&proc->threads); n; n = rb_next(n)) { + thread = rb_entry(n, struct binder_thread, rb_node); + if (thread->transaction_stack) + return true; + } + return false; +} + static int binder_ioctl_freeze(struct binder_freeze_info *info, struct binder_proc *target_proc) { @@ -4679,8 +4694,13 @@ static int binder_ioctl_freeze(struct binder_freeze_info *info, (!target_proc->outstanding_txns), msecs_to_jiffies(info->timeout_ms)); - if (!ret && target_proc->outstanding_txns) - ret = -EAGAIN; + /* Check pending transactions that wait for reply */ + if (ret >= 0) { + binder_inner_proc_lock(target_proc); + if (binder_txns_pending_ilocked(target_proc)) + ret = -EAGAIN; + binder_inner_proc_unlock(target_proc); + } if (ret < 0) { binder_inner_proc_lock(target_proc); @@ -4696,6 +4716,7 @@ static int binder_ioctl_get_freezer_info( { struct binder_proc *target_proc; bool found = false; + __u32 txns_pending; info->sync_recv = 0; info->async_recv = 0; @@ -4705,7 +4726,9 @@ static int binder_ioctl_get_freezer_info( if (target_proc->pid == info->pid) { found = true; binder_inner_proc_lock(target_proc); - info->sync_recv |= target_proc->sync_recv; + txns_pending = binder_txns_pending_ilocked(target_proc); + info->sync_recv |= target_proc->sync_recv | + (txns_pending << 1); info->async_recv |= target_proc->async_recv; binder_inner_proc_unlock(target_proc); } diff --git a/drivers/android/binder_internal.h b/drivers/android/binder_internal.h index 810c0b84d3f8..402c4d4362a8 100644 --- a/drivers/android/binder_internal.h +++ b/drivers/android/binder_internal.h @@ -378,6 +378,8 @@ struct binder_ref { * binder transactions * (protected by @inner_lock) * @sync_recv: process received sync transactions since last frozen + * bit 0: received sync transaction after being frozen + * bit 1: new pending sync transaction during freezing * (protected by @inner_lock) * @async_recv: process received async transactions since last frozen * (protected by @inner_lock) diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index 20e435fe657a..3246f2c74696 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -225,7 +225,14 @@ struct binder_freeze_info { struct binder_frozen_status_info { __u32 pid; + + /* process received sync transactions since last frozen + * bit 0: received sync transaction after being frozen + * bit 1: new pending sync transaction during freezing + */ __u32 sync_recv; + + /* process received async transactions since last frozen */ __u32 async_recv; }; -- cgit v1.2.3 From 844f7eaaed9267ae17d33778efe65548cc940205 Mon Sep 17 00:00:00 2001 From: Eugene Syromiatnikov Date: Sun, 12 Sep 2021 14:22:34 +0200 Subject: include/uapi/linux/xfrm.h: Fix XFRM_MSG_MAPPING ABI breakage Commit 2d151d39073a ("xfrm: Add possibility to set the default to block if we have no policy") broke ABI by changing the value of the XFRM_MSG_MAPPING enum item, thus also evading the build-time check in security/selinux/nlmsgtab.c:selinux_nlmsg_lookup for presence of proper security permission checks in nlmsg_xfrm_perms. Fix it by placing XFRM_MSG_SETDEFAULT/XFRM_MSG_GETDEFAULT to the end of the enum, right before __XFRM_MSG_MAX, and updating the nlmsg_xfrm_perms accordingly. Fixes: 2d151d39073a ("xfrm: Add possibility to set the default to block if we have no policy") References: https://lore.kernel.org/netdev/20210901151402.GA2557@altlinux.org/ Signed-off-by: Eugene Syromiatnikov Acked-by: Antony Antony Acked-by: Nicolas Dichtel Signed-off-by: Steffen Klassert --- include/uapi/linux/xfrm.h | 6 +++--- security/selinux/nlmsgtab.c | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h index b96c1ea7166d..26f456b1f33e 100644 --- a/include/uapi/linux/xfrm.h +++ b/include/uapi/linux/xfrm.h @@ -213,13 +213,13 @@ enum { XFRM_MSG_GETSPDINFO, #define XFRM_MSG_GETSPDINFO XFRM_MSG_GETSPDINFO + XFRM_MSG_MAPPING, +#define XFRM_MSG_MAPPING XFRM_MSG_MAPPING + XFRM_MSG_SETDEFAULT, #define XFRM_MSG_SETDEFAULT XFRM_MSG_SETDEFAULT XFRM_MSG_GETDEFAULT, #define XFRM_MSG_GETDEFAULT XFRM_MSG_GETDEFAULT - - XFRM_MSG_MAPPING, -#define XFRM_MSG_MAPPING XFRM_MSG_MAPPING __XFRM_MSG_MAX }; #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1) diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index d59276f48d4f..94ea2a8b2bb7 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -126,6 +126,8 @@ static const struct nlmsg_perm nlmsg_xfrm_perms[] = { XFRM_MSG_NEWSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, { XFRM_MSG_GETSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_READ }, { XFRM_MSG_MAPPING, NETLINK_XFRM_SOCKET__NLMSG_READ }, + { XFRM_MSG_SETDEFAULT, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, + { XFRM_MSG_GETDEFAULT, NETLINK_XFRM_SOCKET__NLMSG_READ }, }; static const struct nlmsg_perm nlmsg_audit_perms[] = @@ -189,7 +191,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) * structures at the top of this file with the new mappings * before updating the BUILD_BUG_ON() macro! */ - BUILD_BUG_ON(XFRM_MSG_MAX != XFRM_MSG_MAPPING); + BUILD_BUG_ON(XFRM_MSG_MAX != XFRM_MSG_GETDEFAULT); err = nlmsg_perm(nlmsg_type, perm, nlmsg_xfrm_perms, sizeof(nlmsg_xfrm_perms)); break; -- cgit v1.2.3 From f8d858e607b2a36808ac6d4218f5f5203d7a7d63 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 14 Sep 2021 16:46:33 +0200 Subject: xfrm: make user policy API complete >From a userland POV, this API was based on some magic values: - dirmask and action were bitfields but meaning of bits (XFRM_POL_DEFAULT_*) are not exported; - action is confusing, if a bit is set, does it mean drop or accept? Let's try to simplify this uapi by using explicit field and macros. Fixes: 2d151d39073a ("xfrm: Add possibility to set the default to block if we have no policy") Signed-off-by: Nicolas Dichtel Signed-off-by: Steffen Klassert --- include/uapi/linux/xfrm.h | 9 ++++++--- net/xfrm/xfrm_user.c | 36 +++++++++++++++++++----------------- 2 files changed, 25 insertions(+), 20 deletions(-) (limited to 'include/uapi') diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h index 26f456b1f33e..eda0426ec4c2 100644 --- a/include/uapi/linux/xfrm.h +++ b/include/uapi/linux/xfrm.h @@ -514,9 +514,12 @@ struct xfrm_user_offload { #define XFRM_OFFLOAD_INBOUND 2 struct xfrm_userpolicy_default { -#define XFRM_USERPOLICY_DIRMASK_MAX (sizeof(__u8) * 8) - __u8 dirmask; - __u8 action; +#define XFRM_USERPOLICY_UNSPEC 0 +#define XFRM_USERPOLICY_BLOCK 1 +#define XFRM_USERPOLICY_ACCEPT 2 + __u8 in; + __u8 fwd; + __u8 out; }; #ifndef __KERNEL__ diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 4719a6d54aa6..90c88390f1fe 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1966,16 +1966,21 @@ static int xfrm_set_default(struct sk_buff *skb, struct nlmsghdr *nlh, { struct net *net = sock_net(skb->sk); struct xfrm_userpolicy_default *up = nlmsg_data(nlh); - u8 dirmask; - u8 old_default = net->xfrm.policy_default; - if (up->dirmask >= XFRM_USERPOLICY_DIRMASK_MAX) - return -EINVAL; + if (up->in == XFRM_USERPOLICY_BLOCK) + net->xfrm.policy_default |= XFRM_POL_DEFAULT_IN; + else if (up->in == XFRM_USERPOLICY_ACCEPT) + net->xfrm.policy_default &= ~XFRM_POL_DEFAULT_IN; - dirmask = (1 << up->dirmask) & XFRM_POL_DEFAULT_MASK; + if (up->fwd == XFRM_USERPOLICY_BLOCK) + net->xfrm.policy_default |= XFRM_POL_DEFAULT_FWD; + else if (up->fwd == XFRM_USERPOLICY_ACCEPT) + net->xfrm.policy_default &= ~XFRM_POL_DEFAULT_FWD; - net->xfrm.policy_default = (old_default & (0xff ^ dirmask)) - | (up->action << up->dirmask); + if (up->out == XFRM_USERPOLICY_BLOCK) + net->xfrm.policy_default |= XFRM_POL_DEFAULT_OUT; + else if (up->out == XFRM_USERPOLICY_ACCEPT) + net->xfrm.policy_default &= ~XFRM_POL_DEFAULT_OUT; rt_genid_bump_all(net); @@ -1988,13 +1993,11 @@ static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh, struct sk_buff *r_skb; struct nlmsghdr *r_nlh; struct net *net = sock_net(skb->sk); - struct xfrm_userpolicy_default *r_up, *up; + struct xfrm_userpolicy_default *r_up; int len = NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_default)); u32 portid = NETLINK_CB(skb).portid; u32 seq = nlh->nlmsg_seq; - up = nlmsg_data(nlh); - r_skb = nlmsg_new(len, GFP_ATOMIC); if (!r_skb) return -ENOMEM; @@ -2005,15 +2008,14 @@ static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh, return -EMSGSIZE; } - if (up->dirmask >= XFRM_USERPOLICY_DIRMASK_MAX) { - kfree_skb(r_skb); - return -EINVAL; - } - r_up = nlmsg_data(r_nlh); - r_up->action = ((net->xfrm.policy_default & (1 << up->dirmask)) >> up->dirmask); - r_up->dirmask = up->dirmask; + r_up->in = net->xfrm.policy_default & XFRM_POL_DEFAULT_IN ? + XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT; + r_up->fwd = net->xfrm.policy_default & XFRM_POL_DEFAULT_FWD ? + XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT; + r_up->out = net->xfrm.policy_default & XFRM_POL_DEFAULT_OUT ? + XFRM_USERPOLICY_BLOCK : XFRM_USERPOLICY_ACCEPT; nlmsg_end(r_skb, r_nlh); return nlmsg_unicast(net->xfrm.nlsk, r_skb, portid); -- cgit v1.2.3 From 4ca57d5139a0be3cf76c1667a4c0afb16d4a3b02 Mon Sep 17 00:00:00 2001 From: Rajaravi Krishna Katta Date: Tue, 14 Sep 2021 18:28:48 +0300 Subject: habanalabs: fix resetting args in wait for CS IOCTL In wait for CS IOCTL code, the driver resets the incoming args structure before returning to the user, regardless of the return value of the IOCTL. In case the IOCTL returns EINTR, resetting the args will result in error in case the userspace will repeat the ioctl call immediately (which is the behavior in the hl-thunk userspace library). The solution is to reset the args only if the driver returns success (0) as a return value for the IOCTL. Signed-off-by: Rajaravi Krishna Katta Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../misc/habanalabs/common/command_submission.c | 33 +++++++++++++--------- include/uapi/misc/habanalabs.h | 6 ++-- 2 files changed, 21 insertions(+), 18 deletions(-) (limited to 'include/uapi') diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 91b57544f7c6..6dafff375f1c 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -2649,11 +2649,18 @@ put_ctx: free_seq_arr: kfree(cs_seq_arr); - /* update output args */ - memset(args, 0, sizeof(*args)); if (rc) return rc; + if (mcs_data.wait_status == -ERESTARTSYS) { + dev_err_ratelimited(hdev->dev, + "user process got signal while waiting for Multi-CS\n"); + return -EINTR; + } + + /* update output args */ + memset(args, 0, sizeof(*args)); + if (mcs_data.completion_bitmap) { args->out.status = HL_WAIT_CS_STATUS_COMPLETED; args->out.cs_completion_map = mcs_data.completion_bitmap; @@ -2667,8 +2674,6 @@ free_seq_arr: /* update if some CS was gone */ if (mcs_data.timestamp) args->out.flags |= HL_WAIT_CS_STATUS_FLAG_GONE; - } else if (mcs_data.wait_status == -ERESTARTSYS) { - args->out.status = HL_WAIT_CS_STATUS_INTERRUPTED; } else { args->out.status = HL_WAIT_CS_STATUS_BUSY; } @@ -2688,16 +2693,17 @@ static int hl_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data) rc = _hl_cs_wait_ioctl(hdev, hpriv->ctx, args->in.timeout_us, seq, &status, ×tamp); + if (rc == -ERESTARTSYS) { + dev_err_ratelimited(hdev->dev, + "user process got signal while waiting for CS handle %llu\n", + seq); + return -EINTR; + } + memset(args, 0, sizeof(*args)); if (rc) { - if (rc == -ERESTARTSYS) { - dev_err_ratelimited(hdev->dev, - "user process got signal while waiting for CS handle %llu\n", - seq); - args->out.status = HL_WAIT_CS_STATUS_INTERRUPTED; - rc = -EINTR; - } else if (rc == -ETIMEDOUT) { + if (rc == -ETIMEDOUT) { dev_err_ratelimited(hdev->dev, "CS %llu has timed-out while user process is waiting for it\n", seq); @@ -2823,7 +2829,6 @@ wait_again: dev_err_ratelimited(hdev->dev, "user process got signal while waiting for interrupt ID %d\n", interrupt->interrupt_id); - *status = HL_WAIT_CS_STATUS_INTERRUPTED; rc = -EINTR; } else { *status = CS_WAIT_STATUS_BUSY; @@ -2878,8 +2883,6 @@ static int hl_interrupt_wait_ioctl(struct hl_fpriv *hpriv, void *data) args->in.interrupt_timeout_us, args->in.addr, args->in.target, interrupt_offset, &status); - memset(args, 0, sizeof(*args)); - if (rc) { if (rc != -EINTR) dev_err_ratelimited(hdev->dev, @@ -2888,6 +2891,8 @@ static int hl_interrupt_wait_ioctl(struct hl_fpriv *hpriv, void *data) return rc; } + memset(args, 0, sizeof(*args)); + switch (status) { case CS_WAIT_STATUS_COMPLETED: args->out.status = HL_WAIT_CS_STATUS_COMPLETED; diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index 7cc2a0f3f2f5..d13bb8c1b450 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -917,7 +917,6 @@ struct hl_wait_cs_in { #define HL_WAIT_CS_STATUS_BUSY 1 #define HL_WAIT_CS_STATUS_TIMEDOUT 2 #define HL_WAIT_CS_STATUS_ABORTED 3 -#define HL_WAIT_CS_STATUS_INTERRUPTED 4 #define HL_WAIT_CS_STATUS_FLAG_GONE 0x1 #define HL_WAIT_CS_STATUS_FLAG_TIMESTAMP_VLD 0x2 @@ -1286,7 +1285,8 @@ struct hl_debug_args { * EIO - The CS was aborted (usually because the device was reset) * ENODEV - The device wants to do hard-reset (so user need to close FD) * - * The driver also returns a custom define inside the IOCTL which can be: + * The driver also returns a custom define in case the IOCTL call returned 0. + * The define can be one of the following: * * HL_WAIT_CS_STATUS_COMPLETED - The CS has been completed successfully (0) * HL_WAIT_CS_STATUS_BUSY - The CS is still executing (0) @@ -1294,8 +1294,6 @@ struct hl_debug_args { * (ETIMEDOUT) * HL_WAIT_CS_STATUS_ABORTED - The CS was aborted, usually because the * device was reset (EIO) - * HL_WAIT_CS_STATUS_INTERRUPTED - Waiting for the CS was interrupted (EINTR) - * */ #define HL_IOCTL_WAIT_CS \ -- cgit v1.2.3 From 2c28ecad0d099ff914a0675f064db6e5b75e0756 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 27 Sep 2021 15:05:08 +0300 Subject: ASoC: SOF: topology: Add new token for dynamic pipeline Today, we set up all widgets required for all PCM streams at the time of topology parsing even if they are not used. An optimization would be to only set up the widgets required for currently active PCM streams. This would give the FW the opportunity to power gate unused memory blocks, thereby saving power. For dynamic pipelines, the widgets in the connected DAPM path for each PCM will need to be set up at runtime. This patch introduces a new token, DYNAMIC_PIPELINE, for scheduler type widgets that indicate whether a pipeline should be set up statically during topology load or at runtime when the PCM is opened. Introduce a new field called dynamic_pipeline_widget in struct snd_sof_widget to save the value of the parsed token. The token is set only for the pipeline (scheduler type) widget and must be propagated to all widgets in the same pipeline during topology load. Introduce another field called pipe_widget in struct snd_sof_widget that saves the pointer to the scheduler widget with the same pipeline ID as that of the widget. This field is populated when the pipeline completion callback is invoked during topology loading. Signed-off-by: Ranjani Sridharan Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Reviewed-by: Kai Vehmanen Signed-off-by: Daniel Baluta Signed-off-by: Peter Ujfalusi Link: https://lore.kernel.org/r/20210927120517.20505-4-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown --- include/uapi/sound/sof/tokens.h | 1 + sound/soc/sof/sof-audio.h | 13 +++++++++ sound/soc/sof/topology.c | 62 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 75 insertions(+), 1 deletion(-) (limited to 'include/uapi') diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index a642bf30c027..02b71a8deea4 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -51,6 +51,7 @@ #define SOF_TKN_SCHED_CORE 203 #define SOF_TKN_SCHED_FRAMES 204 #define SOF_TKN_SCHED_TIME_DOMAIN 205 +#define SOF_TKN_SCHED_DYNAMIC_PIPELINE 206 /* volume */ #define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250 diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 78a4a0c90a29..4a1c38c5618d 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -81,6 +81,8 @@ struct snd_sof_control { bool comp_data_dirty; }; +struct snd_sof_widget; + /* ASoC SOF DAPM widget */ struct snd_sof_widget { struct snd_soc_component *scomp; @@ -90,8 +92,19 @@ struct snd_sof_widget { int core; int id; + /* + * Flag indicating if the widget should be set up dynamically when a PCM is opened. + * This flag is only set for the scheduler type widget in topology. During topology + * loading, this flag is propagated to all the widgets belonging to the same pipeline. + * When this flag is not set, a widget is set up at the time of topology loading + * and retained until the DSP enters D3. It will need to be set up again when resuming + * from D3. + */ + bool dynamic_pipeline_widget; + struct snd_soc_dapm_widget *widget; struct list_head list; /* list in sdev widget list */ + struct snd_sof_widget *pipe_widget; /* extended data for UUID components */ struct sof_ipc_comp_ext comp_ext; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index d8f7b1edefc3..60d1db6a9193 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -572,6 +572,12 @@ static const struct sof_topology_token sched_tokens[] = { offsetof(struct sof_ipc_pipe_new, time_domain), 0}, }; +static const struct sof_topology_token pipeline_tokens[] = { + {SOF_TKN_SCHED_DYNAMIC_PIPELINE, SND_SOC_TPLG_TUPLE_TYPE_BOOL, get_token_u16, + offsetof(struct snd_sof_widget, dynamic_pipeline_widget), 0}, + +}; + /* volume */ static const struct sof_topology_token volume_tokens[] = { {SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, @@ -1765,6 +1771,15 @@ static int sof_widget_load_pipeline(struct snd_soc_component *scomp, int index, goto err; } + ret = sof_parse_tokens(scomp, swidget, pipeline_tokens, + ARRAY_SIZE(pipeline_tokens), private->array, + le32_to_cpu(private->size)); + if (ret != 0) { + dev_err(scomp->dev, "error: parse dynamic pipeline token failed %d\n", + private->size); + goto err; + } + dev_dbg(scomp->dev, "pipeline %s: period %d pri %d mips %d core %d frames %d\n", swidget->widget->name, pipeline->period, pipeline->priority, pipeline->period_mips, pipeline->core, pipeline->frames_per_sched); @@ -3567,11 +3582,45 @@ int snd_sof_complete_pipeline(struct device *dev, return 1; } +/** + * sof_set_pipe_widget - Set pipe_widget for a component + * @sdev: pointer to struct snd_sof_dev + * @pipe_widget: pointer to struct snd_sof_widget of type snd_soc_dapm_scheduler + * @swidget: pointer to struct snd_sof_widget that has the same pipeline ID as @pipe_widget + * + * Return: 0 if successful, -EINVAL on error. + * The function checks if @swidget is associated with any volatile controls. If so, setting + * the dynamic_pipeline_widget is disallowed. + */ +static int sof_set_pipe_widget(struct snd_sof_dev *sdev, struct snd_sof_widget *pipe_widget, + struct snd_sof_widget *swidget) +{ + struct snd_sof_control *scontrol; + + if (pipe_widget->dynamic_pipeline_widget) { + /* dynamic widgets cannot have volatile kcontrols */ + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) + if (scontrol->comp_id == swidget->comp_id && + (scontrol->access & SNDRV_CTL_ELEM_ACCESS_VOLATILE)) { + dev_err(sdev->dev, + "error: volatile control found for dynamic widget %s\n", + swidget->widget->name); + return -EINVAL; + } + } + + /* set the pipe_widget and apply the dynamic_pipeline_widget_flag */ + swidget->pipe_widget = pipe_widget; + swidget->dynamic_pipeline_widget = pipe_widget->dynamic_pipeline_widget; + + return 0; +} + /* completion - called at completion of firmware loading */ static int sof_complete(struct snd_soc_component *scomp) { struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct snd_sof_widget *swidget; + struct snd_sof_widget *swidget, *comp_swidget; int ret; /* some widget types require completion notificattion */ @@ -3586,6 +3635,17 @@ static int sof_complete(struct snd_soc_component *scomp) return ret; swidget->complete = ret; + + /* + * Apply the dynamic_pipeline_widget flag and set the pipe_widget field + * for all widgets that have the same pipeline ID as the scheduler widget + */ + list_for_each_entry_reverse(comp_swidget, &sdev->widget_list, list) + if (comp_swidget->pipeline_id == swidget->pipeline_id) { + ret = sof_set_pipe_widget(sdev, swidget, comp_swidget); + if (ret < 0) + return ret; + } break; default: break; -- cgit v1.2.3 From 95a13ee858c9e426e63c97063677736f74af7163 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 1 Oct 2021 16:55:44 +0300 Subject: hyper-v: Replace uuid.h with types.h There is no user of anything in uuid.h in the hyperv.h. Replace it with more appropriate types.h. Fixes: f081bbb3fd03 ("hyper-v: Remove internal types from UAPI header") Reported-by: Greg Kroah-Hartman Signed-off-by: Andy Shevchenko Reviewed-by: Haiyang Zhang Link: https://lore.kernel.org/r/20211001135544.1823-1-andriy.shevchenko@linux.intel.com Signed-off-by: Wei Liu --- include/uapi/linux/hyperv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/uapi') diff --git a/include/uapi/linux/hyperv.h b/include/uapi/linux/hyperv.h index 6135d92e0d47..daf82a230c0e 100644 --- a/include/uapi/linux/hyperv.h +++ b/include/uapi/linux/hyperv.h @@ -26,7 +26,7 @@ #ifndef _UAPI_HYPERV_H #define _UAPI_HYPERV_H -#include +#include /* * Framework version for util services. -- cgit v1.2.3 From 36ad9bf1d93d66b901342eab9f8ed6c1537655a6 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 26 Oct 2021 12:16:51 +0100 Subject: ASoC: qdsp6: audioreach: add topology support Add ASoC topology support in audioreach Signed-off-by: Srinivas Kandagatla Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20211026111655.1702-14-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- include/uapi/sound/snd_ar_tokens.h | 208 +++++++ sound/soc/qcom/Kconfig | 1 + sound/soc/qcom/qdsp6/Makefile | 2 +- sound/soc/qcom/qdsp6/audioreach.h | 3 + sound/soc/qcom/qdsp6/q6apm.c | 2 +- sound/soc/qcom/qdsp6/topology.c | 1113 ++++++++++++++++++++++++++++++++++++ 6 files changed, 1327 insertions(+), 2 deletions(-) create mode 100644 include/uapi/sound/snd_ar_tokens.h create mode 100644 sound/soc/qcom/qdsp6/topology.c (limited to 'include/uapi') diff --git a/include/uapi/sound/snd_ar_tokens.h b/include/uapi/sound/snd_ar_tokens.h new file mode 100644 index 000000000000..440c0725660b --- /dev/null +++ b/include/uapi/sound/snd_ar_tokens.h @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ + +#ifndef __SND_AR_TOKENS_H__ +#define __SND_AR_TOKENS_H__ + +#define APM_SUB_GRAPH_PERF_MODE_LOW_POWER 0x1 +#define APM_SUB_GRAPH_PERF_MODE_LOW_LATENCY 0x2 + +#define APM_SUB_GRAPH_DIRECTION_TX 0x1 +#define APM_SUB_GRAPH_DIRECTION_RX 0x2 + +/** Scenario ID Audio Playback */ +#define APM_SUB_GRAPH_SID_AUDIO_PLAYBACK 0x1 +/* Scenario ID Audio Record */ +#define APM_SUB_GRAPH_SID_AUDIO_RECORD 0x2 +/* Scenario ID Voice call. */ +#define APM_SUB_GRAPH_SID_VOICE_CALL 0x3 + +/* container capability ID Pre/Post Processing (PP) */ +#define APM_CONTAINER_CAP_ID_PP 0x1 +/* container capability ID Compression/Decompression (CD) */ +#define APM_CONTAINER_CAP_ID_CD 0x2 +/* container capability ID End Point(EP) */ +#define APM_CONTAINER_CAP_ID_EP 0x3 +/* container capability ID Offload (OLC) */ +#define APM_CONTAINER_CAP_ID_OLC 0x4 + +/* container graph position Stream */ +#define APM_CONT_GRAPH_POS_STREAM 0x1 +/* container graph position Per Stream Per Device*/ +#define APM_CONT_GRAPH_POS_PER_STR_PER_DEV 0x2 +/* container graph position Stream-Device */ +#define APM_CONT_GRAPH_POS_STR_DEV 0x3 +/* container graph position Global Device */ +#define APM_CONT_GRAPH_POS_GLOBAL_DEV 0x4 + +#define APM_PROC_DOMAIN_ID_MDSP 0x1 +#define APM_PROC_DOMAIN_ID_ADSP 0x2 +#define APM_PROC_DOMAIN_ID_SDSP 0x4 +#define APM_PROC_DOMAIN_ID_CDSP 0x5 + +#define PCM_INTERLEAVED 1 +#define PCM_DEINTERLEAVED_PACKED 2 +#define PCM_DEINTERLEAVED_UNPACKED 3 +#define AR_I2S_WS_SRC_EXTERNAL 0 +#define AR_I2S_WS_SRC_INTERNAL 1 + +enum ar_event_types { + AR_EVENT_NONE = 0, + AR_PGA_DAPM_EVENT +}; + +/* + * Kcontrol IDs + */ +#define SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX 256 +#define SND_SOC_AR_TPLG_VOL_CTL 257 + +/** + * %AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: Sub Graph Instance Id + * + * %AR_TKN_U32_SUB_GRAPH_PERF_MODE: Performance mode of subgraph + * APM_SUB_GRAPH_PERF_MODE_LOW_POWER = 1, + * APM_SUB_GRAPH_PERF_MODE_LOW_LATENCY = 2 + * + * %AR_TKN_U32_SUB_GRAPH_DIRECTION: Direction of subgraph + * APM_SUB_GRAPH_DIRECTION_TX = 1, + * APM_SUB_GRAPH_DIRECTION_RX = 2 + * + * %AR_TKN_U32_SUB_GRAPH_SCENARIO_ID: Scenario ID for subgraph + * APM_SUB_GRAPH_SID_AUDIO_PLAYBACK = 1, + * APM_SUB_GRAPH_SID_AUDIO_RECORD = 2, + * APM_SUB_GRAPH_SID_VOICE_CALL = 3 + * + * %AR_TKN_U32_CONTAINER_INSTANCE_ID: Container Instance ID + * + * %AR_TKN_U32_CONTAINER_CAPABILITY_ID: Container capability ID + * APM_CONTAINER_CAP_ID_PP = 1, + * APM_CONTAINER_CAP_ID_CD = 2, + * APM_CONTAINER_CAP_ID_EP = 3, + * APM_CONTAINER_CAP_ID_OLC = 4 + * + * %AR_TKN_U32_CONTAINER_STACK_SIZE: Stack size in the container. + * + * %AR_TKN_U32_CONTAINER_GRAPH_POS: Graph Position + * APM_CONT_GRAPH_POS_STREAM = 1, + * APM_CONT_GRAPH_POS_PER_STR_PER_DEV = 2, + * APM_CONT_GRAPH_POS_STR_DEV = 3, + * APM_CONT_GRAPH_POS_GLOBAL_DEV = 4 + * + * %AR_TKN_U32_CONTAINER_PROC_DOMAIN: Processor domain of container + * APM_PROC_DOMAIN_ID_MDSP = 1, + * APM_PROC_DOMAIN_ID_ADSP = 2, + * APM_PROC_DOMAIN_ID_SDSP = 4, + * APM_PROC_DOMAIN_ID_CDSP = 5 + * + * %AR_TKN_U32_MODULE_ID: Module ID + * + * %AR_TKN_U32_MODULE_INSTANCE_ID: Module Instance ID. + * + * %AR_TKN_U32_MODULE_MAX_IP_PORTS: Module maximum input ports + * + * %AR_TKN_U32_MODULE_MAX_OP_PORTS: Module maximum output ports. + * + * %AR_TKN_U32_MODULE_IN_PORTS: Number of in ports + * + * %AR_TKN_U32_MODULE_OUT_PORTS: Number of out ports. + * + * %AR_TKN_U32_MODULE_SRC_OP_PORT_ID: Source module output port ID + * + * %AR_TKN_U32_MODULE_DST_IN_PORT_ID: Destination module input port ID + * + * %AR_TKN_U32_MODULE_HW_IF_IDX: Interface index types for I2S/LPAIF + * + * %AR_TKN_U32_MODULE_HW_IF_TYPE: Interface type + * LPAIF = 0, + * LPAIF_RXTX = 1, + * LPAIF_WSA = 2, + * LPAIF_VA = 3, + * LPAIF_AXI = 4 + * + * %AR_TKN_U32_MODULE_FMT_INTERLEAVE: PCM Interleaving + * PCM_INTERLEAVED = 1, + * PCM_DEINTERLEAVED_PACKED = 2, + * PCM_DEINTERLEAVED_UNPACKED = 3 + * + * %AR_TKN_U32_MODULE_FMT_DATA: data format + * FIXED POINT = 1, + * IEC60958 PACKETIZED = 3, + * IEC60958 PACKETIZED NON LINEAR = 8, + * COMPR OVER PCM PACKETIZED = 7, + * IEC61937 PACKETIZED = 2, + * GENERIC COMPRESSED = 5 + * + * %AR_TKN_U32_MODULE_FMT_SAMPLE_RATE: sample rate + * + * %AR_TKN_U32_MODULE_FMT_BIT_DEPTH: bit depth + * + * %AR_TKN_U32_MODULE_SD_LINE_IDX: I2S serial data line idx + * I2S_SD0 = 1, + * I2S_SD1 = 2, + * I2S_SD2 = 3, + * I2S_SD3 = 4, + * I2S_QUAD01 = 5, + * I2S_QUAD23 = 6, + * I2S_6CHS = 7, + * I2S_8CHS = 8 + * + * %AR_TKN_U32_MODULE_WS_SRC: Word Select Source + * AR_I2S_WS_SRC_EXTERNAL = 0, + * AR_I2S_WS_SRC_INTERNAL = 1, + * + * %AR_TKN_U32_MODULE_FRAME_SZ_FACTOR: Frame size factor + * + * %AR_TKN_U32_MODULE_LOG_CODE: Log Module Code + * + * %AR_TKN_U32_MODULE_LOG_TAP_POINT_ID: logging tap point of this module + * + * %AR_TKN_U32_MODULE_LOG_MODE: logging mode + * LOG_WAIT = 0, + * LOG_IMMEDIATELY = 1 + * + * %AR_TKN_DAI_INDEX: dai index + * + */ + +/* DAI Tokens */ +#define AR_TKN_DAI_INDEX 1 +/* SUB GRAPH Tokens */ +#define AR_TKN_U32_SUB_GRAPH_INSTANCE_ID 2 +#define AR_TKN_U32_SUB_GRAPH_PERF_MODE 3 +#define AR_TKN_U32_SUB_GRAPH_DIRECTION 4 +#define AR_TKN_U32_SUB_GRAPH_SCENARIO_ID 5 + +/* Container Tokens */ +#define AR_TKN_U32_CONTAINER_INSTANCE_ID 100 +#define AR_TKN_U32_CONTAINER_CAPABILITY_ID 101 +#define AR_TKN_U32_CONTAINER_STACK_SIZE 102 +#define AR_TKN_U32_CONTAINER_GRAPH_POS 103 +#define AR_TKN_U32_CONTAINER_PROC_DOMAIN 104 + +/* Module Tokens */ +#define AR_TKN_U32_MODULE_ID 200 +#define AR_TKN_U32_MODULE_INSTANCE_ID 201 +#define AR_TKN_U32_MODULE_MAX_IP_PORTS 202 +#define AR_TKN_U32_MODULE_MAX_OP_PORTS 203 +#define AR_TKN_U32_MODULE_IN_PORTS 204 +#define AR_TKN_U32_MODULE_OUT_PORTS 205 +#define AR_TKN_U32_MODULE_SRC_OP_PORT_ID 206 +#define AR_TKN_U32_MODULE_DST_IN_PORT_ID 207 +#define AR_TKN_U32_MODULE_SRC_INSTANCE_ID 208 +#define AR_TKN_U32_MODULE_DST_INSTANCE_ID 209 + + +#define AR_TKN_U32_MODULE_HW_IF_IDX 250 +#define AR_TKN_U32_MODULE_HW_IF_TYPE 251 +#define AR_TKN_U32_MODULE_FMT_INTERLEAVE 252 +#define AR_TKN_U32_MODULE_FMT_DATA 253 +#define AR_TKN_U32_MODULE_FMT_SAMPLE_RATE 254 +#define AR_TKN_U32_MODULE_FMT_BIT_DEPTH 255 +#define AR_TKN_U32_MODULE_SD_LINE_IDX 256 +#define AR_TKN_U32_MODULE_WS_SRC 257 +#define AR_TKN_U32_MODULE_FRAME_SZ_FACTOR 258 +#define AR_TKN_U32_MODULE_LOG_CODE 259 +#define AR_TKN_U32_MODULE_LOG_TAP_POINT_ID 260 +#define AR_TKN_U32_MODULE_LOG_MODE 261 + +#endif /* __SND_AR_TOKENS_H__ */ diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 6aaf36b44725..75f447de1faf 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -101,6 +101,7 @@ config SND_SOC_QDSP6 select SND_SOC_QDSP6_ROUTING select SND_SOC_QDSP6_ASM select SND_SOC_QDSP6_ASM_DAI + select SND_SOC_TOPOLOGY select SND_SOC_QDSP6_APM help To add support for MSM QDSP6 Soc Audio. diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index 1a0803d97eec..766b824f6597 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only snd-q6dsp-common-objs := q6dsp-common.o q6dsp-lpass-ports.o q6dsp-lpass-clocks.o -snd-q6apm-objs := q6apm.o audioreach.o +snd-q6apm-objs := q6apm.o audioreach.o topology.o obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += snd-q6dsp-common.o obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index 821e1511140f..4f693a2660b5 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -693,6 +693,9 @@ void *audioreach_alloc_pkt(int payload_size, uint32_t opcode, void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, int graph_id); +/* Topology specific */ +int audioreach_tplg_init(struct snd_soc_component *component); + /* Module specific */ void audioreach_graph_free_buf(struct q6apm_graph *graph); int audioreach_map_memory_regions(struct q6apm_graph *graph, diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index 046f8f2e0c58..13598ef5bacb 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -694,7 +694,7 @@ EXPORT_SYMBOL_GPL(q6apm_graph_flush); static int q6apm_audio_probe(struct snd_soc_component *component) { - return 0; + return audioreach_tplg_init(component); } static void q6apm_audio_remove(struct snd_soc_component *component) diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c new file mode 100644 index 000000000000..f31895379925 --- /dev/null +++ b/sound/soc/qcom/qdsp6/topology.c @@ -0,0 +1,1113 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "q6apm.h" +#include "audioreach.h" + +struct snd_ar_control { + u32 sgid; /* Sub Graph ID */ + struct snd_soc_component *scomp; +}; + +static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6apm *apm, + uint32_t graph_id, + bool *found) +{ + struct audioreach_graph_info *info; + int ret; + + mutex_lock(&apm->lock); + info = idr_find(&apm->graph_info_idr, graph_id); + mutex_unlock(&apm->lock); + + if (info) { + *found = true; + return info; + } + + *found = false; + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&info->sg_list); + + mutex_lock(&apm->lock); + ret = idr_alloc(&apm->graph_info_idr, info, graph_id, graph_id + 1, GFP_KERNEL); + mutex_unlock(&apm->lock); + + if (ret < 0) { + dev_err(apm->dev, "Failed to allocate Graph ID (%x)\n", graph_id); + kfree(info); + return ERR_PTR(ret); + } + + info->id = ret; + + return info; +} + +static void audioreach_tplg_add_sub_graph(struct audioreach_sub_graph *sg, + struct audioreach_graph_info *info) +{ + list_add_tail(&sg->node, &info->sg_list); + sg->info = info; + info->num_sub_graphs++; +} + +static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm *apm, + uint32_t sub_graph_id, + bool *found) +{ + struct audioreach_sub_graph *sg; + int ret; + + if (!sub_graph_id) + return ERR_PTR(-EINVAL); + + /* Find if there is already a matching sub-graph */ + mutex_lock(&apm->lock); + sg = idr_find(&apm->sub_graphs_idr, sub_graph_id); + mutex_unlock(&apm->lock); + + if (sg) { + *found = true; + return sg; + } + + *found = false; + sg = kzalloc(sizeof(*sg), GFP_KERNEL); + if (!sg) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&sg->container_list); + + mutex_lock(&apm->lock); + ret = idr_alloc(&apm->sub_graphs_idr, sg, sub_graph_id, sub_graph_id + 1, GFP_KERNEL); + mutex_unlock(&apm->lock); + + if (ret < 0) { + dev_err(apm->dev, "Failed to allocate Sub-Graph Instance ID (%x)\n", sub_graph_id); + kfree(sg); + return ERR_PTR(ret); + } + + sg->sub_graph_id = ret; + + return sg; +} + +static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm *apm, + struct audioreach_sub_graph *sg, + uint32_t container_id, + bool *found) +{ + struct audioreach_container *cont; + int ret; + + if (!container_id) + return ERR_PTR(-EINVAL); + + mutex_lock(&apm->lock); + cont = idr_find(&apm->containers_idr, container_id); + mutex_unlock(&apm->lock); + + if (cont) { + *found = true; + return cont; + } + *found = false; + + cont = kzalloc(sizeof(*cont), GFP_KERNEL); + if (!cont) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&cont->modules_list); + + mutex_lock(&apm->lock); + ret = idr_alloc(&apm->containers_idr, cont, container_id, container_id + 1, GFP_KERNEL); + mutex_unlock(&apm->lock); + + if (ret < 0) { + dev_err(apm->dev, "Failed to allocate Container Instance ID (%x)\n", container_id); + kfree(cont); + return ERR_PTR(ret); + } + + cont->container_id = ret; + cont->sub_graph = sg; + /* add to container list */ + list_add_tail(&cont->node, &sg->container_list); + sg->num_containers++; + + return cont; +} + +static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm, + struct audioreach_container *cont, + struct snd_soc_dapm_widget *w, + uint32_t module_id, bool *found) +{ + struct audioreach_module *mod; + int ret; + + mutex_lock(&apm->lock); + mod = idr_find(&apm->modules_idr, module_id); + mutex_unlock(&apm->lock); + + if (mod) { + *found = true; + return mod; + } + *found = false; + mod = kzalloc(sizeof(*mod), GFP_KERNEL); + if (!mod) + return ERR_PTR(-ENOMEM); + + mutex_lock(&apm->lock); + if (!module_id) { /* alloc module id dynamically */ + ret = idr_alloc_cyclic(&apm->modules_idr, mod, + AR_MODULE_DYNAMIC_INSTANCE_ID_START, + AR_MODULE_DYNAMIC_INSTANCE_ID_END, GFP_KERNEL); + } else { + ret = idr_alloc(&apm->modules_idr, mod, module_id, module_id + 1, GFP_KERNEL); + } + mutex_unlock(&apm->lock); + + if (ret < 0) { + dev_err(apm->dev, "Failed to allocate Module Instance ID (%x)\n", module_id); + kfree(mod); + return ERR_PTR(ret); + } + + mod->instance_id = ret; + /* add to module list */ + list_add_tail(&mod->node, &cont->modules_list); + mod->container = cont; + mod->widget = w; + cont->num_modules++; + + return mod; +} + +static struct snd_soc_tplg_vendor_array *audioreach_get_sg_array( + struct snd_soc_tplg_private *private) +{ + struct snd_soc_tplg_vendor_array *sg_array = NULL; + bool found = false; + int sz; + + for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) { + struct snd_soc_tplg_vendor_value_elem *sg_elem; + int tkn_count = 0; + + sg_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); + sg_elem = sg_array->value; + sz = sz + le32_to_cpu(sg_array->size); + while (!found && tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) { + switch (le32_to_cpu(sg_elem->token)) { + case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: + found = true; + break; + default: + break; + } + tkn_count++; + sg_elem++; + } + } + + if (found) + return sg_array; + + return NULL; +} + +static struct snd_soc_tplg_vendor_array *audioreach_get_cont_array( + struct snd_soc_tplg_private *private) +{ + struct snd_soc_tplg_vendor_array *cont_array = NULL; + bool found = false; + int sz; + + for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) { + struct snd_soc_tplg_vendor_value_elem *cont_elem; + int tkn_count = 0; + + cont_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); + cont_elem = cont_array->value; + sz = sz + le32_to_cpu(cont_array->size); + while (!found && tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) { + switch (le32_to_cpu(cont_elem->token)) { + case AR_TKN_U32_CONTAINER_INSTANCE_ID: + found = true; + break; + default: + break; + } + tkn_count++; + cont_elem++; + } + } + + if (found) + return cont_array; + + return NULL; +} + +static struct snd_soc_tplg_vendor_array *audioreach_get_module_array( + struct snd_soc_tplg_private *private) +{ + struct snd_soc_tplg_vendor_array *mod_array = NULL; + bool found = false; + int sz = 0; + + for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) { + struct snd_soc_tplg_vendor_value_elem *mod_elem; + int tkn_count = 0; + + mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz); + mod_elem = mod_array->value; + sz = sz + le32_to_cpu(mod_array->size); + while (!found && tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { + switch (le32_to_cpu(mod_elem->token)) { + case AR_TKN_U32_MODULE_INSTANCE_ID: + found = true; + break; + default: + break; + } + tkn_count++; + mod_elem++; + } + } + + if (found) + return mod_array; + + return NULL; +} + +static struct audioreach_sub_graph *audioreach_parse_sg_tokens(struct q6apm *apm, + struct snd_soc_tplg_private *private) +{ + struct snd_soc_tplg_vendor_value_elem *sg_elem; + struct snd_soc_tplg_vendor_array *sg_array; + struct audioreach_graph_info *info = NULL; + int graph_id, sub_graph_id, tkn_count = 0; + struct audioreach_sub_graph *sg; + bool found; + + sg_array = audioreach_get_sg_array(private); + sg_elem = sg_array->value; + + while (tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) { + switch (le32_to_cpu(sg_elem->token)) { + case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: + sub_graph_id = le32_to_cpu(sg_elem->value); + sg = audioreach_tplg_alloc_sub_graph(apm, sub_graph_id, &found); + if (IS_ERR(sg)) { + return sg; + } else if (found) { + /* Already parsed data for this sub-graph */ + return sg; + } + break; + case AR_TKN_DAI_INDEX: + /* Sub graph is associated with predefined graph */ + graph_id = le32_to_cpu(sg_elem->value); + info = audioreach_tplg_alloc_graph_info(apm, graph_id, &found); + if (IS_ERR(info)) + return ERR_CAST(info); + break; + case AR_TKN_U32_SUB_GRAPH_PERF_MODE: + sg->perf_mode = le32_to_cpu(sg_elem->value); + break; + case AR_TKN_U32_SUB_GRAPH_DIRECTION: + sg->direction = le32_to_cpu(sg_elem->value); + break; + case AR_TKN_U32_SUB_GRAPH_SCENARIO_ID: + sg->scenario_id = le32_to_cpu(sg_elem->value); + break; + default: + dev_err(apm->dev, "Not a valid token %d for graph\n", sg_elem->token); + break; + + } + tkn_count++; + sg_elem++; + } + + /* Sub graph is associated with predefined graph */ + if (info) + audioreach_tplg_add_sub_graph(sg, info); + + return sg; +} + +static struct audioreach_container *audioreach_parse_cont_tokens(struct q6apm *apm, + struct audioreach_sub_graph *sg, + struct snd_soc_tplg_private *private) +{ + struct snd_soc_tplg_vendor_value_elem *cont_elem; + struct snd_soc_tplg_vendor_array *cont_array; + struct audioreach_container *cont; + int container_id, tkn_count = 0; + bool found = false; + + cont_array = audioreach_get_cont_array(private); + cont_elem = cont_array->value; + + while (tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) { + switch (le32_to_cpu(cont_elem->token)) { + case AR_TKN_U32_CONTAINER_INSTANCE_ID: + container_id = le32_to_cpu(cont_elem->value); + cont = audioreach_tplg_alloc_container(apm, sg, container_id, &found); + if (IS_ERR(cont) || found)/* Error or Already parsed container data */ + return cont; + break; + case AR_TKN_U32_CONTAINER_CAPABILITY_ID: + cont->capability_id = le32_to_cpu(cont_elem->value); + break; + case AR_TKN_U32_CONTAINER_STACK_SIZE: + cont->stack_size = le32_to_cpu(cont_elem->value); + break; + case AR_TKN_U32_CONTAINER_GRAPH_POS: + cont->graph_pos = le32_to_cpu(cont_elem->value); + break; + case AR_TKN_U32_CONTAINER_PROC_DOMAIN: + cont->proc_domain = le32_to_cpu(cont_elem->value); + break; + default: + dev_err(apm->dev, "Not a valid token %d for graph\n", cont_elem->token); + break; + + } + tkn_count++; + cont_elem++; + } + + return cont; +} + +static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *apm, + struct audioreach_container *cont, + struct snd_soc_tplg_private *private, + struct snd_soc_dapm_widget *w) +{ + uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0; + uint32_t src_mod_inst_id = 0, src_mod_op_port_id = 0; + uint32_t dst_mod_inst_id = 0, dst_mod_ip_port_id = 0; + int module_id = 0, instance_id = 0, tkn_count = 0; + struct snd_soc_tplg_vendor_value_elem *mod_elem; + struct snd_soc_tplg_vendor_array *mod_array; + struct audioreach_module *mod = NULL; + bool found; + + mod_array = audioreach_get_module_array(private); + mod_elem = mod_array->value; + + while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { + switch (le32_to_cpu(mod_elem->token)) { + /* common module info */ + case AR_TKN_U32_MODULE_ID: + module_id = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_INSTANCE_ID: + instance_id = le32_to_cpu(mod_elem->value); + mod = audioreach_tplg_alloc_module(apm, cont, w, + instance_id, &found); + if (IS_ERR(mod)) { + return mod; + } else if (found) { + dev_err(apm->dev, "Duplicate Module Instance ID 0x%08x found\n", + instance_id); + return ERR_PTR(-EINVAL); + } + + break; + case AR_TKN_U32_MODULE_MAX_IP_PORTS: + max_ip_port = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_MAX_OP_PORTS: + max_op_port = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_IN_PORTS: + in_port = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_OUT_PORTS: + out_port = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_SRC_OP_PORT_ID: + src_mod_op_port_id = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_SRC_INSTANCE_ID: + src_mod_inst_id = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_DST_INSTANCE_ID: + dst_mod_inst_id = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_DST_IN_PORT_ID: + dst_mod_ip_port_id = le32_to_cpu(mod_elem->value); + + default: + break; + + } + tkn_count++; + mod_elem++; + } + + if (mod) { + mod->module_id = module_id; + mod->max_ip_port = max_ip_port; + mod->max_op_port = max_op_port; + mod->in_port = in_port; + mod->out_port = out_port; + mod->src_mod_inst_id = src_mod_inst_id; + mod->src_mod_op_port_id = src_mod_op_port_id; + mod->dst_mod_inst_id = dst_mod_inst_id; + mod->dst_mod_ip_port_id = dst_mod_ip_port_id; + } + + return mod; +} + +static int audioreach_widget_load_module_common(struct snd_soc_component *component, + int index, struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *tplg_w) +{ + struct q6apm *apm = dev_get_drvdata(component->dev); + struct audioreach_container *cont; + struct audioreach_sub_graph *sg; + struct audioreach_module *mod; + struct snd_soc_dobj *dobj; + + sg = audioreach_parse_sg_tokens(apm, &tplg_w->priv); + if (IS_ERR(sg)) + return PTR_ERR(sg); + + cont = audioreach_parse_cont_tokens(apm, sg, &tplg_w->priv); + if (IS_ERR(cont)) + return PTR_ERR(cont); + + mod = audioreach_parse_common_tokens(apm, cont, &tplg_w->priv, w); + if (IS_ERR(mod)) + return PTR_ERR(mod); + + dobj = &w->dobj; + dobj->private = mod; + + return 0; +} + +static int audioreach_widget_load_enc_dec_cnv(struct snd_soc_component *component, + int index, struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *tplg_w) +{ + struct snd_soc_tplg_vendor_value_elem *mod_elem; + struct snd_soc_tplg_vendor_array *mod_array; + struct audioreach_module *mod; + struct snd_soc_dobj *dobj; + int tkn_count = 0; + int ret; + + ret = audioreach_widget_load_module_common(component, index, w, tplg_w); + if (ret) + return ret; + + dobj = &w->dobj; + mod = dobj->private; + mod_array = audioreach_get_module_array(&tplg_w->priv); + mod_elem = mod_array->value; + + while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { + switch (le32_to_cpu(mod_elem->token)) { + case AR_TKN_U32_MODULE_FMT_INTERLEAVE: + mod->interleave_type = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_FMT_SAMPLE_RATE: + mod->rate = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_FMT_BIT_DEPTH: + mod->bit_depth = le32_to_cpu(mod_elem->value); + break; + default: + break; + } + tkn_count++; + mod_elem++; + } + + return 0; +} + +static int audioreach_widget_log_module_load(struct audioreach_module *mod, + struct snd_soc_tplg_vendor_array *mod_array) +{ + struct snd_soc_tplg_vendor_value_elem *mod_elem; + int tkn_count = 0; + + mod_elem = mod_array->value; + + while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { + switch (le32_to_cpu(mod_elem->token)) { + + case AR_TKN_U32_MODULE_LOG_CODE: + mod->log_code = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_LOG_TAP_POINT_ID: + mod->log_tap_point_id = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_LOG_MODE: + mod->log_mode = le32_to_cpu(mod_elem->value); + break; + default: + break; + } + tkn_count++; + mod_elem++; + } + + return 0; +} + +static int audioreach_widget_dma_module_load(struct audioreach_module *mod, + struct snd_soc_tplg_vendor_array *mod_array) +{ + struct snd_soc_tplg_vendor_value_elem *mod_elem; + int tkn_count = 0; + + mod_elem = mod_array->value; + + while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { + switch (le32_to_cpu(mod_elem->token)) { + case AR_TKN_U32_MODULE_HW_IF_IDX: + mod->hw_interface_idx = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_FMT_DATA: + mod->data_format = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_HW_IF_TYPE: + mod->hw_interface_type = le32_to_cpu(mod_elem->value); + break; + default: + break; + } + tkn_count++; + mod_elem++; + } + + return 0; +} + +static int audioreach_widget_i2s_module_load(struct audioreach_module *mod, + struct snd_soc_tplg_vendor_array *mod_array) +{ + struct snd_soc_tplg_vendor_value_elem *mod_elem; + int tkn_count = 0; + + mod_elem = mod_array->value; + + while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) { + switch (le32_to_cpu(mod_elem->token)) { + case AR_TKN_U32_MODULE_HW_IF_IDX: + mod->hw_interface_idx = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_FMT_DATA: + mod->data_format = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_HW_IF_TYPE: + mod->hw_interface_type = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_SD_LINE_IDX: + mod->sd_line_idx = le32_to_cpu(mod_elem->value); + break; + case AR_TKN_U32_MODULE_WS_SRC: + mod->ws_src = le32_to_cpu(mod_elem->value); + break; + default: + break; + } + tkn_count++; + mod_elem++; + } + + return 0; +} + +static int audioreach_widget_load_buffer(struct snd_soc_component *component, + int index, struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *tplg_w) +{ + struct snd_soc_tplg_vendor_array *mod_array; + struct audioreach_module *mod; + struct snd_soc_dobj *dobj; + int ret; + + ret = audioreach_widget_load_module_common(component, index, w, tplg_w); + if (ret) + return ret; + + dobj = &w->dobj; + mod = dobj->private; + + mod_array = audioreach_get_module_array(&tplg_w->priv); + + switch (mod->module_id) { + case MODULE_ID_CODEC_DMA_SINK: + case MODULE_ID_CODEC_DMA_SOURCE: + audioreach_widget_dma_module_load(mod, mod_array); + break; + case MODULE_ID_DATA_LOGGING: + audioreach_widget_log_module_load(mod, mod_array); + break; + case MODULE_ID_I2S_SINK: + case MODULE_ID_I2S_SOURCE: + audioreach_widget_i2s_module_load(mod, mod_array); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int audioreach_widget_load_mixer(struct snd_soc_component *component, + int index, struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *tplg_w) +{ + struct snd_soc_tplg_vendor_value_elem *w_elem; + struct snd_soc_tplg_vendor_array *w_array; + struct snd_ar_control *scontrol; + struct snd_soc_dobj *dobj; + int tkn_count = 0; + + w_array = &tplg_w->priv.array[0]; + + scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL); + if (!scontrol) + return -ENOMEM; + + scontrol->scomp = component; + dobj = &w->dobj; + dobj->private = scontrol; + + w_elem = w_array->value; + while (tkn_count <= (le32_to_cpu(w_array->num_elems) - 1)) { + switch (le32_to_cpu(w_elem->token)) { + case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: + scontrol->sgid = le32_to_cpu(w_elem->value); + break; + default: /* ignore other tokens */ + break; + } + tkn_count++; + w_elem++; + } + + return 0; +} + +static int audioreach_pga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) + +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct audioreach_module *mod = w->dobj.private; + struct q6apm *apm = dev_get_drvdata(c->dev); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* apply gain after power up of widget */ + audioreach_gain_set_vol_ctrl(apm, mod, mod->gain); + break; + default: + break; + } + + return 0; +} + +static const struct snd_soc_tplg_widget_events audioreach_widget_ops[] = { + { AR_PGA_DAPM_EVENT, audioreach_pga_event }, +}; + +static int audioreach_widget_load_pga(struct snd_soc_component *component, + int index, struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *tplg_w) +{ + struct audioreach_module *mod; + struct snd_soc_dobj *dobj; + int ret; + + ret = audioreach_widget_load_module_common(component, index, w, tplg_w); + if (ret) + return ret; + + dobj = &w->dobj; + mod = dobj->private; + mod->gain = VOL_CTRL_DEFAULT_GAIN; + + ret = snd_soc_tplg_widget_bind_event(w, audioreach_widget_ops, + ARRAY_SIZE(audioreach_widget_ops), + le16_to_cpu(tplg_w->event_type)); + if (ret) { + dev_err(component->dev, "matching event handlers NOT found for %d\n", + le16_to_cpu(tplg_w->event_type)); + return -EINVAL; + } + + return 0; +} + +static int audioreach_widget_ready(struct snd_soc_component *component, + int index, struct snd_soc_dapm_widget *w, + struct snd_soc_tplg_dapm_widget *tplg_w) +{ + switch (w->id) { + case snd_soc_dapm_aif_in: + case snd_soc_dapm_aif_out: + audioreach_widget_load_buffer(component, index, w, tplg_w); + break; + case snd_soc_dapm_decoder: + case snd_soc_dapm_encoder: + case snd_soc_dapm_src: + audioreach_widget_load_enc_dec_cnv(component, index, w, tplg_w); + break; + case snd_soc_dapm_buffer: + audioreach_widget_load_buffer(component, index, w, tplg_w); + break; + case snd_soc_dapm_mixer: + return audioreach_widget_load_mixer(component, index, w, tplg_w); + case snd_soc_dapm_pga: + return audioreach_widget_load_pga(component, index, w, tplg_w); + case snd_soc_dapm_dai_link: + case snd_soc_dapm_scheduler: + case snd_soc_dapm_out_drv: + default: + dev_err(component->dev, "Widget type (0x%x) not yet supported\n", w->id); + break; + } + + return 0; +} + +static int audioreach_widget_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj); + struct q6apm *apm = dev_get_drvdata(scomp->dev); + struct audioreach_container *cont; + struct audioreach_module *mod; + + mod = dobj->private; + cont = mod->container; + + if (w->id == snd_soc_dapm_mixer) { + /* virtual widget */ + kfree(dobj->private); + return 0; + } + + mutex_lock(&apm->lock); + idr_remove(&apm->modules_idr, mod->instance_id); + cont->num_modules--; + + list_del(&mod->node); + kfree(mod); + /* Graph Info has N sub-graphs, sub-graph has N containers, Container has N Modules */ + if (list_empty(&cont->modules_list)) { /* if no modules in the container then remove it */ + struct audioreach_sub_graph *sg = cont->sub_graph; + + idr_remove(&apm->containers_idr, cont->container_id); + list_del(&cont->node); + sg->num_containers--; + kfree(cont); + /* check if there are no more containers in the sub graph and remove it */ + if (list_empty(&sg->container_list)) { + struct audioreach_graph_info *info = sg->info; + + idr_remove(&apm->sub_graphs_idr, sg->sub_graph_id); + list_del(&sg->node); + info->num_sub_graphs--; + kfree(sg); + /* Check if there are no more sub-graphs left then remove graph info */ + if (list_empty(&info->sg_list)) { + idr_remove(&apm->graph_info_idr, info->id); + kfree(info); + } + } + } + + mutex_unlock(&apm->lock); + + return 0; +} + +static struct audioreach_module *audioreach_find_widget(struct snd_soc_component *comp, + const char *name) +{ + struct q6apm *apm = dev_get_drvdata(comp->dev); + struct audioreach_module *module; + int id; + + idr_for_each_entry(&apm->modules_idr, module, id) { + if (!strcmp(name, module->widget->name)) + return module; + } + + return NULL; +} + +static int audioreach_route_load(struct snd_soc_component *scomp, int index, + struct snd_soc_dapm_route *route) +{ + struct audioreach_module *src, *sink; + + src = audioreach_find_widget(scomp, route->source); + sink = audioreach_find_widget(scomp, route->sink); + + if (src && sink) { + src->dst_mod_inst_id = sink->instance_id; + sink->src_mod_inst_id = src->instance_id; + } + + return 0; +} + +static int audioreach_route_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + return 0; +} + +static int audioreach_tplg_complete(struct snd_soc_component *component) +{ + /* TBD */ + return 0; +} + +/* DAI link - used for any driver specific init */ +static int audioreach_link_load(struct snd_soc_component *component, int index, + struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg) +{ + link->nonatomic = true; + link->dynamic = true; + link->platforms->name = NULL; + link->platforms->of_node = of_get_compatible_child(component->dev->of_node, + "qcom,q6apm-dais"); + return 0; +} + +static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct snd_ar_control *dapm_scontrol = dw->dobj.private; + struct snd_ar_control *scontrol = mc->dobj.private; + struct q6apm *data = dev_get_drvdata(c->dev); + bool connected; + + connected = q6apm_is_sub_graphs_connected(data, scontrol->sgid, dapm_scontrol->sgid); + if (connected) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct snd_ar_control *dapm_scontrol = dw->dobj.private; + struct snd_ar_control *scontrol = mc->dobj.private; + struct q6apm *data = dev_get_drvdata(c->dev); + + if (ucontrol->value.integer.value[0]) { + q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, true); + snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL); + } else { + q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, false); + snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL); + } + return 0; +} + +static int audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); + struct audioreach_module *mod = dw->dobj.private; + + ucontrol->value.integer.value[0] = mod->gain; + + return 0; +} + +static int audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol); + struct audioreach_module *mod = dw->dobj.private; + + mod->gain = ucontrol->value.integer.value[0]; + + return 1; +} + +static int audioreach_control_load_mix(struct snd_soc_component *scomp, + struct snd_ar_control *scontrol, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_soc_tplg_vendor_value_elem *c_elem; + struct snd_soc_tplg_vendor_array *c_array; + struct snd_soc_tplg_mixer_control *mc; + int tkn_count = 0; + + mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr); + c_array = (struct snd_soc_tplg_vendor_array *)mc->priv.data; + + c_elem = c_array->value; + + while (tkn_count <= (le32_to_cpu(c_array->num_elems) - 1)) { + switch (le32_to_cpu(c_elem->token)) { + case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID: + scontrol->sgid = le32_to_cpu(c_elem->value); + break; + default: + /* Ignore other tokens */ + break; + } + c_elem++; + tkn_count++; + } + + return 0; +} + +static int audioreach_control_load(struct snd_soc_component *scomp, int index, + struct snd_kcontrol_new *kc, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct snd_ar_control *scontrol; + struct soc_mixer_control *sm; + struct snd_soc_dobj *dobj; + int ret = 0; + + scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL); + if (!scontrol) + return -ENOMEM; + + scontrol->scomp = scomp; + + switch (le32_to_cpu(hdr->ops.get)) { + case SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX: + sm = (struct soc_mixer_control *)kc->private_value; + dobj = &sm->dobj; + ret = audioreach_control_load_mix(scomp, scontrol, kc, hdr); + break; + case SND_SOC_AR_TPLG_VOL_CTL: + sm = (struct soc_mixer_control *)kc->private_value; + dobj = &sm->dobj; + break; + default: + dev_warn(scomp->dev, "control type not supported %d:%d:%d\n", + hdr->ops.get, hdr->ops.put, hdr->ops.info); + kfree(scontrol); + return -EINVAL; + } + + dobj->private = scontrol; + return ret; +} + +static int audioreach_control_unload(struct snd_soc_component *scomp, + struct snd_soc_dobj *dobj) +{ + struct snd_ar_control *scontrol = dobj->private; + + kfree(scontrol); + + return 0; +} + +static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = { + {SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX, audioreach_get_audio_mixer, + audioreach_put_audio_mixer, snd_soc_info_volsw}, + {SND_SOC_AR_TPLG_VOL_CTL, audioreach_get_vol_ctrl_audio_mixer, + audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw}, +}; + +static struct snd_soc_tplg_ops audioreach_tplg_ops = { + .io_ops = audioreach_io_ops, + .io_ops_count = ARRAY_SIZE(audioreach_io_ops), + + .control_load = audioreach_control_load, + .control_unload = audioreach_control_unload, + + .widget_ready = audioreach_widget_ready, + .widget_unload = audioreach_widget_unload, + + .complete = audioreach_tplg_complete, + .link_load = audioreach_link_load, + + .dapm_route_load = audioreach_route_load, + .dapm_route_unload = audioreach_route_unload, +}; + +int audioreach_tplg_init(struct snd_soc_component *component) +{ + struct snd_soc_card *card = component->card; + struct device *dev = component->dev; + const struct firmware *fw; + char *tplg_fw_name; + int ret; + + /* Inline with Qualcomm UCM configs and linux-firmware path */ + tplg_fw_name = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", card->driver_name, card->name); + if (!tplg_fw_name) + return -ENOMEM; + + ret = request_firmware(&fw, tplg_fw_name, dev); + if (ret < 0) { + dev_err(dev, "tplg firmware loading %s failed %d \n", tplg_fw_name, ret); + goto err; + } + + ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw); + if (ret < 0) { + dev_err(dev, "tplg component load failed%d\n", ret); + ret = -EINVAL; + } + + release_firmware(fw); +err: + kfree(tplg_fw_name); + + return ret; +} +EXPORT_SYMBOL_GPL(audioreach_tplg_init); -- cgit v1.2.3