From 17d43f2bf98c75afe28fdc5f7032b43df2fac9ce Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 9 Oct 2019 16:34:16 -0700 Subject: [PATCH 0001/1055] fscrypt: invoke crypto API for ESSIV handling Instead of open-coding the calculations for ESSIV handling, use an ESSIV skcipher which does all of this under the hood. ESSIV was added to the crypto API in v5.4. This is based on a patch from Ard Biesheuvel, but reworked to apply after all the fscrypt changes that went into v5.4. Tested with 'kvm-xfstests -c ext4,f2fs -g encrypt', including the ciphertext verification tests for v1 and v2 encryption policies. Originally-from: Ard Biesheuvel Acked-by: Ard Biesheuvel Signed-off-by: Eric Biggers --- Documentation/filesystems/fscrypt.rst | 5 +- fs/crypto/crypto.c | 4 - fs/crypto/fscrypt_private.h | 7 -- fs/crypto/keysetup.c | 111 +++----------------------- fs/crypto/keysetup_v1.c | 4 - 5 files changed, 14 insertions(+), 117 deletions(-) diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 8a0700af9596..6ec459be3de1 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -308,8 +308,9 @@ If unsure, you should use the (AES-256-XTS, AES-256-CTS-CBC) pair. AES-128-CBC was added only for low-powered embedded devices with crypto accelerators such as CAAM or CESA that do not support XTS. To -use AES-128-CBC, CONFIG_CRYPTO_SHA256 (or another SHA-256 -implementation) must be enabled so that ESSIV can be used. +use AES-128-CBC, CONFIG_CRYPTO_ESSIV and CONFIG_CRYPTO_SHA256 (or +another SHA-256 implementation) must be enabled so that ESSIV can be +used. Adiantum is a (primarily) stream cipher-based mode that is fast even on CPUs without dedicated crypto instructions. It's also a true diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 35efeae24efc..946d9bb70cf2 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include "fscrypt_private.h" @@ -142,9 +141,6 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, if (fscrypt_is_direct_key_policy(&ci->ci_policy)) memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE); - - if (ci->ci_essiv_tfm != NULL) - crypto_cipher_encrypt_one(ci->ci_essiv_tfm, iv->raw, iv->raw); } /* Encrypt or decrypt a single filesystem block of file contents */ diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index e84efc01512e..76c64297ce18 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -163,12 +163,6 @@ struct fscrypt_info { /* The actual crypto transform used for encryption and decryption */ struct crypto_skcipher *ci_ctfm; - /* - * Cipher for ESSIV IV generation. Only set for CBC contents - * encryption, otherwise is NULL. - */ - struct crypto_cipher *ci_essiv_tfm; - /* * Encryption mode used for this inode. It corresponds to either the * contents or filenames encryption mode, depending on the inode type. @@ -444,7 +438,6 @@ struct fscrypt_mode { int keysize; int ivsize; bool logged_impl_name; - bool needs_essiv; }; static inline bool diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index e3ba6b45c06c..03ecd4ed713a 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -8,15 +8,11 @@ * Heavily modified since then. */ -#include -#include #include #include #include "fscrypt_private.h" -static struct crypto_shash *essiv_hash_tfm; - static struct fscrypt_mode available_modes[] = { [FSCRYPT_MODE_AES_256_XTS] = { .friendly_name = "AES-256-XTS", @@ -31,11 +27,10 @@ static struct fscrypt_mode available_modes[] = { .ivsize = 16, }, [FSCRYPT_MODE_AES_128_CBC] = { - .friendly_name = "AES-128-CBC", - .cipher_str = "cbc(aes)", + .friendly_name = "AES-128-CBC-ESSIV", + .cipher_str = "essiv(cbc(aes),sha256)", .keysize = 16, .ivsize = 16, - .needs_essiv = true, }, [FSCRYPT_MODE_AES_128_CTS] = { .friendly_name = "AES-128-CTS-CBC", @@ -111,98 +106,16 @@ struct crypto_skcipher *fscrypt_allocate_skcipher(struct fscrypt_mode *mode, return ERR_PTR(err); } -static int derive_essiv_salt(const u8 *key, int keysize, u8 *salt) -{ - struct crypto_shash *tfm = READ_ONCE(essiv_hash_tfm); - - /* init hash transform on demand */ - if (unlikely(!tfm)) { - struct crypto_shash *prev_tfm; - - tfm = crypto_alloc_shash("sha256", 0, 0); - if (IS_ERR(tfm)) { - if (PTR_ERR(tfm) == -ENOENT) { - fscrypt_warn(NULL, - "Missing crypto API support for SHA-256"); - return -ENOPKG; - } - fscrypt_err(NULL, - "Error allocating SHA-256 transform: %ld", - PTR_ERR(tfm)); - return PTR_ERR(tfm); - } - prev_tfm = cmpxchg(&essiv_hash_tfm, NULL, tfm); - if (prev_tfm) { - crypto_free_shash(tfm); - tfm = prev_tfm; - } - } - - { - SHASH_DESC_ON_STACK(desc, tfm); - desc->tfm = tfm; - desc->flags = 0; - - return crypto_shash_digest(desc, key, keysize, salt); - } -} - -static int init_essiv_generator(struct fscrypt_info *ci, const u8 *raw_key, - int keysize) -{ - int err; - struct crypto_cipher *essiv_tfm; - u8 salt[SHA256_DIGEST_SIZE]; - - if (WARN_ON(ci->ci_mode->ivsize != AES_BLOCK_SIZE)) - return -EINVAL; - - essiv_tfm = crypto_alloc_cipher("aes", 0, 0); - if (IS_ERR(essiv_tfm)) - return PTR_ERR(essiv_tfm); - - ci->ci_essiv_tfm = essiv_tfm; - - err = derive_essiv_salt(raw_key, keysize, salt); - if (err) - goto out; - - /* - * Using SHA256 to derive the salt/key will result in AES-256 being - * used for IV generation. File contents encryption will still use the - * configured keysize (AES-128) nevertheless. - */ - err = crypto_cipher_setkey(essiv_tfm, salt, sizeof(salt)); - if (err) - goto out; - -out: - memzero_explicit(salt, sizeof(salt)); - return err; -} - -/* Given the per-file key, set up the file's crypto transform object(s) */ +/* Given the per-file key, set up the file's crypto transform object */ int fscrypt_set_derived_key(struct fscrypt_info *ci, const u8 *derived_key) { - struct fscrypt_mode *mode = ci->ci_mode; - struct crypto_skcipher *ctfm; - int err; - - ctfm = fscrypt_allocate_skcipher(mode, derived_key, ci->ci_inode); - if (IS_ERR(ctfm)) - return PTR_ERR(ctfm); + struct crypto_skcipher *tfm; - ci->ci_ctfm = ctfm; + tfm = fscrypt_allocate_skcipher(ci->ci_mode, derived_key, ci->ci_inode); + if (IS_ERR(tfm)) + return PTR_ERR(tfm); - if (mode->needs_essiv) { - err = init_essiv_generator(ci, derived_key, mode->keysize); - if (err) { - fscrypt_warn(ci->ci_inode, - "Error initializing ESSIV generator: %d", - err); - return err; - } - } + ci->ci_ctfm = tfm; return 0; } @@ -389,13 +302,11 @@ static void put_crypt_info(struct fscrypt_info *ci) if (!ci) return; - if (ci->ci_direct_key) { + if (ci->ci_direct_key) fscrypt_put_direct_key(ci->ci_direct_key); - } else if ((ci->ci_ctfm != NULL || ci->ci_essiv_tfm != NULL) && - !fscrypt_is_direct_key_policy(&ci->ci_policy)) { + else if (ci->ci_ctfm != NULL && + !fscrypt_is_direct_key_policy(&ci->ci_policy)) crypto_free_skcipher(ci->ci_ctfm); - crypto_free_cipher(ci->ci_essiv_tfm); - } key = ci->ci_master_key; if (key) { diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c index 4ae795d61840..454fb03fc30e 100644 --- a/fs/crypto/keysetup_v1.c +++ b/fs/crypto/keysetup_v1.c @@ -270,10 +270,6 @@ static int setup_v1_file_key_direct(struct fscrypt_info *ci, return -EINVAL; } - /* ESSIV implies 16-byte IVs which implies !DIRECT_KEY */ - if (WARN_ON(mode->needs_essiv)) - return -EINVAL; - dk = fscrypt_get_direct_key(ci, raw_master_key); if (IS_ERR(dk)) return PTR_ERR(dk); -- GitLab From e3ba9dad312c74db8fa8d685fd6329fccfb53cda Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 9 Oct 2019 16:34:17 -0700 Subject: [PATCH 0002/1055] fscrypt: remove struct fscrypt_ctx Now that ext4 and f2fs implement their own post-read workflow that supports both fscrypt and fsverity, the fscrypt-only workflow based around struct fscrypt_ctx is no longer used. So remove the unused code. This is based on a patch from Chandan Rajendra's "Consolidate FS read I/O callbacks code" patchset, but rebased onto the latest kernel, folded __fscrypt_decrypt_bio() into fscrypt_decrypt_bio(), cleaned up fscrypt_initialize(), and updated the commit message. Originally-from: Chandan Rajendra Signed-off-by: Eric Biggers --- fs/crypto/bio.c | 29 +--------- fs/crypto/crypto.c | 110 +++--------------------------------- fs/crypto/fscrypt_private.h | 2 - include/linux/fscrypt.h | 32 ----------- 4 files changed, 10 insertions(+), 163 deletions(-) diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index 0eb98a6d6f14..4a7f4d78ef90 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -26,7 +26,7 @@ #include #include "fscrypt_private.h" -static void __fscrypt_decrypt_bio(struct bio *bio, bool done) +void fscrypt_decrypt_bio(struct bio *bio) { struct bio_vec *bv; int i; @@ -37,37 +37,10 @@ static void __fscrypt_decrypt_bio(struct bio *bio, bool done) bv->bv_offset); if (ret) SetPageError(page); - else if (done) - SetPageUptodate(page); - if (done) - unlock_page(page); } } - -void fscrypt_decrypt_bio(struct bio *bio) -{ - __fscrypt_decrypt_bio(bio, false); -} EXPORT_SYMBOL(fscrypt_decrypt_bio); -static void completion_pages(struct work_struct *work) -{ - struct fscrypt_ctx *ctx = container_of(work, struct fscrypt_ctx, work); - struct bio *bio = ctx->bio; - - __fscrypt_decrypt_bio(bio, true); - fscrypt_release_ctx(ctx); - bio_put(bio); -} - -void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, struct bio *bio) -{ - INIT_WORK(&ctx->work, completion_pages); - ctx->bio = bio; - fscrypt_enqueue_decrypt_work(&ctx->work); -} -EXPORT_SYMBOL(fscrypt_enqueue_decrypt_bio); - int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, sector_t pblk, unsigned int len) { diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 946d9bb70cf2..9c5b59cdc63c 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -30,24 +30,16 @@ #include "fscrypt_private.h" static unsigned int num_prealloc_crypto_pages = 32; -static unsigned int num_prealloc_crypto_ctxs = 128; module_param(num_prealloc_crypto_pages, uint, 0444); MODULE_PARM_DESC(num_prealloc_crypto_pages, "Number of crypto pages to preallocate"); -module_param(num_prealloc_crypto_ctxs, uint, 0444); -MODULE_PARM_DESC(num_prealloc_crypto_ctxs, - "Number of crypto contexts to preallocate"); static mempool_t *fscrypt_bounce_page_pool = NULL; -static LIST_HEAD(fscrypt_free_ctxs); -static DEFINE_SPINLOCK(fscrypt_ctx_lock); - static struct workqueue_struct *fscrypt_read_workqueue; static DEFINE_MUTEX(fscrypt_init_mutex); -static struct kmem_cache *fscrypt_ctx_cachep; struct kmem_cache *fscrypt_info_cachep; void fscrypt_enqueue_decrypt_work(struct work_struct *work) @@ -56,62 +48,6 @@ void fscrypt_enqueue_decrypt_work(struct work_struct *work) } EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work); -/** - * fscrypt_release_ctx() - Release a decryption context - * @ctx: The decryption context to release. - * - * If the decryption context was allocated from the pre-allocated pool, return - * it to that pool. Else, free it. - */ -void fscrypt_release_ctx(struct fscrypt_ctx *ctx) -{ - unsigned long flags; - - if (ctx->flags & FS_CTX_REQUIRES_FREE_ENCRYPT_FL) { - kmem_cache_free(fscrypt_ctx_cachep, ctx); - } else { - spin_lock_irqsave(&fscrypt_ctx_lock, flags); - list_add(&ctx->free_list, &fscrypt_free_ctxs); - spin_unlock_irqrestore(&fscrypt_ctx_lock, flags); - } -} -EXPORT_SYMBOL(fscrypt_release_ctx); - -/** - * fscrypt_get_ctx() - Get a decryption context - * @gfp_flags: The gfp flag for memory allocation - * - * Allocate and initialize a decryption context. - * - * Return: A new decryption context on success; an ERR_PTR() otherwise. - */ -struct fscrypt_ctx *fscrypt_get_ctx(gfp_t gfp_flags) -{ - struct fscrypt_ctx *ctx; - unsigned long flags; - - /* - * First try getting a ctx from the free list so that we don't have to - * call into the slab allocator. - */ - spin_lock_irqsave(&fscrypt_ctx_lock, flags); - ctx = list_first_entry_or_null(&fscrypt_free_ctxs, - struct fscrypt_ctx, free_list); - if (ctx) - list_del(&ctx->free_list); - spin_unlock_irqrestore(&fscrypt_ctx_lock, flags); - if (!ctx) { - ctx = kmem_cache_zalloc(fscrypt_ctx_cachep, gfp_flags); - if (!ctx) - return ERR_PTR(-ENOMEM); - ctx->flags |= FS_CTX_REQUIRES_FREE_ENCRYPT_FL; - } else { - ctx->flags &= ~FS_CTX_REQUIRES_FREE_ENCRYPT_FL; - } - return ctx; -} -EXPORT_SYMBOL(fscrypt_get_ctx); - struct page *fscrypt_alloc_bounce_page(gfp_t gfp_flags) { return mempool_alloc(fscrypt_bounce_page_pool, gfp_flags); @@ -391,17 +327,6 @@ const struct dentry_operations fscrypt_d_ops = { .d_revalidate = fscrypt_d_revalidate, }; -static void fscrypt_destroy(void) -{ - struct fscrypt_ctx *pos, *n; - - list_for_each_entry_safe(pos, n, &fscrypt_free_ctxs, free_list) - kmem_cache_free(fscrypt_ctx_cachep, pos); - INIT_LIST_HEAD(&fscrypt_free_ctxs); - mempool_destroy(fscrypt_bounce_page_pool); - fscrypt_bounce_page_pool = NULL; -} - /** * fscrypt_initialize() - allocate major buffers for fs encryption. * @cop_flags: fscrypt operations flags @@ -409,11 +334,11 @@ static void fscrypt_destroy(void) * We only call this when we start accessing encrypted files, since it * results in memory getting allocated that wouldn't otherwise be used. * - * Return: Zero on success, non-zero otherwise. + * Return: 0 on success; -errno on failure */ int fscrypt_initialize(unsigned int cop_flags) { - int i, res = -ENOMEM; + int err = 0; /* No need to allocate a bounce page pool if this FS won't use it. */ if (cop_flags & FS_CFLG_OWN_PAGES) @@ -421,29 +346,18 @@ int fscrypt_initialize(unsigned int cop_flags) mutex_lock(&fscrypt_init_mutex); if (fscrypt_bounce_page_pool) - goto already_initialized; - - for (i = 0; i < num_prealloc_crypto_ctxs; i++) { - struct fscrypt_ctx *ctx; - - ctx = kmem_cache_zalloc(fscrypt_ctx_cachep, GFP_NOFS); - if (!ctx) - goto fail; - list_add(&ctx->free_list, &fscrypt_free_ctxs); - } + goto out_unlock; + err = -ENOMEM; fscrypt_bounce_page_pool = mempool_create_page_pool(num_prealloc_crypto_pages, 0); if (!fscrypt_bounce_page_pool) - goto fail; + goto out_unlock; -already_initialized: - mutex_unlock(&fscrypt_init_mutex); - return 0; -fail: - fscrypt_destroy(); + err = 0; +out_unlock: mutex_unlock(&fscrypt_init_mutex); - return res; + return err; } void fscrypt_msg(const struct inode *inode, const char *level, @@ -489,13 +403,9 @@ static int __init fscrypt_init(void) if (!fscrypt_read_workqueue) goto fail; - fscrypt_ctx_cachep = KMEM_CACHE(fscrypt_ctx, SLAB_RECLAIM_ACCOUNT); - if (!fscrypt_ctx_cachep) - goto fail_free_queue; - fscrypt_info_cachep = KMEM_CACHE(fscrypt_info, SLAB_RECLAIM_ACCOUNT); if (!fscrypt_info_cachep) - goto fail_free_ctx; + goto fail_free_queue; err = fscrypt_init_keyring(); if (err) @@ -505,8 +415,6 @@ static int __init fscrypt_init(void) fail_free_info: kmem_cache_destroy(fscrypt_info_cachep); -fail_free_ctx: - kmem_cache_destroy(fscrypt_ctx_cachep); fail_free_queue: destroy_workqueue(fscrypt_read_workqueue); fail: diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 76c64297ce18..dacf8fcbac3b 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -203,8 +203,6 @@ typedef enum { FS_ENCRYPT, } fscrypt_direction_t; -#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001 - static inline bool fscrypt_valid_enc_modes(u32 contents_mode, u32 filenames_mode) { diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 72ea24ce52ab..d1013ba97ddf 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -20,7 +20,6 @@ #define FS_CRYPTO_BLOCK_SIZE 16 -struct fscrypt_ctx; struct fscrypt_info; struct fscrypt_str { @@ -64,18 +63,6 @@ struct fscrypt_operations { unsigned int max_namelen; }; -/* Decryption work */ -struct fscrypt_ctx { - union { - struct { - struct bio *bio; - struct work_struct work; - }; - struct list_head free_list; /* Free list */ - }; - u8 flags; /* Flags */ -}; - static inline bool fscrypt_has_encryption_key(const struct inode *inode) { /* pairs with cmpxchg_release() in fscrypt_get_encryption_info() */ @@ -102,8 +89,6 @@ static inline void fscrypt_handle_d_move(struct dentry *dentry) /* crypto.c */ extern void fscrypt_enqueue_decrypt_work(struct work_struct *); -extern struct fscrypt_ctx *fscrypt_get_ctx(gfp_t); -extern void fscrypt_release_ctx(struct fscrypt_ctx *); extern struct page *fscrypt_encrypt_pagecache_blocks(struct page *page, unsigned int len, @@ -244,8 +229,6 @@ static inline bool fscrypt_match_name(const struct fscrypt_name *fname, /* bio.c */ extern void fscrypt_decrypt_bio(struct bio *); -extern void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, - struct bio *bio); extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, unsigned int); @@ -290,16 +273,6 @@ static inline void fscrypt_enqueue_decrypt_work(struct work_struct *work) { } -static inline struct fscrypt_ctx *fscrypt_get_ctx(gfp_t gfp_flags) -{ - return ERR_PTR(-EOPNOTSUPP); -} - -static inline void fscrypt_release_ctx(struct fscrypt_ctx *ctx) -{ - return; -} - static inline struct page *fscrypt_encrypt_pagecache_blocks(struct page *page, unsigned int len, unsigned int offs, @@ -479,11 +452,6 @@ static inline void fscrypt_decrypt_bio(struct bio *bio) { } -static inline void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, - struct bio *bio) -{ -} - static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, sector_t pblk, unsigned int len) { -- GitLab From 85416094893e980b18aa20ddc0435695c3aaca64 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 9 Oct 2019 16:34:17 -0700 Subject: [PATCH 0003/1055] fscrypt: zeroize fscrypt_info before freeing memset the struct fscrypt_info to zero before freeing. This isn't really needed currently, since there's no secret key directly in the fscrypt_info. But there's a decent chance that someone will add such a field in the future, e.g. in order to use an API that takes a raw key such as siphash(). So it's good to do this as a hardening measure. Signed-off-by: Eric Biggers --- fs/crypto/keysetup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 03ecd4ed713a..8b6072b2b84f 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -327,6 +327,7 @@ static void put_crypt_info(struct fscrypt_info *ci) key_invalidate(key); key_put(key); } + memzero_explicit(ci, sizeof(*ci)); kmem_cache_free(fscrypt_info_cachep, ci); } -- GitLab From 5d0a5024fd62229f65c56aac6fa2dfe01fc5ba45 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 21 Oct 2019 13:49:03 -0700 Subject: [PATCH 0004/1055] fscrypt: avoid data race on fscrypt_mode::logged_impl_name The access to logged_impl_name is technically a data race, which tools like KCSAN could complain about in the future. See: https://github.com/google/ktsan/wiki/READ_ONCE-and-WRITE_ONCE Fix by using xchg(), which also ensures that only one thread does the logging. This also required switching from bool to int, to avoid a build error on the RISC-V architecture which doesn't implement xchg on bytes. Signed-off-by: Eric Biggers --- fs/crypto/fscrypt_private.h | 2 +- fs/crypto/keysetup.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index dacf8fcbac3b..d9a3e8614049 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -435,7 +435,7 @@ struct fscrypt_mode { const char *cipher_str; int keysize; int ivsize; - bool logged_impl_name; + int logged_impl_name; }; static inline bool diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index 8b6072b2b84f..b634e9d71aa4 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -81,15 +81,13 @@ struct crypto_skcipher *fscrypt_allocate_skcipher(struct fscrypt_mode *mode, mode->cipher_str, PTR_ERR(tfm)); return tfm; } - if (unlikely(!mode->logged_impl_name)) { + if (!xchg(&mode->logged_impl_name, 1)) { /* * fscrypt performance can vary greatly depending on which * crypto algorithm implementation is used. Help people debug * performance problems by logging the ->cra_driver_name the - * first time a mode is used. Note that multiple threads can - * race here, but it doesn't really matter. + * first time a mode is used. */ - mode->logged_impl_name = true; pr_info("fscrypt: %s using implementation \"%s\"\n", mode->friendly_name, crypto_skcipher_alg(tfm)->base.cra_driver_name); -- GitLab From 959cb31e1ae85bf249a8faf142a74d3af3d27c3d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 24 Oct 2019 14:54:36 -0700 Subject: [PATCH 0005/1055] fscrypt: add support for IV_INO_LBLK_64 policies Inline encryption hardware compliant with the UFS v2.1 standard or with the upcoming version of the eMMC standard has the following properties: (1) Per I/O request, the encryption key is specified by a previously loaded keyslot. There might be only a small number of keyslots. (2) Per I/O request, the starting IV is specified by a 64-bit "data unit number" (DUN). IV bits 64-127 are assumed to be 0. The hardware automatically increments the DUN for each "data unit" of configurable size in the request, e.g. for each filesystem block. Property (1) makes it inefficient to use the traditional fscrypt per-file keys. Property (2) precludes the use of the existing DIRECT_KEY fscrypt policy flag, which needs at least 192 IV bits. Therefore, add a new fscrypt policy flag IV_INO_LBLK_64 which causes the encryption to modified as follows: - The encryption keys are derived from the master key, encryption mode number, and filesystem UUID. - The IVs are chosen as (inode_number << 32) | file_logical_block_num. For filenames encryption, file_logical_block_num is 0. Since the file nonces aren't used in the key derivation, many files may share the same encryption key. This is much more efficient on the target hardware. Including the inode number in the IVs and mixing the filesystem UUID into the keys ensures that data in different files is nevertheless still encrypted differently. Additionally, limiting the inode and block numbers to 32 bits and placing the block number in the low bits maintains compatibility with the 64-bit DUN convention (property (2) above). Since this scheme assumes that inode numbers are stable (which may preclude filesystem shrinking) and that inode and file logical block numbers are at most 32-bit, IV_INO_LBLK_64 will only be allowed on filesystems that meet these constraints. These are acceptable limitations for the cases where this format would actually be used. Note that IV_INO_LBLK_64 is an on-disk format, not an implementation. This patch just adds support for it using the existing filesystem layer encryption. A later patch will add support for inline encryption. Reviewed-by: Paul Crowley Co-developed-by: Satya Tangirala Signed-off-by: Satya Tangirala Signed-off-by: Eric Biggers --- Documentation/filesystems/fscrypt.rst | 63 +++++++++++++++++---------- fs/crypto/crypto.c | 10 ++++- fs/crypto/fscrypt_private.h | 16 +++++-- fs/crypto/keyring.c | 6 ++- fs/crypto/keysetup.c | 45 ++++++++++++++----- fs/crypto/policy.c | 41 ++++++++++++++++- include/linux/fscrypt.h | 3 ++ include/uapi/linux/fscrypt.h | 3 +- 8 files changed, 146 insertions(+), 41 deletions(-) diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 6ec459be3de1..471a511c7508 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -256,13 +256,8 @@ alternative master keys or to support rotating master keys. Instead, the master keys may be wrapped in userspace, e.g. as is done by the `fscrypt `_ tool. -Including the inode number in the IVs was considered. However, it was -rejected as it would have prevented ext4 filesystems from being -resized, and by itself still wouldn't have been sufficient to prevent -the same key from being directly reused for both XTS and CTS-CBC. - -DIRECT_KEY and per-mode keys ----------------------------- +DIRECT_KEY policies +------------------- The Adiantum encryption mode (see `Encryption modes and usage`_) is suitable for both contents and filenames encryption, and it accepts @@ -285,6 +280,21 @@ IV. Moreover: key derived using the KDF. Users may use the same master key for other v2 encryption policies. +IV_INO_LBLK_64 policies +----------------------- + +When FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 is set in the fscrypt policy, +the encryption keys are derived from the master key, encryption mode +number, and filesystem UUID. This normally results in all files +protected by the same master key sharing a single contents encryption +key and a single filenames encryption key. To still encrypt different +files' data differently, inode numbers are included in the IVs. +Consequently, shrinking the filesystem may not be allowed. + +This format is optimized for use with inline encryption hardware +compliant with the UFS or eMMC standards, which support only 64 IV +bits per I/O request and may have only a small number of keyslots. + Key identifiers --------------- @@ -342,10 +352,16 @@ a little endian number, except that: is encrypted with AES-256 where the AES-256 key is the SHA-256 hash of the file's data encryption key. -- In the "direct key" configuration (FSCRYPT_POLICY_FLAG_DIRECT_KEY - set in the fscrypt_policy), the file's nonce is also appended to the - IV. Currently this is only allowed with the Adiantum encryption - mode. +- With `DIRECT_KEY policies`_, the file's nonce is appended to the IV. + Currently this is only allowed with the Adiantum encryption mode. + +- With `IV_INO_LBLK_64 policies`_, the logical block number is limited + to 32 bits and is placed in bits 0-31 of the IV. The inode number + (which is also limited to 32 bits) is placed in bits 32-63. + +Note that because file logical block numbers are included in the IVs, +filesystems must enforce that blocks are never shifted around within +encrypted files, e.g. via "collapse range" or "insert range". Filenames encryption -------------------- @@ -355,10 +371,10 @@ the requirements to retain support for efficient directory lookups and filenames of up to 255 bytes, the same IV is used for every filename in a directory. -However, each encrypted directory still uses a unique key; or -alternatively (for the "direct key" configuration) has the file's -nonce included in the IVs. Thus, IV reuse is limited to within a -single directory. +However, each encrypted directory still uses a unique key, or +alternatively has the file's nonce (for `DIRECT_KEY policies`_) or +inode number (for `IV_INO_LBLK_64 policies`_) included in the IVs. +Thus, IV reuse is limited to within a single directory. With CTS-CBC, the IV reuse means that when the plaintext filenames share a common prefix at least as long as the cipher block size (16 @@ -432,12 +448,15 @@ This structure must be initialized as follows: (1) for ``contents_encryption_mode`` and FSCRYPT_MODE_AES_256_CTS (4) for ``filenames_encryption_mode``. -- ``flags`` must contain a value from ```` which - identifies the amount of NUL-padding to use when encrypting - filenames. If unsure, use FSCRYPT_POLICY_FLAGS_PAD_32 (0x3). - Additionally, if the encryption modes are both - FSCRYPT_MODE_ADIANTUM, this can contain - FSCRYPT_POLICY_FLAG_DIRECT_KEY; see `DIRECT_KEY and per-mode keys`_. +- ``flags`` contains optional flags from ````: + + - FSCRYPT_POLICY_FLAGS_PAD_*: The amount of NUL padding to use when + encrypting filenames. If unsure, use FSCRYPT_POLICY_FLAGS_PAD_32 + (0x3). + - FSCRYPT_POLICY_FLAG_DIRECT_KEY: See `DIRECT_KEY policies`_. + - FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64: See `IV_INO_LBLK_64 + policies`_. This is mutually exclusive with DIRECT_KEY and is not + supported on v1 policies. - For v2 encryption policies, ``__reserved`` must be zeroed. @@ -1090,7 +1109,7 @@ policy structs (see `Setting an encryption policy`_), except that the context structs also contain a nonce. The nonce is randomly generated by the kernel and is used as KDF input or as a tweak to cause different files to be encrypted differently; see `Per-file keys`_ and -`DIRECT_KEY and per-mode keys`_. +`DIRECT_KEY policies`_. Data path changes ----------------- diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 9c5b59cdc63c..6e6f39ea18a7 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -72,11 +72,17 @@ EXPORT_SYMBOL(fscrypt_free_bounce_page); void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num, const struct fscrypt_info *ci) { + u8 flags = fscrypt_policy_flags(&ci->ci_policy); + memset(iv, 0, ci->ci_mode->ivsize); - iv->lblk_num = cpu_to_le64(lblk_num); - if (fscrypt_is_direct_key_policy(&ci->ci_policy)) + if (flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { + WARN_ON_ONCE((u32)lblk_num != lblk_num); + lblk_num |= (u64)ci->ci_inode->i_ino << 32; + } else if (flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE); + } + iv->lblk_num = cpu_to_le64(lblk_num); } /* Encrypt or decrypt a single filesystem block of file contents */ diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index d9a3e8614049..130b50e5a011 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -163,6 +163,9 @@ struct fscrypt_info { /* The actual crypto transform used for encryption and decryption */ struct crypto_skcipher *ci_ctfm; + /* True if the key should be freed when this fscrypt_info is freed */ + bool ci_owns_key; + /* * Encryption mode used for this inode. It corresponds to either the * contents or filenames encryption mode, depending on the inode type. @@ -281,7 +284,8 @@ extern int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key, */ #define HKDF_CONTEXT_KEY_IDENTIFIER 1 #define HKDF_CONTEXT_PER_FILE_KEY 2 -#define HKDF_CONTEXT_PER_MODE_KEY 3 +#define HKDF_CONTEXT_DIRECT_KEY 3 +#define HKDF_CONTEXT_IV_INO_LBLK_64_KEY 4 extern int fscrypt_hkdf_expand(struct fscrypt_hkdf *hkdf, u8 context, const u8 *info, unsigned int infolen, @@ -378,8 +382,14 @@ struct fscrypt_master_key { struct list_head mk_decrypted_inodes; spinlock_t mk_decrypted_inodes_lock; - /* Per-mode tfms for DIRECT_KEY policies, allocated on-demand */ - struct crypto_skcipher *mk_mode_keys[__FSCRYPT_MODE_MAX + 1]; + /* Crypto API transforms for DIRECT_KEY policies, allocated on-demand */ + struct crypto_skcipher *mk_direct_tfms[__FSCRYPT_MODE_MAX + 1]; + + /* + * Crypto API transforms for filesystem-layer implementation of + * IV_INO_LBLK_64 policies, allocated on-demand. + */ + struct crypto_skcipher *mk_iv_ino_lblk_64_tfms[__FSCRYPT_MODE_MAX + 1]; } __randomize_layout; diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c index 7f43ca5d30ae..ecbebdc1b02a 100644 --- a/fs/crypto/keyring.c +++ b/fs/crypto/keyring.c @@ -43,8 +43,10 @@ static void free_master_key(struct fscrypt_master_key *mk) wipe_master_key_secret(&mk->mk_secret); - for (i = 0; i < ARRAY_SIZE(mk->mk_mode_keys); i++) - crypto_free_skcipher(mk->mk_mode_keys[i]); + for (i = 0; i <= __FSCRYPT_MODE_MAX; i++) { + crypto_free_skcipher(mk->mk_direct_tfms[i]); + crypto_free_skcipher(mk->mk_iv_ino_lblk_64_tfms[i]); + } key_put(mk->mk_users); kzfree(mk); diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c index b634e9d71aa4..2f926d3e6b5d 100644 --- a/fs/crypto/keysetup.c +++ b/fs/crypto/keysetup.c @@ -114,40 +114,54 @@ int fscrypt_set_derived_key(struct fscrypt_info *ci, const u8 *derived_key) return PTR_ERR(tfm); ci->ci_ctfm = tfm; + ci->ci_owns_key = true; return 0; } static int setup_per_mode_key(struct fscrypt_info *ci, - struct fscrypt_master_key *mk) + struct fscrypt_master_key *mk, + struct crypto_skcipher **tfms, + u8 hkdf_context, bool include_fs_uuid) { + const struct inode *inode = ci->ci_inode; + const struct super_block *sb = inode->i_sb; struct fscrypt_mode *mode = ci->ci_mode; u8 mode_num = mode - available_modes; struct crypto_skcipher *tfm, *prev_tfm; u8 mode_key[FSCRYPT_MAX_KEY_SIZE]; + u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)]; + unsigned int hkdf_infolen = 0; int err; - if (WARN_ON(mode_num >= ARRAY_SIZE(mk->mk_mode_keys))) + if (WARN_ON(mode_num > __FSCRYPT_MODE_MAX)) return -EINVAL; /* pairs with cmpxchg() below */ - tfm = READ_ONCE(mk->mk_mode_keys[mode_num]); + tfm = READ_ONCE(tfms[mode_num]); if (likely(tfm != NULL)) goto done; BUILD_BUG_ON(sizeof(mode_num) != 1); + BUILD_BUG_ON(sizeof(sb->s_uuid) != 16); + BUILD_BUG_ON(sizeof(hkdf_info) != 17); + hkdf_info[hkdf_infolen++] = mode_num; + if (include_fs_uuid) { + memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid, + sizeof(sb->s_uuid)); + hkdf_infolen += sizeof(sb->s_uuid); + } err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, - HKDF_CONTEXT_PER_MODE_KEY, - &mode_num, sizeof(mode_num), + hkdf_context, hkdf_info, hkdf_infolen, mode_key, mode->keysize); if (err) return err; - tfm = fscrypt_allocate_skcipher(mode, mode_key, ci->ci_inode); + tfm = fscrypt_allocate_skcipher(mode, mode_key, inode); memzero_explicit(mode_key, mode->keysize); if (IS_ERR(tfm)) return PTR_ERR(tfm); /* pairs with READ_ONCE() above */ - prev_tfm = cmpxchg(&mk->mk_mode_keys[mode_num], NULL, tfm); + prev_tfm = cmpxchg(&tfms[mode_num], NULL, tfm); if (prev_tfm != NULL) { crypto_free_skcipher(tfm); tfm = prev_tfm; @@ -178,7 +192,19 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_info *ci, ci->ci_mode->friendly_name); return -EINVAL; } - return setup_per_mode_key(ci, mk); + return setup_per_mode_key(ci, mk, mk->mk_direct_tfms, + HKDF_CONTEXT_DIRECT_KEY, false); + } else if (ci->ci_policy.v2.flags & + FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) { + /* + * IV_INO_LBLK_64: encryption keys are derived from (master_key, + * mode_num, filesystem_uuid), and inode number is included in + * the IVs. This format is optimized for use with inline + * encryption hardware compliant with the UFS or eMMC standards. + */ + return setup_per_mode_key(ci, mk, mk->mk_iv_ino_lblk_64_tfms, + HKDF_CONTEXT_IV_INO_LBLK_64_KEY, + true); } err = fscrypt_hkdf_expand(&mk->mk_secret.hkdf, @@ -302,8 +328,7 @@ static void put_crypt_info(struct fscrypt_info *ci) if (ci->ci_direct_key) fscrypt_put_direct_key(ci->ci_direct_key); - else if (ci->ci_ctfm != NULL && - !fscrypt_is_direct_key_policy(&ci->ci_policy)) + else if (ci->ci_owns_key) crypto_free_skcipher(ci->ci_ctfm); key = ci->ci_master_key; diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c index 4072ba644595..96f528071bed 100644 --- a/fs/crypto/policy.c +++ b/fs/crypto/policy.c @@ -29,6 +29,40 @@ bool fscrypt_policies_equal(const union fscrypt_policy *policy1, return !memcmp(policy1, policy2, fscrypt_policy_size(policy1)); } +static bool supported_iv_ino_lblk_64_policy( + const struct fscrypt_policy_v2 *policy, + const struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + int ino_bits = 64, lblk_bits = 64; + + if (policy->flags & FSCRYPT_POLICY_FLAG_DIRECT_KEY) { + fscrypt_warn(inode, + "The DIRECT_KEY and IV_INO_LBLK_64 flags are mutually exclusive"); + return false; + } + /* + * It's unsafe to include inode numbers in the IVs if the filesystem can + * potentially renumber inodes, e.g. via filesystem shrinking. + */ + if (!sb->s_cop->has_stable_inodes || + !sb->s_cop->has_stable_inodes(sb)) { + fscrypt_warn(inode, + "Can't use IV_INO_LBLK_64 policy on filesystem '%s' because it doesn't have stable inode numbers", + sb->s_id); + return false; + } + if (sb->s_cop->get_ino_and_lblk_bits) + sb->s_cop->get_ino_and_lblk_bits(sb, &ino_bits, &lblk_bits); + if (ino_bits > 32 || lblk_bits > 32) { + fscrypt_warn(inode, + "Can't use IV_INO_LBLK_64 policy on filesystem '%s' because it doesn't use 32-bit inode and block numbers", + sb->s_id); + return false; + } + return true; +} + /** * fscrypt_supported_policy - check whether an encryption policy is supported * @@ -55,7 +89,8 @@ bool fscrypt_supported_policy(const union fscrypt_policy *policy_u, return false; } - if (policy->flags & ~FSCRYPT_POLICY_FLAGS_VALID) { + if (policy->flags & ~(FSCRYPT_POLICY_FLAGS_PAD_MASK | + FSCRYPT_POLICY_FLAG_DIRECT_KEY)) { fscrypt_warn(inode, "Unsupported encryption flags (0x%02x)", policy->flags); @@ -83,6 +118,10 @@ bool fscrypt_supported_policy(const union fscrypt_policy *policy_u, return false; } + if ((policy->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) && + !supported_iv_ino_lblk_64_policy(policy, inode)) + return false; + if (memchr_inv(policy->__reserved, 0, sizeof(policy->__reserved))) { fscrypt_warn(inode, diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index d1013ba97ddf..7f302250e52e 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -61,6 +61,9 @@ struct fscrypt_operations { bool (*dummy_context)(struct inode *); bool (*empty_dir)(struct inode *); unsigned int max_namelen; + bool (*has_stable_inodes)(struct super_block *sb); + void (*get_ino_and_lblk_bits)(struct super_block *sb, + int *ino_bits_ret, int *lblk_bits_ret); }; static inline bool fscrypt_has_encryption_key(const struct inode *inode) diff --git a/include/uapi/linux/fscrypt.h b/include/uapi/linux/fscrypt.h index 39ccfe9311c3..1beb174ad950 100644 --- a/include/uapi/linux/fscrypt.h +++ b/include/uapi/linux/fscrypt.h @@ -17,7 +17,8 @@ #define FSCRYPT_POLICY_FLAGS_PAD_32 0x03 #define FSCRYPT_POLICY_FLAGS_PAD_MASK 0x03 #define FSCRYPT_POLICY_FLAG_DIRECT_KEY 0x04 -#define FSCRYPT_POLICY_FLAGS_VALID 0x07 +#define FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 0x08 +#define FSCRYPT_POLICY_FLAGS_VALID 0x0F /* Encryption algorithms */ #define FSCRYPT_MODE_AES_256_XTS 1 -- GitLab From b9c8fe456e8918ef476d433f09bb01b424e444e4 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 24 Oct 2019 14:54:37 -0700 Subject: [PATCH 0006/1055] ext4: add support for IV_INO_LBLK_64 encryption policies IV_INO_LBLK_64 encryption policies have special requirements from the filesystem beyond those of the existing encryption policies: - Inode numbers must never change, even if the filesystem is resized. - Inode numbers must be <= 32 bits. - File logical block numbers must be <= 32 bits. ext4 has 32-bit inode and file logical block numbers. However, resize2fs can re-number inodes when shrinking an ext4 filesystem. However, typically the people who would want to use this format don't care about filesystem shrinking. They'd be fine with a solution that just prevents the filesystem from being shrunk. Therefore, add a new feature flag EXT4_FEATURE_COMPAT_STABLE_INODES that will do exactly that. Then wire up the fscrypt_operations to expose this flag to fs/crypto/, so that it allows IV_INO_LBLK_64 policies when this flag is set. Acked-by: Theodore Ts'o Signed-off-by: Eric Biggers --- fs/ext4/ext4.h | 2 ++ fs/ext4/super.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 6b1bf406cf10..8d6accd3f763 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1683,6 +1683,7 @@ static inline bool ext4_verity_in_progress(struct inode *inode) #define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010 #define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020 #define EXT4_FEATURE_COMPAT_SPARSE_SUPER2 0x0200 +#define EXT4_FEATURE_COMPAT_STABLE_INODES 0x0800 #define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 #define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 @@ -1779,6 +1780,7 @@ EXT4_FEATURE_COMPAT_FUNCS(xattr, EXT_ATTR) EXT4_FEATURE_COMPAT_FUNCS(resize_inode, RESIZE_INODE) EXT4_FEATURE_COMPAT_FUNCS(dir_index, DIR_INDEX) EXT4_FEATURE_COMPAT_FUNCS(sparse_super2, SPARSE_SUPER2) +EXT4_FEATURE_COMPAT_FUNCS(stable_inodes, STABLE_INODES) EXT4_FEATURE_RO_COMPAT_FUNCS(sparse_super, SPARSE_SUPER) EXT4_FEATURE_RO_COMPAT_FUNCS(large_file, LARGE_FILE) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 64de90f18408..066941be4812 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1239,6 +1239,18 @@ static bool ext4_dummy_context(struct inode *inode) return DUMMY_ENCRYPTION_ENABLED(EXT4_SB(inode->i_sb)); } +static bool ext4_has_stable_inodes(struct super_block *sb) +{ + return ext4_has_feature_stable_inodes(sb); +} + +static void ext4_get_ino_and_lblk_bits(struct super_block *sb, + int *ino_bits_ret, int *lblk_bits_ret) +{ + *ino_bits_ret = 8 * sizeof(EXT4_SB(sb)->s_es->s_inodes_count); + *lblk_bits_ret = 8 * sizeof(ext4_lblk_t); +} + static const struct fscrypt_operations ext4_cryptops = { .key_prefix = "ext4:", .get_context = ext4_get_context, @@ -1246,6 +1258,8 @@ static const struct fscrypt_operations ext4_cryptops = { .dummy_context = ext4_dummy_context, .empty_dir = ext4_empty_dir, .max_namelen = EXT4_NAME_LEN, + .has_stable_inodes = ext4_has_stable_inodes, + .get_ino_and_lblk_bits = ext4_get_ino_and_lblk_bits, }; #endif -- GitLab From a6a7ff5b18879839e7f4b261828addcc245c16db Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 24 Oct 2019 14:54:38 -0700 Subject: [PATCH 0007/1055] f2fs: add support for IV_INO_LBLK_64 encryption policies f2fs inode numbers are stable across filesystem resizing, and f2fs inode and file logical block numbers are always 32-bit. So f2fs can always support IV_INO_LBLK_64 encryption policies. Wire up the needed fscrypt_operations to declare support. Acked-by: Jaegeuk Kim Signed-off-by: Eric Biggers --- fs/f2fs/super.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 47898dc931ef..6ed411850b1c 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2324,13 +2324,27 @@ static bool f2fs_dummy_context(struct inode *inode) return DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(inode)); } +static bool f2fs_has_stable_inodes(struct super_block *sb) +{ + return true; +} + +static void f2fs_get_ino_and_lblk_bits(struct super_block *sb, + int *ino_bits_ret, int *lblk_bits_ret) +{ + *ino_bits_ret = 8 * sizeof(nid_t); + *lblk_bits_ret = 8 * sizeof(block_t); +} + static const struct fscrypt_operations f2fs_cryptops = { - .key_prefix = "f2fs:", - .get_context = f2fs_get_context, - .set_context = f2fs_set_context, - .dummy_context = f2fs_dummy_context, - .empty_dir = f2fs_empty_dir, - .max_namelen = F2FS_NAME_LEN, + .key_prefix = "f2fs:", + .get_context = f2fs_get_context, + .set_context = f2fs_set_context, + .dummy_context = f2fs_dummy_context, + .empty_dir = f2fs_empty_dir, + .max_namelen = F2FS_NAME_LEN, + .has_stable_inodes = f2fs_has_stable_inodes, + .get_ino_and_lblk_bits = f2fs_get_ino_and_lblk_bits, }; #endif -- GitLab From 9cccb8da2cc7fa2152597e5897bbb3c244c80f36 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 30 Oct 2019 15:19:15 -0700 Subject: [PATCH 0008/1055] docs: fs-verity: document first supported kernel version I had meant to replace these TODOs with the actual version when applying the patches, but forgot to do so. Do it now. Signed-off-by: Eric Biggers --- Documentation/filesystems/fsverity.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/filesystems/fsverity.rst b/Documentation/filesystems/fsverity.rst index 42a0b6dd9e0b..dd55204c9ef8 100644 --- a/Documentation/filesystems/fsverity.rst +++ b/Documentation/filesystems/fsverity.rst @@ -398,7 +398,7 @@ pages have been read into the pagecache. (See `Verifying data`_.) ext4 ---- -ext4 supports fs-verity since Linux TODO and e2fsprogs v1.45.2. +ext4 supports fs-verity since Linux v5.4 and e2fsprogs v1.45.2. To create verity files on an ext4 filesystem, the filesystem must have been formatted with ``-O verity`` or had ``tune2fs -O verity`` run on @@ -434,7 +434,7 @@ also only supports extent-based files. f2fs ---- -f2fs supports fs-verity since Linux TODO and f2fs-tools v1.11.0. +f2fs supports fs-verity since Linux v5.4 and f2fs-tools v1.11.0. To create verity files on an f2fs filesystem, the filesystem must have been formatted with ``-O verity``. -- GitLab From b5f2f63e91693d8b4739c72aa20d240b3831b3bd Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 29 Oct 2019 13:41:38 -0700 Subject: [PATCH 0009/1055] statx: define STATX_ATTR_VERITY Add a statx attribute bit STATX_ATTR_VERITY which will be set if the file has fs-verity enabled. This is the statx() equivalent of FS_VERITY_FL which is returned by FS_IOC_GETFLAGS. This is useful because it allows applications to check whether a file is a verity file without opening it. Opening a verity file can be expensive because the fsverity_info is set up on open, which involves parsing metadata and optionally verifying a cryptographic signature. This is analogous to how various other bits are exposed through both FS_IOC_GETFLAGS and statx(), e.g. the encrypt bit. Reviewed-by: Andreas Dilger Acked-by: Darrick J. Wong Signed-off-by: Eric Biggers --- include/linux/stat.h | 3 ++- include/uapi/linux/stat.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/linux/stat.h b/include/linux/stat.h index 22484e44544d..07295841fccd 100644 --- a/include/linux/stat.h +++ b/include/linux/stat.h @@ -33,7 +33,8 @@ struct kstat { STATX_ATTR_IMMUTABLE | \ STATX_ATTR_APPEND | \ STATX_ATTR_NODUMP | \ - STATX_ATTR_ENCRYPTED \ + STATX_ATTR_ENCRYPTED | \ + STATX_ATTR_VERITY \ )/* Attrs corresponding to FS_*_FL flags */ u64 ino; dev_t dev; diff --git a/include/uapi/linux/stat.h b/include/uapi/linux/stat.h index 7b35e98d3c58..ad80a5c885d5 100644 --- a/include/uapi/linux/stat.h +++ b/include/uapi/linux/stat.h @@ -167,8 +167,8 @@ struct statx { #define STATX_ATTR_APPEND 0x00000020 /* [I] File is append-only */ #define STATX_ATTR_NODUMP 0x00000040 /* [I] File is not to be dumped */ #define STATX_ATTR_ENCRYPTED 0x00000800 /* [I] File requires key to decrypt in fs */ - #define STATX_ATTR_AUTOMOUNT 0x00001000 /* Dir: Automount trigger */ +#define STATX_ATTR_VERITY 0x00100000 /* [I] Verity protected file */ #endif /* _UAPI_LINUX_STAT_H */ -- GitLab From 0c17322429c1962edcac6d3703b0f7bf77ad1d64 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 29 Oct 2019 13:41:39 -0700 Subject: [PATCH 0010/1055] ext4: support STATX_ATTR_VERITY Set the STATX_ATTR_VERITY bit when the statx() system call is used on a verity file on ext4. Reviewed-by: Andreas Dilger Signed-off-by: Eric Biggers --- fs/ext4/inode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index a8b0cbc65655..4f2c73b52c83 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -5510,12 +5510,15 @@ int ext4_getattr(const struct path *path, struct kstat *stat, stat->attributes |= STATX_ATTR_IMMUTABLE; if (flags & EXT4_NODUMP_FL) stat->attributes |= STATX_ATTR_NODUMP; + if (flags & EXT4_VERITY_FL) + stat->attributes |= STATX_ATTR_VERITY; stat->attributes_mask |= (STATX_ATTR_APPEND | STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED | STATX_ATTR_IMMUTABLE | - STATX_ATTR_NODUMP); + STATX_ATTR_NODUMP | + STATX_ATTR_VERITY); generic_fillattr(inode, stat); return 0; -- GitLab From c4948febfddaee63b867427716794ebdc41a49b8 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 29 Oct 2019 13:41:40 -0700 Subject: [PATCH 0011/1055] f2fs: support STATX_ATTR_VERITY Set the STATX_ATTR_VERITY bit when the statx() system call is used on a verity file on f2fs. Signed-off-by: Eric Biggers --- fs/f2fs/file.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 70292386ed85..115763b0135c 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -725,11 +725,14 @@ int f2fs_getattr(const struct path *path, struct kstat *stat, stat->attributes |= STATX_ATTR_IMMUTABLE; if (flags & F2FS_NODUMP_FL) stat->attributes |= STATX_ATTR_NODUMP; + if (IS_VERITY(inode)) + stat->attributes |= STATX_ATTR_VERITY; stat->attributes_mask |= (STATX_ATTR_APPEND | STATX_ATTR_ENCRYPTED | STATX_ATTR_IMMUTABLE | - STATX_ATTR_NODUMP); + STATX_ATTR_NODUMP | + STATX_ATTR_VERITY); generic_fillattr(inode, stat); -- GitLab From 84648bc446073628e6659b4bab41fc5add71b301 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 29 Oct 2019 13:41:41 -0700 Subject: [PATCH 0012/1055] docs: fs-verity: mention statx() support Document that the statx() system call can now be used to check whether a file is a verity file. Signed-off-by: Eric Biggers --- Documentation/filesystems/fsverity.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/filesystems/fsverity.rst b/Documentation/filesystems/fsverity.rst index dd55204c9ef8..a95536b6443c 100644 --- a/Documentation/filesystems/fsverity.rst +++ b/Documentation/filesystems/fsverity.rst @@ -226,6 +226,14 @@ To do so, check for FS_VERITY_FL (0x00100000) in the returned flags. The verity flag is not settable via FS_IOC_SETFLAGS. You must use FS_IOC_ENABLE_VERITY instead, since parameters must be provided. +statx +----- + +Since Linux v5.5, the statx() system call sets STATX_ATTR_VERITY if +the file has fs-verity enabled. This can perform better than +FS_IOC_GETFLAGS and FS_IOC_MEASURE_VERITY because it doesn't require +opening the file, and opening verity files can be expensive. + Accessing verity files ====================== -- GitLab From 5f2d37a7252e86f5734defb2336d2278a8dc0d57 Mon Sep 17 00:00:00 2001 From: Ram Muthiah Date: Thu, 9 Jan 2020 14:53:34 -0800 Subject: [PATCH 0013/1055] ANDROID: cuttlefish_defconfig: remove 80211_HWSIM Fix to re-enable wifi on cf + kernel 4.14. Remove mac80211_hwsim virtual device on cuttlefish kernels as we want to use virt_wifi now instead. Test: Local boot with cuttlefish Bug: 145836345 Change-Id: Ifac04724afef7f5ad5aff46bae9c1ea0e77f892c Signed-off-by: Ram Muthiah --- arch/x86/configs/x86_64_cuttlefish_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index a21970185ddf..11e1f466ddd8 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -281,7 +281,6 @@ CONFIG_USB_USBNET=y # CONFIG_WLAN_VENDOR_TI is not set # CONFIG_WLAN_VENDOR_ZYDAS is not set # CONFIG_WLAN_VENDOR_QUANTENNA is not set -CONFIG_MAC80211_HWSIM=y CONFIG_VIRT_WIFI=y CONFIG_INPUT_MOUSEDEV=y CONFIG_INPUT_EVDEV=y -- GitLab From ca9689826312faeee13b0b5d78653658241b8c7d Mon Sep 17 00:00:00 2001 From: "Joel Fernandes (Google)" Date: Mon, 14 Oct 2019 13:03:08 -0400 Subject: [PATCH 0014/1055] BACKPORT: perf_event: Add support for LSM and SELinux checks In current mainline, the degree of access to perf_event_open(2) system call depends on the perf_event_paranoid sysctl. This has a number of limitations: 1. The sysctl is only a single value. Many types of accesses are controlled based on the single value thus making the control very limited and coarse grained. 2. The sysctl is global, so if the sysctl is changed, then that means all processes get access to perf_event_open(2) opening the door to security issues. This patch adds LSM and SELinux access checking which will be used in Android to access perf_event_open(2) for the purposes of attaching BPF programs to tracepoints, perf profiling and other operations from userspace. These operations are intended for production systems. 5 new LSM hooks are added: 1. perf_event_open: This controls access during the perf_event_open(2) syscall itself. The hook is called from all the places that the perf_event_paranoid sysctl is checked to keep it consistent with the systctl. The hook gets passed a 'type' argument which controls CPU, kernel and tracepoint accesses (in this context, CPU, kernel and tracepoint have the same semantics as the perf_event_paranoid sysctl). Additionally, I added an 'open' type which is similar to perf_event_paranoid sysctl == 3 patch carried in Android and several other distros but was rejected in mainline [1] in 2016. 2. perf_event_alloc: This allocates a new security object for the event which stores the current SID within the event. It will be useful when the perf event's FD is passed through IPC to another process which may try to read the FD. Appropriate security checks will limit access. 3. perf_event_free: Called when the event is closed. 4. perf_event_read: Called from the read(2) and mmap(2) syscalls for the event. 5. perf_event_write: Called from the ioctl(2) syscalls for the event. [1] https://lwn.net/Articles/696240/ Since Peter had suggest LSM hooks in 2016 [1], I am adding his Suggested-by tag below. To use this patch, we set the perf_event_paranoid sysctl to -1 and then apply selinux checking as appropriate (default deny everything, and then add policy rules to give access to domains that need it). In the future we can remove the perf_event_paranoid sysctl altogether. Suggested-by: Peter Zijlstra Co-developed-by: Peter Zijlstra Signed-off-by: Joel Fernandes (Google) Signed-off-by: Peter Zijlstra (Intel) Acked-by: James Morris Cc: Arnaldo Carvalho de Melo Cc: rostedt@goodmis.org Cc: Yonghong Song Cc: Kees Cook Cc: Ingo Molnar Cc: Alexei Starovoitov Cc: jeffv@google.com Cc: Jiri Olsa Cc: Daniel Borkmann Cc: primiano@google.com Cc: Song Liu Cc: rsavitski@google.com Cc: Namhyung Kim Cc: Matthew Garrett Link: https://lkml.kernel.org/r/20191014170308.70668-1-joel@joelfernandes.org (cherry picked from commit da97e18458fb42d7c00fac5fd1c56a3896ec666e) [ Ryan Savitski: adapted for older APIs, and folded in upstream ae79d5588a04 (perf/core: Fix !CONFIG_PERF_EVENTS build warnings and failures). This should fix the build errors from the previous backport attempt, where certain configurations would end up with functions referring to the perf_event struct prior to its declaration (and therefore declaring it with a different scope). ] Bug: 137092007 Change-Id: Iece194b3519dc5016ccbe127fc4e5c425ee7c442 Signed-off-by: Ryan Savitski --- arch/powerpc/perf/core-book3s.c | 15 +++---- arch/x86/events/intel/bts.c | 8 ++-- arch/x86/events/intel/core.c | 5 ++- arch/x86/events/intel/p4.c | 5 ++- include/linux/lsm_hooks.h | 15 +++++++ include/linux/perf_event.h | 36 ++++++++++++--- include/linux/security.h | 39 +++++++++++++++- kernel/events/core.c | 57 ++++++++++++++++++----- kernel/trace/trace_event_perf.c | 15 ++++--- security/security.c | 27 +++++++++++ security/selinux/hooks.c | 70 +++++++++++++++++++++++++++++ security/selinux/include/classmap.h | 2 + security/selinux/include/objsec.h | 6 ++- 13 files changed, 262 insertions(+), 38 deletions(-) diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 3188040022c4..1c37f08bcddd 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -95,7 +95,7 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs) { return 0; } -static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) { } +static inline void perf_get_data_addr(struct perf_event *event, struct pt_regs *regs, u64 *addrp) { } static inline u32 perf_get_misc_flags(struct pt_regs *regs) { return 0; @@ -126,7 +126,7 @@ static unsigned long ebb_switch_in(bool ebb, struct cpu_hw_events *cpuhw) static inline void power_pmu_bhrb_enable(struct perf_event *event) {} static inline void power_pmu_bhrb_disable(struct perf_event *event) {} static void power_pmu_sched_task(struct perf_event_context *ctx, bool sched_in) {} -static inline void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) {} +static inline void power_pmu_bhrb_read(struct perf_event *event, struct cpu_hw_events *cpuhw) {} static void pmao_restore_workaround(bool ebb) { } static bool use_ic(u64 event) { @@ -174,7 +174,7 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs) * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC, the * [POWER7P_]MMCRA_SDAR_VALID bit in MMCRA, or the SDAR_VALID bit in SIER. */ -static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) +static inline void perf_get_data_addr(struct perf_event *event, struct pt_regs *regs, u64 *addrp) { unsigned long mmcra = regs->dsisr; bool sdar_valid; @@ -435,7 +435,7 @@ static __u64 power_pmu_bhrb_to(u64 addr) } /* Processing BHRB entries */ -static void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) +static void power_pmu_bhrb_read(struct perf_event *event, struct cpu_hw_events *cpuhw) { u64 val; u64 addr; @@ -463,8 +463,7 @@ static void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) * exporting it to userspace (avoid exposure of regions * where we could have speculative execution) */ - if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN) && - is_kernel_addr(addr)) + if (is_kernel_addr(addr) && perf_allow_kernel(&event->attr) != 0) continue; /* Branches are read most recent first (ie. mfbhrb 0 is @@ -2077,12 +2076,12 @@ static void record_and_restart(struct perf_event *event, unsigned long val, if (event->attr.sample_type & (PERF_SAMPLE_ADDR | PERF_SAMPLE_PHYS_ADDR)) - perf_get_data_addr(regs, &data.addr); + perf_get_data_addr(event, regs, &data.addr); if (event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK) { struct cpu_hw_events *cpuhw; cpuhw = this_cpu_ptr(&cpu_hw_events); - power_pmu_bhrb_read(cpuhw); + power_pmu_bhrb_read(event, cpuhw); data.br_stack = &cpuhw->bhrb_stack; } diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c index 510f9461407e..5a1cd9c3addf 100644 --- a/arch/x86/events/intel/bts.c +++ b/arch/x86/events/intel/bts.c @@ -563,9 +563,11 @@ static int bts_event_init(struct perf_event *event) * Note that the default paranoia setting permits unprivileged * users to profile the kernel. */ - if (event->attr.exclude_kernel && perf_paranoid_kernel() && - !capable(CAP_SYS_ADMIN)) - return -EACCES; + if (event->attr.exclude_kernel) { + ret = perf_allow_kernel(&event->attr); + if (ret) + return ret; + } if (x86_add_exclusive(x86_lbr_exclusive_bts)) return -EBUSY; diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 4a60ed8c4413..0307e34d2272 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3087,8 +3087,9 @@ static int intel_pmu_hw_config(struct perf_event *event) if (x86_pmu.version < 3) return -EINVAL; - if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) - return -EACCES; + ret = perf_allow_cpu(&event->attr); + if (ret) + return ret; event->hw.config |= ARCH_PERFMON_EVENTSEL_ANY; diff --git a/arch/x86/events/intel/p4.c b/arch/x86/events/intel/p4.c index d32c0eed38ca..4f9ac72968db 100644 --- a/arch/x86/events/intel/p4.c +++ b/arch/x86/events/intel/p4.c @@ -776,8 +776,9 @@ static int p4_validate_raw_event(struct perf_event *event) * the user needs special permissions to be able to use it */ if (p4_ht_active() && p4_event_bind_map[v].shared) { - if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) - return -EACCES; + v = perf_allow_cpu(&event->attr); + if (v) + return v; } /* ESCR EventMask bits may be invalid */ diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 7161d8e7ee79..7e9f59aeadb6 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1727,6 +1727,14 @@ union security_list_options { int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux); void (*bpf_prog_free_security)(struct bpf_prog_aux *aux); #endif /* CONFIG_BPF_SYSCALL */ +#ifdef CONFIG_PERF_EVENTS + int (*perf_event_open)(struct perf_event_attr *attr, int type); + int (*perf_event_alloc)(struct perf_event *event); + void (*perf_event_free)(struct perf_event *event); + int (*perf_event_read)(struct perf_event *event); + int (*perf_event_write)(struct perf_event *event); + +#endif }; struct security_hook_heads { @@ -1955,6 +1963,13 @@ struct security_hook_heads { struct list_head bpf_prog_alloc_security; struct list_head bpf_prog_free_security; #endif /* CONFIG_BPF_SYSCALL */ +#ifdef CONFIG_PERF_EVENTS + struct list_head perf_event_open; + struct list_head perf_event_alloc; + struct list_head perf_event_free; + struct list_head perf_event_read; + struct list_head perf_event_write; +#endif } __randomize_layout; /* diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index ac16bac38c03..5d798eb5ac0a 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -54,6 +54,7 @@ struct perf_guest_info_callbacks { #include #include #include +#include #include struct perf_callchain_entry { @@ -712,6 +713,9 @@ struct perf_event { int cgrp_defer_enabled; #endif +#ifdef CONFIG_SECURITY + void *security; +#endif struct list_head sb_list; #endif /* CONFIG_PERF_EVENTS */ }; @@ -1175,24 +1179,46 @@ extern int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write, int perf_event_max_stack_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); +/* Access to perf_event_open(2) syscall. */ +#define PERF_SECURITY_OPEN 0 + +/* Finer grained perf_event_open(2) access control. */ +#define PERF_SECURITY_CPU 1 +#define PERF_SECURITY_KERNEL 2 +#define PERF_SECURITY_TRACEPOINT 3 + static inline bool perf_paranoid_any(void) { return sysctl_perf_event_paranoid > 2; } -static inline bool perf_paranoid_tracepoint_raw(void) +static inline int perf_is_paranoid(void) { return sysctl_perf_event_paranoid > -1; } -static inline bool perf_paranoid_cpu(void) +static inline int perf_allow_kernel(struct perf_event_attr *attr) { - return sysctl_perf_event_paranoid > 0; + if (sysctl_perf_event_paranoid > 1 && !capable(CAP_SYS_ADMIN)) + return -EACCES; + + return security_perf_event_open(attr, PERF_SECURITY_KERNEL); } -static inline bool perf_paranoid_kernel(void) +static inline int perf_allow_cpu(struct perf_event_attr *attr) { - return sysctl_perf_event_paranoid > 1; + if (sysctl_perf_event_paranoid > 0 && !capable(CAP_SYS_ADMIN)) + return -EACCES; + + return security_perf_event_open(attr, PERF_SECURITY_CPU); +} + +static inline int perf_allow_tracepoint(struct perf_event_attr *attr) +{ + if (sysctl_perf_event_paranoid > -1 && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + return security_perf_event_open(attr, PERF_SECURITY_TRACEPOINT); } extern void perf_event_init(void); diff --git a/include/linux/security.h b/include/linux/security.h index 73f1ef625d40..666c75c2269c 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1801,5 +1801,42 @@ static inline void free_secdata(void *secdata) { } #endif /* CONFIG_SECURITY */ -#endif /* ! __LINUX_SECURITY_H */ +#ifdef CONFIG_PERF_EVENTS +struct perf_event_attr; +struct perf_event; + +#ifdef CONFIG_SECURITY +extern int security_perf_event_open(struct perf_event_attr *attr, int type); +extern int security_perf_event_alloc(struct perf_event *event); +extern void security_perf_event_free(struct perf_event *event); +extern int security_perf_event_read(struct perf_event *event); +extern int security_perf_event_write(struct perf_event *event); +#else +static inline int security_perf_event_open(struct perf_event_attr *attr, + int type) +{ + return 0; +} + +static inline int security_perf_event_alloc(struct perf_event *event) +{ + return 0; +} + +static inline void security_perf_event_free(struct perf_event *event) +{ +} + +static inline int security_perf_event_read(struct perf_event *event) +{ + return 0; +} +static inline int security_perf_event_write(struct perf_event *event) +{ + return 0; +} +#endif /* CONFIG_SECURITY */ +#endif /* CONFIG_PERF_EVENTS */ + +#endif /* ! __LINUX_SECURITY_H */ diff --git a/kernel/events/core.c b/kernel/events/core.c index f87d54270076..e24e2d558cbc 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3912,8 +3912,9 @@ find_get_context(struct pmu *pmu, struct task_struct *task, if (!task) { /* Must be root to operate on a CPU event: */ - if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) - return ERR_PTR(-EACCES); + err = perf_allow_cpu(&event->attr); + if (err) + return ERR_PTR(err); cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); ctx = &cpuctx->ctx; @@ -4216,6 +4217,8 @@ static void _free_event(struct perf_event *event) unaccount_event(event); + security_perf_event_free(event); + if (event->rb) { /* * Can happen when we close an event with re-directed output. @@ -4635,6 +4638,10 @@ perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) struct perf_event_context *ctx; int ret; + ret = security_perf_event_read(event); + if (ret) + return ret; + ctx = perf_event_ctx_lock(event); ret = __perf_read(event, buf, count); perf_event_ctx_unlock(event, ctx); @@ -4880,6 +4887,11 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct perf_event_context *ctx; long ret; + /* Treat ioctl like writes as it is likely a mutating operation. */ + ret = security_perf_event_write(event); + if (ret) + return ret; + ctx = perf_event_ctx_lock(event); ret = _perf_ioctl(event, cmd, arg); perf_event_ctx_unlock(event, ctx); @@ -5340,6 +5352,10 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; + ret = security_perf_event_read(event); + if (ret) + return ret; + vma_size = vma->vm_end - vma->vm_start; if (vma->vm_pgoff == 0) { @@ -5453,7 +5469,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) lock_limit >>= PAGE_SHIFT; locked = vma->vm_mm->pinned_vm + extra; - if ((locked > lock_limit) && perf_paranoid_tracepoint_raw() && + if ((locked > lock_limit) && perf_is_paranoid() && !capable(CAP_IPC_LOCK)) { ret = -EPERM; goto unlock; @@ -9693,11 +9709,20 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, } } + err = security_perf_event_alloc(event); + if (err) + goto err_callchain_buffer; + /* symmetric to unaccount_event() in _free_event() */ account_event(event); return event; +err_callchain_buffer: + if (!event->parent) { + if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) + put_callchain_buffers(); + } err_addr_filters: kfree(event->addr_filter_ranges); @@ -9815,9 +9840,11 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr, attr->branch_sample_type = mask; } /* privileged levels capture (kernel, hv): check permissions */ - if ((mask & PERF_SAMPLE_BRANCH_PERM_PLM) - && perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) - return -EACCES; + if (mask & PERF_SAMPLE_BRANCH_PERM_PLM) { + ret = perf_allow_kernel(attr); + if (ret) + return ret; + } } if (attr->sample_type & PERF_SAMPLE_REGS_USER) { @@ -10030,13 +10057,19 @@ SYSCALL_DEFINE5(perf_event_open, if (perf_paranoid_any() && !capable(CAP_SYS_ADMIN)) return -EACCES; + /* Do we allow access to perf_event_open(2) ? */ + err = security_perf_event_open(&attr, PERF_SECURITY_OPEN); + if (err) + return err; + err = perf_copy_attr(attr_uptr, &attr); if (err) return err; if (!attr.exclude_kernel) { - if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) - return -EACCES; + err = perf_allow_kernel(&attr); + if (err) + return err; } if (attr.namespaces) { @@ -10053,9 +10086,11 @@ SYSCALL_DEFINE5(perf_event_open, } /* Only privileged users can get physical addresses */ - if ((attr.sample_type & PERF_SAMPLE_PHYS_ADDR) && - perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) - return -EACCES; + if ((attr.sample_type & PERF_SAMPLE_PHYS_ADDR)) { + err = perf_allow_kernel(&attr); + if (err) + return err; + } if (!attr.sample_max_stack) attr.sample_max_stack = sysctl_perf_event_max_stack; diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 13ba2d3f6a91..80b7b194c181 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -7,6 +7,7 @@ #include #include +#include #include "trace.h" static char __percpu *perf_trace_buf[PERF_NR_CONTEXTS]; @@ -24,8 +25,10 @@ static int total_ref_count; static int perf_trace_event_perm(struct trace_event_call *tp_event, struct perf_event *p_event) { + int ret; + if (tp_event->perf_perm) { - int ret = tp_event->perf_perm(tp_event, p_event); + ret = tp_event->perf_perm(tp_event, p_event); if (ret) return ret; } @@ -44,8 +47,9 @@ static int perf_trace_event_perm(struct trace_event_call *tp_event, /* The ftrace function trace is allowed only for root. */ if (ftrace_event_is_function(tp_event)) { - if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) - return -EPERM; + ret = perf_allow_tracepoint(&p_event->attr); + if (ret) + return ret; if (!is_sampling_event(p_event)) return 0; @@ -80,8 +84,9 @@ static int perf_trace_event_perm(struct trace_event_call *tp_event, * ...otherwise raw tracepoint data can be a severe data leak, * only allow root to have these. */ - if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) - return -EPERM; + ret = perf_allow_tracepoint(&p_event->attr); + if (ret) + return ret; return 0; } diff --git a/security/security.c b/security/security.c index fb4910f0d0e2..5afd1dc81511 100644 --- a/security/security.c +++ b/security/security.c @@ -1745,3 +1745,30 @@ void security_bpf_prog_free(struct bpf_prog_aux *aux) call_void_hook(bpf_prog_free_security, aux); } #endif /* CONFIG_BPF_SYSCALL */ + +#ifdef CONFIG_PERF_EVENTS +int security_perf_event_open(struct perf_event_attr *attr, int type) +{ + return call_int_hook(perf_event_open, 0, attr, type); +} + +int security_perf_event_alloc(struct perf_event *event) +{ + return call_int_hook(perf_event_alloc, 0, event); +} + +void security_perf_event_free(struct perf_event *event) +{ + call_void_hook(perf_event_free, event); +} + +int security_perf_event_read(struct perf_event *event) +{ + return call_int_hook(perf_event_read, 0, event); +} + +int security_perf_event_write(struct perf_event *event) +{ + return call_int_hook(perf_event_write, 0, event); +} +#endif /* CONFIG_PERF_EVENTS */ diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3c017acc3a92..2595465dcd3b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6620,6 +6620,68 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) } #endif + +#ifdef CONFIG_PERF_EVENTS +static int selinux_perf_event_open(struct perf_event_attr *attr, int type) +{ + u32 requested, sid = current_sid(); + + if (type == PERF_SECURITY_OPEN) + requested = PERF_EVENT__OPEN; + else if (type == PERF_SECURITY_CPU) + requested = PERF_EVENT__CPU; + else if (type == PERF_SECURITY_KERNEL) + requested = PERF_EVENT__KERNEL; + else if (type == PERF_SECURITY_TRACEPOINT) + requested = PERF_EVENT__TRACEPOINT; + else + return -EINVAL; + + return avc_has_perm(&selinux_state, sid, sid, SECCLASS_PERF_EVENT, + requested, NULL); +} + +static int selinux_perf_event_alloc(struct perf_event *event) +{ + struct perf_event_security_struct *perfsec; + + perfsec = kzalloc(sizeof(*perfsec), GFP_KERNEL); + if (!perfsec) + return -ENOMEM; + + perfsec->sid = current_sid(); + event->security = perfsec; + + return 0; +} + +static void selinux_perf_event_free(struct perf_event *event) +{ + struct perf_event_security_struct *perfsec = event->security; + + event->security = NULL; + kfree(perfsec); +} + +static int selinux_perf_event_read(struct perf_event *event) +{ + struct perf_event_security_struct *perfsec = event->security; + u32 sid = current_sid(); + + return avc_has_perm(&selinux_state, sid, perfsec->sid, + SECCLASS_PERF_EVENT, PERF_EVENT__READ, NULL); +} + +static int selinux_perf_event_write(struct perf_event *event) +{ + struct perf_event_security_struct *perfsec = event->security; + u32 sid = current_sid(); + + return avc_has_perm(&selinux_state, sid, perfsec->sid, + SECCLASS_PERF_EVENT, PERF_EVENT__WRITE, NULL); +} +#endif + static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), @@ -6849,6 +6911,14 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free), LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free), #endif + +#ifdef CONFIG_PERF_EVENTS + LSM_HOOK_INIT(perf_event_open, selinux_perf_event_open), + LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc), + LSM_HOOK_INIT(perf_event_free, selinux_perf_event_free), + LSM_HOOK_INIT(perf_event_read, selinux_perf_event_read), + LSM_HOOK_INIT(perf_event_write, selinux_perf_event_write), +#endif }; static __init int selinux_init(void) diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 5ae315ab060b..000effa857aa 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -241,6 +241,8 @@ struct security_class_mapping secclass_map[] = { { "manage_subnet", NULL } }, { "bpf", {"map_create", "map_read", "map_write", "prog_load", "prog_run"} }, + { "perf_event", + {"open", "cpu", "kernel", "tracepoint", "read", "write"} }, { NULL } }; diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 18b3fe02b44c..512908b55ca3 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -151,7 +151,11 @@ struct pkey_security_struct { }; struct bpf_security_struct { - u32 sid; /*SID of bpf obj creater*/ + u32 sid; /* SID of bpf obj creator */ +}; + +struct perf_event_security_struct { + u32 sid; /* SID of perf_event obj creator */ }; #endif /* _SELINUX_OBJSEC_H_ */ -- GitLab From d9d60cd6fc5cccaf639f96bc0921150c9c7589cf Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 26 Sep 2017 15:16:05 -0400 Subject: [PATCH 0015/1055] UPSTREAM: USB: dummy-hcd: bandwidth limits for non-bulk transfers (Upstream commit ffc4ea79bc06f42283da10ea06bb17b9a3e2b2b4.) Part of the emulation performed by dummy-hcd is accounting for bandwidth utilization. The total amount of data transferred in a single frame is supposed to be no larger than an actual USB connection could accommodate. Currently the driver performs bandwidth limiting only for bulk transfers; control and periodic transfers are effectively unlimited. (Presumably drivers were not expected to request extremely large control or interrupt transfers.) This patch improves the situation somewhat by restricting them as well. The emulation still isn't perfect. On a real system, even 0-length transfers use some bandwidth because of transaction overhead (IN, OUT, ACK, NACK packets) and packet overhead (SYNC, PID, bit stuffing, CRC, EOP). Adding in those factors is left as an exercise for a later patch. Signed-off-by: Alan Stern Signed-off-by: Felipe Balbi Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: Ib3bbaf9868a76dba2795042abb0f063099f9fc98 --- drivers/usb/gadget/udc/dummy_hcd.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 7e90f786d923..1336cadfdb5d 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -1770,6 +1770,7 @@ static void dummy_timer(unsigned long _dum_hcd) int i; /* simplistic model for one frame's bandwidth */ + /* FIXME: account for transaction and packet overhead */ switch (dum->gadget.speed) { case USB_SPEED_LOW: total = 8/*bytes*/ * 12/*packets*/; @@ -1814,7 +1815,6 @@ static void dummy_timer(unsigned long _dum_hcd) struct dummy_request *req; u8 address; struct dummy_ep *ep = NULL; - int type; int status = -EINPROGRESS; /* stop when we reach URBs queued after the timer interrupt */ @@ -1826,14 +1826,10 @@ static void dummy_timer(unsigned long _dum_hcd) goto return_urb; else if (dum_hcd->rh_state != DUMMY_RH_RUNNING) continue; - type = usb_pipetype(urb->pipe); - /* used up this frame's non-periodic bandwidth? - * FIXME there's infinite bandwidth for control and - * periodic transfers ... unrealistic. - */ - if (total <= 0 && type == PIPE_BULK) - continue; + /* Used up this frame's bandwidth? */ + if (total <= 0) + break; /* find the gadget's ep for this request (if configured) */ address = usb_pipeendpoint (urb->pipe); -- GitLab From 30b987d1afb40e6f3662ed602cd25d6c1d1080ad Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 18 Apr 2019 13:12:07 -0400 Subject: [PATCH 0016/1055] UPSTREAM: USB: dummy-hcd: Fix failure to give back unlinked URBs (Upstream commit 50896c410354432e8e7baf97fcdd7df265e683ae.) The syzkaller USB fuzzer identified a failure mode in which dummy-hcd would never give back an unlinked URB. This causes usb_kill_urb() to hang, leading to WARNINGs and unkillable threads. In dummy-hcd, all URBs are given back by the dummy_timer() routine as it scans through the list of pending URBS. Failure to give back URBs can be caused by failure to start or early exit from the scanning loop. The code currently has two such pathways: One is triggered when an unsupported bus transfer speed is encountered, and the other by exhausting the simulated bandwidth for USB transfers during a frame. This patch removes those two paths, thereby allowing all unlinked URBs to be given back in a timely manner. It adds a check for the bus speed when the gadget first starts running, so that dummy_timer() will never thereafter encounter an unsupported speed. And it prevents the loop from exiting as soon as the total bandwidth has been used up (the scanning loop continues, giving back unlinked URBs as they are found, but not transferring any more data). Thanks to Andrey Konovalov for manually running the syzkaller fuzzer to help track down the source of the bug. Signed-off-by: Alan Stern Reported-and-tested-by: syzbot+d919b0f29d7b5a4994b9@syzkaller.appspotmail.com CC: Signed-off-by: Felipe Balbi Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: I67f054e708130e1c7f252395bc560d6ec0760b24 --- drivers/usb/gadget/udc/dummy_hcd.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 1336cadfdb5d..f29b5b0bb0dc 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -980,8 +980,18 @@ static int dummy_udc_start(struct usb_gadget *g, struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); struct dummy *dum = dum_hcd->dum; - if (driver->max_speed == USB_SPEED_UNKNOWN) + switch (g->speed) { + /* All the speeds we support */ + case USB_SPEED_LOW: + case USB_SPEED_FULL: + case USB_SPEED_HIGH: + case USB_SPEED_SUPER: + break; + default: + dev_err(dummy_dev(dum_hcd), "Unsupported driver max speed %d\n", + driver->max_speed); return -EINVAL; + } /* * SLAVE side init ... the layer above hardware, which @@ -1785,9 +1795,10 @@ static void dummy_timer(unsigned long _dum_hcd) /* Bus speed is 500000 bytes/ms, so use a little less */ total = 490000; break; - default: + default: /* Can't happen */ dev_err(dummy_dev(dum_hcd), "bogus device speed\n"); - return; + total = 0; + break; } /* FIXME if HZ != 1000 this will probably misbehave ... */ @@ -1829,7 +1840,7 @@ static void dummy_timer(unsigned long _dum_hcd) /* Used up this frame's bandwidth? */ if (total <= 0) - break; + continue; /* find the gadget's ep for this request (if configured) */ address = usb_pipeendpoint (urb->pipe); -- GitLab From e7da360e27600d547ee57a6561b701b912b68a14 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Mon, 21 Oct 2019 16:20:58 +0200 Subject: [PATCH 0017/1055] UPSTREAM: USB: dummy-hcd: increase max number of devices to 32 (Upstream commit 8442b02bf3c6770e0d7e7ea17be36c30e95987b6.) When fuzzing the USB subsystem with syzkaller, we currently use 8 testing processes within one VM. To isolate testing processes from one another it is desirable to assign a dedicated USB bus to each of those, which means we need at least 8 Dummy UDC/HCD devices. This patch increases the maximum number of Dummy UDC/HCD devices to 32 (more than 8 in case we need more of them in the future). Signed-off-by: Andrey Konovalov Link: https://lore.kernel.org/r/665578f904484069bb6100fb20283b22a046ad9b.1571667489.git.andreyknvl@google.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: I09d161f22c639b5b4864d38dcff2c967019b2e7c --- drivers/usb/gadget/udc/dummy_hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index f29b5b0bb0dc..4e002e650be1 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -2741,7 +2741,7 @@ static struct platform_driver dummy_hcd_driver = { }; /*-------------------------------------------------------------------------*/ -#define MAX_NUM_UDC 2 +#define MAX_NUM_UDC 32 static struct platform_device *the_udc_pdev[MAX_NUM_UDC]; static struct platform_device *the_hcd_pdev[MAX_NUM_UDC]; -- GitLab From 6bdf711ca1ab2423f04d6372e6061595f738144f Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Mon, 21 Oct 2019 16:20:59 +0200 Subject: [PATCH 0018/1055] UPSTREAM: USB: dummy-hcd: use usb_urb_dir_in instead of usb_pipein (Upstream commit 6dabeb891c001c592645df2f477fed9f5d959987.) Commit fea3409112a9 ("USB: add direction bit to urb->transfer_flags") has added a usb_urb_dir_in() helper function that can be used to determine the direction of the URB. With that patch USB_DIR_IN control requests with wLength == 0 are considered out requests by real USB HCDs. This patch changes dummy-hcd to use the usb_urb_dir_in() helper to match that behavior. Signed-off-by: Andrey Konovalov Link: https://lore.kernel.org/r/4ae9e68ebca02f08a93ac61fe065057c9a01f0a8.1571667489.git.andreyknvl@google.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: Ia6397c15219ec53c753ce0e843603628968fc906 --- drivers/usb/gadget/udc/dummy_hcd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 4e002e650be1..8ee76524a0b7 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -1335,7 +1335,7 @@ static int dummy_perform_transfer(struct urb *urb, struct dummy_request *req, u32 this_sg; bool next_sg; - to_host = usb_pipein(urb->pipe); + to_host = usb_urb_dir_in(urb); rbuf = req->req.buf + req->req.actual; if (!urb->num_sgs) { @@ -1423,7 +1423,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, /* FIXME update emulated data toggle too */ - to_host = usb_pipein(urb->pipe); + to_host = usb_urb_dir_in(urb); if (unlikely(len == 0)) is_short = 1; else { @@ -1844,7 +1844,7 @@ static void dummy_timer(unsigned long _dum_hcd) /* find the gadget's ep for this request (if configured) */ address = usb_pipeendpoint (urb->pipe); - if (usb_pipein(urb->pipe)) + if (usb_urb_dir_in(urb)) address |= USB_DIR_IN; ep = find_endpoint(dum, address); if (!ep) { @@ -2397,7 +2397,7 @@ static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb) s = "?"; break; } s; }), - ep, ep ? (usb_pipein(urb->pipe) ? "in" : "out") : "", + ep, ep ? (usb_urb_dir_in(urb) ? "in" : "out") : "", ({ char *s; \ switch (usb_pipetype(urb->pipe)) { \ case PIPE_CONTROL: \ -- GitLab From 65c0bbac0a29de4356e814a0fed838cb4484364c Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Mon, 21 Oct 2019 16:20:59 +0200 Subject: [PATCH 0019/1055] USB: dummy-hcd: use usb_urb_dir_in instead of usb_pipein commit 6dabeb891c001c592645df2f477fed9f5d959987 upstream. Commit fea3409112a9 ("USB: add direction bit to urb->transfer_flags") has added a usb_urb_dir_in() helper function that can be used to determine the direction of the URB. With that patch USB_DIR_IN control requests with wLength == 0 are considered out requests by real USB HCDs. This patch changes dummy-hcd to use the usb_urb_dir_in() helper to match that behavior. Signed-off-by: Andrey Konovalov Link: https://lore.kernel.org/r/4ae9e68ebca02f08a93ac61fe065057c9a01f0a8.1571667489.git.andreyknvl@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/dummy_hcd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 7e90f786d923..8218a5845ed0 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -1325,7 +1325,7 @@ static int dummy_perform_transfer(struct urb *urb, struct dummy_request *req, u32 this_sg; bool next_sg; - to_host = usb_pipein(urb->pipe); + to_host = usb_urb_dir_in(urb); rbuf = req->req.buf + req->req.actual; if (!urb->num_sgs) { @@ -1413,7 +1413,7 @@ static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, /* FIXME update emulated data toggle too */ - to_host = usb_pipein(urb->pipe); + to_host = usb_urb_dir_in(urb); if (unlikely(len == 0)) is_short = 1; else { @@ -1837,7 +1837,7 @@ static void dummy_timer(unsigned long _dum_hcd) /* find the gadget's ep for this request (if configured) */ address = usb_pipeendpoint (urb->pipe); - if (usb_pipein(urb->pipe)) + if (usb_urb_dir_in(urb)) address |= USB_DIR_IN; ep = find_endpoint(dum, address); if (!ep) { @@ -2390,7 +2390,7 @@ static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb) s = "?"; break; } s; }), - ep, ep ? (usb_pipein(urb->pipe) ? "in" : "out") : "", + ep, ep ? (usb_urb_dir_in(urb) ? "in" : "out") : "", ({ char *s; \ switch (usb_pipetype(urb->pipe)) { \ case PIPE_CONTROL: \ -- GitLab From f0e24d683636a9193a2adcc928b78ba74bd46f1a Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Mon, 21 Oct 2019 16:20:58 +0200 Subject: [PATCH 0020/1055] USB: dummy-hcd: increase max number of devices to 32 commit 8442b02bf3c6770e0d7e7ea17be36c30e95987b6 upstream. When fuzzing the USB subsystem with syzkaller, we currently use 8 testing processes within one VM. To isolate testing processes from one another it is desirable to assign a dedicated USB bus to each of those, which means we need at least 8 Dummy UDC/HCD devices. This patch increases the maximum number of Dummy UDC/HCD devices to 32 (more than 8 in case we need more of them in the future). Signed-off-by: Andrey Konovalov Link: https://lore.kernel.org/r/665578f904484069bb6100fb20283b22a046ad9b.1571667489.git.andreyknvl@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/dummy_hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 8218a5845ed0..a0c1d77a7e38 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -2734,7 +2734,7 @@ static struct platform_driver dummy_hcd_driver = { }; /*-------------------------------------------------------------------------*/ -#define MAX_NUM_UDC 2 +#define MAX_NUM_UDC 32 static struct platform_device *the_udc_pdev[MAX_NUM_UDC]; static struct platform_device *the_hcd_pdev[MAX_NUM_UDC]; -- GitLab From 09226e5c38639437565af01e6009a9286a351d04 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Wed, 20 Nov 2019 16:57:15 +0100 Subject: [PATCH 0021/1055] locking/spinlock/debug: Fix various data races [ Upstream commit 1a365e822372ba24c9da0822bc583894f6f3d821 ] This fixes various data races in spinlock_debug. By testing with KCSAN, it is observable that the console gets spammed with data races reports, suggesting these are extremely frequent. Example data race report: read to 0xffff8ab24f403c48 of 4 bytes by task 221 on cpu 2: debug_spin_lock_before kernel/locking/spinlock_debug.c:85 [inline] do_raw_spin_lock+0x9b/0x210 kernel/locking/spinlock_debug.c:112 __raw_spin_lock include/linux/spinlock_api_smp.h:143 [inline] _raw_spin_lock+0x39/0x40 kernel/locking/spinlock.c:151 spin_lock include/linux/spinlock.h:338 [inline] get_partial_node.isra.0.part.0+0x32/0x2f0 mm/slub.c:1873 get_partial_node mm/slub.c:1870 [inline] write to 0xffff8ab24f403c48 of 4 bytes by task 167 on cpu 3: debug_spin_unlock kernel/locking/spinlock_debug.c:103 [inline] do_raw_spin_unlock+0xc9/0x1a0 kernel/locking/spinlock_debug.c:138 __raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h:159 [inline] _raw_spin_unlock_irqrestore+0x2d/0x50 kernel/locking/spinlock.c:191 spin_unlock_irqrestore include/linux/spinlock.h:393 [inline] free_debug_processing+0x1b3/0x210 mm/slub.c:1214 __slab_free+0x292/0x400 mm/slub.c:2864 As a side-effect, with KCSAN, this eventually locks up the console, most likely due to deadlock, e.g. .. -> printk lock -> spinlock_debug -> KCSAN detects data race -> kcsan_print_report() -> printk lock -> deadlock. This fix will 1) avoid the data races, and 2) allow using lock debugging together with KCSAN. Reported-by: Qian Cai Signed-off-by: Marco Elver 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/20191120155715.28089-1-elver@google.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin --- kernel/locking/spinlock_debug.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/kernel/locking/spinlock_debug.c b/kernel/locking/spinlock_debug.c index 9aa0fccd5d43..03595c29c566 100644 --- a/kernel/locking/spinlock_debug.c +++ b/kernel/locking/spinlock_debug.c @@ -51,19 +51,19 @@ EXPORT_SYMBOL(__rwlock_init); static void spin_dump(raw_spinlock_t *lock, const char *msg) { - struct task_struct *owner = NULL; + struct task_struct *owner = READ_ONCE(lock->owner); - if (lock->owner && lock->owner != SPINLOCK_OWNER_INIT) - owner = lock->owner; + if (owner == SPINLOCK_OWNER_INIT) + owner = NULL; printk(KERN_EMERG "BUG: spinlock %s on CPU#%d, %s/%d\n", msg, raw_smp_processor_id(), current->comm, task_pid_nr(current)); printk(KERN_EMERG " lock: %pS, .magic: %08x, .owner: %s/%d, " ".owner_cpu: %d\n", - lock, lock->magic, + lock, READ_ONCE(lock->magic), owner ? owner->comm : "", owner ? task_pid_nr(owner) : -1, - lock->owner_cpu); + READ_ONCE(lock->owner_cpu)); dump_stack(); } @@ -80,16 +80,16 @@ static void spin_bug(raw_spinlock_t *lock, const char *msg) static inline void debug_spin_lock_before(raw_spinlock_t *lock) { - SPIN_BUG_ON(lock->magic != SPINLOCK_MAGIC, lock, "bad magic"); - SPIN_BUG_ON(lock->owner == current, lock, "recursion"); - SPIN_BUG_ON(lock->owner_cpu == raw_smp_processor_id(), + SPIN_BUG_ON(READ_ONCE(lock->magic) != SPINLOCK_MAGIC, lock, "bad magic"); + SPIN_BUG_ON(READ_ONCE(lock->owner) == current, lock, "recursion"); + SPIN_BUG_ON(READ_ONCE(lock->owner_cpu) == raw_smp_processor_id(), lock, "cpu recursion"); } static inline void debug_spin_lock_after(raw_spinlock_t *lock) { - lock->owner_cpu = raw_smp_processor_id(); - lock->owner = current; + WRITE_ONCE(lock->owner_cpu, raw_smp_processor_id()); + WRITE_ONCE(lock->owner, current); } static inline void debug_spin_unlock(raw_spinlock_t *lock) @@ -99,8 +99,8 @@ static inline void debug_spin_unlock(raw_spinlock_t *lock) SPIN_BUG_ON(lock->owner != current, lock, "wrong owner"); SPIN_BUG_ON(lock->owner_cpu != raw_smp_processor_id(), lock, "wrong CPU"); - lock->owner = SPINLOCK_OWNER_INIT; - lock->owner_cpu = -1; + WRITE_ONCE(lock->owner, SPINLOCK_OWNER_INIT); + WRITE_ONCE(lock->owner_cpu, -1); } /* @@ -183,8 +183,8 @@ static inline void debug_write_lock_before(rwlock_t *lock) static inline void debug_write_lock_after(rwlock_t *lock) { - lock->owner_cpu = raw_smp_processor_id(); - lock->owner = current; + WRITE_ONCE(lock->owner_cpu, raw_smp_processor_id()); + WRITE_ONCE(lock->owner, current); } static inline void debug_write_unlock(rwlock_t *lock) @@ -193,8 +193,8 @@ static inline void debug_write_unlock(rwlock_t *lock) RWLOCK_BUG_ON(lock->owner != current, lock, "wrong owner"); RWLOCK_BUG_ON(lock->owner_cpu != raw_smp_processor_id(), lock, "wrong CPU"); - lock->owner = SPINLOCK_OWNER_INIT; - lock->owner_cpu = -1; + WRITE_ONCE(lock->owner, SPINLOCK_OWNER_INIT); + WRITE_ONCE(lock->owner_cpu, -1); } void do_raw_write_lock(rwlock_t *lock) -- GitLab From d74adafded9ceb57fca7012ae1e24d512dd8dcb6 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 15 Nov 2019 12:39:23 +0100 Subject: [PATCH 0022/1055] netfilter: ctnetlink: netns exit must wait for callbacks [ Upstream commit 18a110b022a5c02e7dc9f6109d0bd93e58ac6ebb ] Curtis Taylor and Jon Maxwell reported and debugged a crash on 3.10 based kernel. Crash occurs in ctnetlink_conntrack_events because net->nfnl socket is NULL. The nfnl socket was set to NULL by netns destruction running on another cpu. The exiting network namespace calls the relevant destructors in the following order: 1. ctnetlink_net_exit_batch This nulls out the event callback pointer in struct netns. 2. nfnetlink_net_exit_batch This nulls net->nfnl socket and frees it. 3. nf_conntrack_cleanup_net_list This removes all remaining conntrack entries. This is order is correct. The only explanation for the crash so ar is: cpu1: conntrack is dying, eviction occurs: -> nf_ct_delete() -> nf_conntrack_event_report \ -> nf_conntrack_eventmask_report -> notify->fcn() (== ctnetlink_conntrack_events). cpu1: a. fetches rcu protected pointer to obtain ctnetlink event callback. b. gets interrupted. cpu2: runs netns exit handlers: a runs ctnetlink destructor, event cb pointer set to NULL. b runs nfnetlink destructor, nfnl socket is closed and set to NULL. cpu1: c. resumes and trips over NULL net->nfnl. Problem appears to be that ctnetlink_net_exit_batch only prevents future callers of nf_conntrack_eventmask_report() from obtaining the callback. It doesn't wait of other cpus that might have already obtained the callbacks address. I don't see anything in upstream kernels that would prevent similar crash: We need to wait for all cpus to have exited the event callback. Fixes: 9592a5c01e79dbc59eb56fa ("netfilter: ctnetlink: netns support") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/netfilter/nf_conntrack_netlink.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index c781c9a1a697..39a32edaa92c 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -3422,6 +3422,9 @@ static void __net_exit ctnetlink_net_exit_batch(struct list_head *net_exit_list) list_for_each_entry(net, net_exit_list, exit_list) ctnetlink_net_exit(net); + + /* wait for other cpus until they are done with ctnl_notifiers */ + synchronize_rcu(); } static struct pernet_operations ctnetlink_net_ops = { -- GitLab From ec3bb975c6013aa2f5e8a96a0bee2c8d39618e89 Mon Sep 17 00:00:00 2001 From: qize wang Date: Fri, 29 Nov 2019 18:10:54 +0800 Subject: [PATCH 0023/1055] mwifiex: Fix heap overflow in mmwifiex_process_tdls_action_frame() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 1e58252e334dc3f3756f424a157d1b7484464c40 ] mwifiex_process_tdls_action_frame() without checking the incoming tdls infomation element's vality before use it, this may cause multi heap buffer overflows. Fix them by putting vality check before use it. IE is TLV struct, but ht_cap and ht_oper aren’t TLV struct. the origin marvell driver code is wrong: memcpy(&sta_ptr->tdls_cap.ht_oper, pos,.... memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos,... Fix the bug by changing pos(the address of IE) to pos+2 ( the address of IE value ). Signed-off-by: qize wang Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin --- drivers/net/wireless/marvell/mwifiex/tdls.c | 70 +++++++++++++++++++-- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c index e76af2866a19..b5340af9fa5e 100644 --- a/drivers/net/wireless/marvell/mwifiex/tdls.c +++ b/drivers/net/wireless/marvell/mwifiex/tdls.c @@ -956,59 +956,117 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv, switch (*pos) { case WLAN_EID_SUPP_RATES: + if (pos[1] > 32) + return; sta_ptr->tdls_cap.rates_len = pos[1]; for (i = 0; i < pos[1]; i++) sta_ptr->tdls_cap.rates[i] = pos[i + 2]; break; case WLAN_EID_EXT_SUPP_RATES: + if (pos[1] > 32) + return; basic = sta_ptr->tdls_cap.rates_len; + if (pos[1] > 32 - basic) + return; for (i = 0; i < pos[1]; i++) sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2]; sta_ptr->tdls_cap.rates_len += pos[1]; break; case WLAN_EID_HT_CAPABILITY: - memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos, + if (pos > end - sizeof(struct ieee80211_ht_cap) - 2) + return; + if (pos[1] != sizeof(struct ieee80211_ht_cap)) + return; + /* copy the ie's value into ht_capb*/ + memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos + 2, sizeof(struct ieee80211_ht_cap)); sta_ptr->is_11n_enabled = 1; break; case WLAN_EID_HT_OPERATION: - memcpy(&sta_ptr->tdls_cap.ht_oper, pos, + if (pos > end - + sizeof(struct ieee80211_ht_operation) - 2) + return; + if (pos[1] != sizeof(struct ieee80211_ht_operation)) + return; + /* copy the ie's value into ht_oper*/ + memcpy(&sta_ptr->tdls_cap.ht_oper, pos + 2, sizeof(struct ieee80211_ht_operation)); break; case WLAN_EID_BSS_COEX_2040: + if (pos > end - 3) + return; + if (pos[1] != 1) + return; sta_ptr->tdls_cap.coex_2040 = pos[2]; break; case WLAN_EID_EXT_CAPABILITY: + if (pos > end - sizeof(struct ieee_types_header)) + return; + if (pos[1] < sizeof(struct ieee_types_header)) + return; + if (pos[1] > 8) + return; memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos, sizeof(struct ieee_types_header) + min_t(u8, pos[1], 8)); break; case WLAN_EID_RSN: + if (pos > end - sizeof(struct ieee_types_header)) + return; + if (pos[1] < sizeof(struct ieee_types_header)) + return; + if (pos[1] > IEEE_MAX_IE_SIZE - + sizeof(struct ieee_types_header)) + return; memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos, sizeof(struct ieee_types_header) + min_t(u8, pos[1], IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header))); break; case WLAN_EID_QOS_CAPA: + if (pos > end - 3) + return; + if (pos[1] != 1) + return; sta_ptr->tdls_cap.qos_info = pos[2]; break; case WLAN_EID_VHT_OPERATION: - if (priv->adapter->is_hw_11ac_capable) - memcpy(&sta_ptr->tdls_cap.vhtoper, pos, + if (priv->adapter->is_hw_11ac_capable) { + if (pos > end - + sizeof(struct ieee80211_vht_operation) - 2) + return; + if (pos[1] != + sizeof(struct ieee80211_vht_operation)) + return; + /* copy the ie's value into vhtoper*/ + memcpy(&sta_ptr->tdls_cap.vhtoper, pos + 2, sizeof(struct ieee80211_vht_operation)); + } break; case WLAN_EID_VHT_CAPABILITY: if (priv->adapter->is_hw_11ac_capable) { - memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos, + if (pos > end - + sizeof(struct ieee80211_vht_cap) - 2) + return; + if (pos[1] != sizeof(struct ieee80211_vht_cap)) + return; + /* copy the ie's value into vhtcap*/ + memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos + 2, sizeof(struct ieee80211_vht_cap)); sta_ptr->is_11ac_enabled = 1; } break; case WLAN_EID_AID: - if (priv->adapter->is_hw_11ac_capable) + if (priv->adapter->is_hw_11ac_capable) { + if (pos > end - 4) + return; + if (pos[1] != 2) + return; sta_ptr->tdls_cap.aid = get_unaligned_le16((pos + 2)); + } + break; default: break; } -- GitLab From 9606b11726ecfb9724baf695cfa49704d370b2fb Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 15 Nov 2019 11:36:09 +0000 Subject: [PATCH 0024/1055] libtraceevent: Fix lib installation with O= [ Upstream commit 587db8ebdac2c5eb3a8851e16b26f2e2711ab797 ] When we use 'O=' with make to build libtraceevent in a separate folder it fails to install libtraceevent.a and libtraceevent.so.1.1.0 with the error: INSTALL /home/sudip/linux/obj-trace/libtraceevent.a INSTALL /home/sudip/linux/obj-trace/libtraceevent.so.1.1.0 cp: cannot stat 'libtraceevent.a': No such file or directory Makefile:225: recipe for target 'install_lib' failed make: *** [install_lib] Error 1 I used the command: make O=../../../obj-trace DESTDIR=~/test prefix==/usr install It turns out libtraceevent Makefile, even though it builds in a separate folder, searches for libtraceevent.a and libtraceevent.so.1.1.0 in its source folder. So, add the 'OUTPUT' prefix to the source path so that 'make' looks for the files in the correct place. Signed-off-by: Sudipm Mukherjee Reviewed-by: Steven Rostedt (VMware) Cc: linux-trace-devel@vger.kernel.org Link: http://lore.kernel.org/lkml/20191115113610.21493-1-sudipm.mukherjee@gmail.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin --- tools/lib/traceevent/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 8107f060fa84..a0ac01c647f5 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile @@ -115,6 +115,7 @@ EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION) LIB_TARGET = libtraceevent.a libtraceevent.so.$(EVENT_PARSE_VERSION) LIB_INSTALL = libtraceevent.a libtraceevent.so* +LIB_INSTALL := $(addprefix $(OUTPUT),$(LIB_INSTALL)) INCLUDES = -I. -I $(srctree)/tools/include $(CONFIG_INCLUDES) -- GitLab From c2f48252f119d8363475cca0544246e566fed31d Mon Sep 17 00:00:00 2001 From: Dave Young Date: Wed, 4 Dec 2019 15:52:33 +0800 Subject: [PATCH 0025/1055] x86/efi: Update e820 with reserved EFI boot services data to fix kexec breakage [ Upstream commit af164898482817a1d487964b68f3c21bae7a1beb ] Michael Weiser reported that he got this error during a kexec rebooting: esrt: Unsupported ESRT version 2904149718861218184. The ESRT memory stays in EFI boot services data, and it was reserved in kernel via efi_mem_reserve(). The initial purpose of the reservation is to reuse the EFI boot services data across kexec reboot. For example the BGRT image data and some ESRT memory like Michael reported. But although the memory is reserved it is not updated in the X86 E820 table, and kexec_file_load() iterates system RAM in the IO resource list to find places for kernel, initramfs and other stuff. In Michael's case the kexec loaded initramfs overwrote the ESRT memory and then the failure happened. Since kexec_file_load() depends on the E820 table being updated, just fix this by updating the reserved EFI boot services memory as reserved type in E820. Originally any memory descriptors with EFI_MEMORY_RUNTIME attribute are bypassed in the reservation code path because they are assumed as reserved. But the reservation is still needed for multiple kexec reboots, and it is the only possible case we come here thus just drop the code chunk, then everything works without side effects. On my machine the ESRT memory sits in an EFI runtime data range, it does not trigger the problem, but I successfully tested with BGRT instead. both kexec_load() and kexec_file_load() work and kdump works as well. [ mingo: Edited the changelog. ] Reported-by: Michael Weiser Tested-by: Michael Weiser Signed-off-by: Dave Young Cc: Ard Biesheuvel Cc: Borislav Petkov Cc: Eric W. Biederman Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: kexec@lists.infradead.org Cc: linux-efi@vger.kernel.org Link: https://lkml.kernel.org/r/20191204075233.GA10520@dhcp-128-65.nay.redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin --- arch/x86/platform/efi/quirks.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 5b513ccffde4..cadd7fd290fa 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -257,10 +257,6 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size) return; } - /* No need to reserve regions that will never be freed. */ - if (md.attribute & EFI_MEMORY_RUNTIME) - return; - size += addr % EFI_PAGE_SIZE; size = round_up(size, EFI_PAGE_SIZE); addr = round_down(addr, EFI_PAGE_SIZE); @@ -290,6 +286,8 @@ void __init efi_arch_mem_reserve(phys_addr_t addr, u64 size) early_memunmap(new, new_size); efi_memmap_install(new_phys, num_entries); + e820__range_update(addr, size, E820_TYPE_RAM, E820_TYPE_RESERVED); + e820__update_table(e820_table); } /* -- GitLab From 57bf13ee5910b446d45426f8d2ac136d2c19b39d Mon Sep 17 00:00:00 2001 From: Arvind Sankar Date: Fri, 6 Dec 2019 16:55:38 +0000 Subject: [PATCH 0026/1055] efi/gop: Return EFI_NOT_FOUND if there are no usable GOPs [ Upstream commit 6fc3cec30dfeee7d3c5db8154016aff9d65503c5 ] If we don't find a usable instance of the Graphics Output Protocol (GOP) because none of them have a framebuffer (i.e. they were all PIXEL_BLT_ONLY), but all the EFI calls succeeded, we will return EFI_SUCCESS even though we didn't find a usable GOP. Fix this by explicitly returning EFI_NOT_FOUND if no usable GOPs are found, allowing the caller to probe for UGA instead. Signed-off-by: Arvind Sankar Signed-off-by: Ard Biesheuvel Cc: Andy Shevchenko Cc: Bhupesh Sharma Cc: Masayoshi Mizuma Cc: linux-efi@vger.kernel.org Link: https://lkml.kernel.org/r/20191206165542.31469-3-ardb@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin --- drivers/firmware/efi/libstub/gop.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/efi/libstub/gop.c b/drivers/firmware/efi/libstub/gop.c index 24c461dea7af..16ed61c023e8 100644 --- a/drivers/firmware/efi/libstub/gop.c +++ b/drivers/firmware/efi/libstub/gop.c @@ -121,7 +121,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, u64 fb_base; struct efi_pixel_bitmask pixel_info; int pixel_format; - efi_status_t status = EFI_NOT_FOUND; + efi_status_t status; u32 *handles = (u32 *)(unsigned long)gop_handle; int i; @@ -177,7 +177,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, /* Did we find any GOPs? */ if (!first_gop) - goto out; + return EFI_NOT_FOUND; /* EFI framebuffer */ si->orig_video_isVGA = VIDEO_TYPE_EFI; @@ -199,7 +199,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, si->lfb_size = si->lfb_linelength * si->lfb_height; si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; -out: + return status; } @@ -239,7 +239,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, u64 fb_base; struct efi_pixel_bitmask pixel_info; int pixel_format; - efi_status_t status = EFI_NOT_FOUND; + efi_status_t status; u64 *handles = (u64 *)(unsigned long)gop_handle; int i; @@ -295,7 +295,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, /* Did we find any GOPs? */ if (!first_gop) - goto out; + return EFI_NOT_FOUND; /* EFI framebuffer */ si->orig_video_isVGA = VIDEO_TYPE_EFI; @@ -317,7 +317,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, si->lfb_size = si->lfb_linelength * si->lfb_height; si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; -out: + return status; } -- GitLab From 49277422c995e0d960381a6f67ebda03b548492e Mon Sep 17 00:00:00 2001 From: Arvind Sankar Date: Fri, 6 Dec 2019 16:55:39 +0000 Subject: [PATCH 0027/1055] efi/gop: Return EFI_SUCCESS if a usable GOP was found [ Upstream commit dbd89c303b4420f6cdb689fd398349fc83b059dd ] If we've found a usable instance of the Graphics Output Protocol (GOP) with a framebuffer, it is possible that one of the later EFI calls fails while checking if any support console output. In this case status may be an EFI error code even though we found a usable GOP. Fix this by explicitly return EFI_SUCCESS if a usable GOP has been located. Signed-off-by: Arvind Sankar Signed-off-by: Ard Biesheuvel Cc: Andy Shevchenko Cc: Bhupesh Sharma Cc: Masayoshi Mizuma Cc: linux-efi@vger.kernel.org Link: https://lkml.kernel.org/r/20191206165542.31469-4-ardb@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin --- drivers/firmware/efi/libstub/gop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/efi/libstub/gop.c b/drivers/firmware/efi/libstub/gop.c index 16ed61c023e8..81ffda5d1e48 100644 --- a/drivers/firmware/efi/libstub/gop.c +++ b/drivers/firmware/efi/libstub/gop.c @@ -200,7 +200,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; - return status; + return EFI_SUCCESS; } static efi_status_t @@ -318,7 +318,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, si->capabilities |= VIDEO_CAPABILITY_SKIP_QUIRKS; - return status; + return EFI_SUCCESS; } /* -- GitLab From 3b631b675b39d084ef4066a5642597a585357f95 Mon Sep 17 00:00:00 2001 From: Arvind Sankar Date: Fri, 6 Dec 2019 16:55:40 +0000 Subject: [PATCH 0028/1055] efi/gop: Fix memory leak in __gop_query32/64() [ Upstream commit ff397be685e410a59c34b21ce0c55d4daa466bb7 ] efi_graphics_output_protocol::query_mode() returns info in callee-allocated memory which must be freed by the caller, which we aren't doing. We don't actually need to call query_mode() in order to obtain the info for the current graphics mode, which is already there in gop->mode->info, so just access it directly in the setup_gop32/64() functions. Also nothing uses the size of the info structure, so don't update the passed-in size (which is the size of the gop_handle table in bytes) unnecessarily. Signed-off-by: Arvind Sankar Signed-off-by: Ard Biesheuvel Cc: Andy Shevchenko Cc: Bhupesh Sharma Cc: Masayoshi Mizuma Cc: linux-efi@vger.kernel.org Link: https://lkml.kernel.org/r/20191206165542.31469-5-ardb@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin --- drivers/firmware/efi/libstub/gop.c | 66 ++++++------------------------ 1 file changed, 12 insertions(+), 54 deletions(-) diff --git a/drivers/firmware/efi/libstub/gop.c b/drivers/firmware/efi/libstub/gop.c index 81ffda5d1e48..fd8053f9556e 100644 --- a/drivers/firmware/efi/libstub/gop.c +++ b/drivers/firmware/efi/libstub/gop.c @@ -85,30 +85,6 @@ setup_pixel_info(struct screen_info *si, u32 pixels_per_scan_line, } } -static efi_status_t -__gop_query32(efi_system_table_t *sys_table_arg, - struct efi_graphics_output_protocol_32 *gop32, - struct efi_graphics_output_mode_info **info, - unsigned long *size, u64 *fb_base) -{ - struct efi_graphics_output_protocol_mode_32 *mode; - efi_graphics_output_protocol_query_mode query_mode; - efi_status_t status; - unsigned long m; - - m = gop32->mode; - mode = (struct efi_graphics_output_protocol_mode_32 *)m; - query_mode = (void *)(unsigned long)gop32->query_mode; - - status = __efi_call_early(query_mode, (void *)gop32, mode->mode, size, - info); - if (status != EFI_SUCCESS) - return status; - - *fb_base = mode->frame_buffer_base; - return status; -} - static efi_status_t setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, efi_guid_t *proto, unsigned long size, void **gop_handle) @@ -130,6 +106,7 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, nr_gops = size / sizeof(u32); for (i = 0; i < nr_gops; i++) { + struct efi_graphics_output_protocol_mode_32 *mode; struct efi_graphics_output_mode_info *info = NULL; efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; bool conout_found = false; @@ -147,9 +124,11 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, if (status == EFI_SUCCESS) conout_found = true; - status = __gop_query32(sys_table_arg, gop32, &info, &size, - ¤t_fb_base); - if (status == EFI_SUCCESS && (!first_gop || conout_found) && + mode = (void *)(unsigned long)gop32->mode; + info = (void *)(unsigned long)mode->info; + current_fb_base = mode->frame_buffer_base; + + if ((!first_gop || conout_found) && info->pixel_format != PIXEL_BLT_ONLY) { /* * Systems that use the UEFI Console Splitter may @@ -203,30 +182,6 @@ setup_gop32(efi_system_table_t *sys_table_arg, struct screen_info *si, return EFI_SUCCESS; } -static efi_status_t -__gop_query64(efi_system_table_t *sys_table_arg, - struct efi_graphics_output_protocol_64 *gop64, - struct efi_graphics_output_mode_info **info, - unsigned long *size, u64 *fb_base) -{ - struct efi_graphics_output_protocol_mode_64 *mode; - efi_graphics_output_protocol_query_mode query_mode; - efi_status_t status; - unsigned long m; - - m = gop64->mode; - mode = (struct efi_graphics_output_protocol_mode_64 *)m; - query_mode = (void *)(unsigned long)gop64->query_mode; - - status = __efi_call_early(query_mode, (void *)gop64, mode->mode, size, - info); - if (status != EFI_SUCCESS) - return status; - - *fb_base = mode->frame_buffer_base; - return status; -} - static efi_status_t setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, efi_guid_t *proto, unsigned long size, void **gop_handle) @@ -248,6 +203,7 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, nr_gops = size / sizeof(u64); for (i = 0; i < nr_gops; i++) { + struct efi_graphics_output_protocol_mode_64 *mode; struct efi_graphics_output_mode_info *info = NULL; efi_guid_t conout_proto = EFI_CONSOLE_OUT_DEVICE_GUID; bool conout_found = false; @@ -265,9 +221,11 @@ setup_gop64(efi_system_table_t *sys_table_arg, struct screen_info *si, if (status == EFI_SUCCESS) conout_found = true; - status = __gop_query64(sys_table_arg, gop64, &info, &size, - ¤t_fb_base); - if (status == EFI_SUCCESS && (!first_gop || conout_found) && + mode = (void *)(unsigned long)gop64->mode; + info = (void *)(unsigned long)mode->info; + current_fb_base = mode->frame_buffer_base; + + if ((!first_gop || conout_found) && info->pixel_format != PIXEL_BLT_ONLY) { /* * Systems that use the UEFI Console Splitter may -- GitLab From 210670f32876544b6cb7613dc4d1c7b63dec03d0 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 27 Nov 2019 15:56:40 +0000 Subject: [PATCH 0029/1055] ARM: vexpress: Set-up shared OPP table instead of individual for each CPU [ Upstream commit 2a76352ad2cc6b78e58f737714879cc860903802 ] Currently we add individual copy of same OPP table for each CPU within the cluster. This is redundant and doesn't reflect the reality. We can't use core cpumask to set policy->cpus in ve_spc_cpufreq_init() anymore as it gets called via cpuhp_cpufreq_online()->cpufreq_online() ->cpufreq_driver->init() and the cpumask gets updated upon CPU hotplug operations. It also may cause issues when the vexpress_spc_cpufreq driver is built as a module. Since ve_spc_clk_init is built-in device initcall, we should be able to use the same topology_core_cpumask to set the opp sharing cpumask via dev_pm_opp_set_sharing_cpus and use the same later in the driver via dev_pm_opp_get_sharing_cpus. Cc: Liviu Dudau Cc: Lorenzo Pieralisi Acked-by: Viresh Kumar Tested-by: Dietmar Eggemann Signed-off-by: Sudeep Holla Signed-off-by: Sasha Levin --- arch/arm/mach-vexpress/spc.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-vexpress/spc.c b/arch/arm/mach-vexpress/spc.c index fe488523694c..635b0d549487 100644 --- a/arch/arm/mach-vexpress/spc.c +++ b/arch/arm/mach-vexpress/spc.c @@ -555,8 +555,9 @@ static struct clk *ve_spc_clk_register(struct device *cpu_dev) static int __init ve_spc_clk_init(void) { - int cpu; + int cpu, cluster; struct clk *clk; + bool init_opp_table[MAX_CLUSTERS] = { false }; if (!info) return 0; /* Continue only if SPC is initialised */ @@ -582,8 +583,17 @@ static int __init ve_spc_clk_init(void) continue; } + cluster = topology_physical_package_id(cpu_dev->id); + if (init_opp_table[cluster]) + continue; + if (ve_init_opp_table(cpu_dev)) pr_warn("failed to initialise cpu%d opp table\n", cpu); + else if (dev_pm_opp_set_sharing_cpus(cpu_dev, + topology_core_cpumask(cpu_dev->id))) + pr_warn("failed to mark OPPs shared for cpu%d\n", cpu); + else + init_opp_table[cluster] = true; } platform_device_register_simple("vexpress-spc-cpufreq", -1, NULL, 0); -- GitLab From 38061de32f9c9f943e5fe1685e8473ccad2d5098 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 5 Dec 2019 13:35:11 +0100 Subject: [PATCH 0030/1055] netfilter: uapi: Avoid undefined left-shift in xt_sctp.h [ Upstream commit 164166558aacea01b99c8c8ffb710d930405ba69 ] With 'bytes(__u32)' being 32, a left-shift of 31 may happen which is undefined for the signed 32-bit value 1. Avoid this by declaring 1 as unsigned. Signed-off-by: Phil Sutter Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- include/uapi/linux/netfilter/xt_sctp.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/netfilter/xt_sctp.h b/include/uapi/linux/netfilter/xt_sctp.h index 4bc6d1a08781..b4d804a9fccb 100644 --- a/include/uapi/linux/netfilter/xt_sctp.h +++ b/include/uapi/linux/netfilter/xt_sctp.h @@ -41,19 +41,19 @@ struct xt_sctp_info { #define SCTP_CHUNKMAP_SET(chunkmap, type) \ do { \ (chunkmap)[type / bytes(__u32)] |= \ - 1 << (type % bytes(__u32)); \ + 1u << (type % bytes(__u32)); \ } while (0) #define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \ do { \ (chunkmap)[type / bytes(__u32)] &= \ - ~(1 << (type % bytes(__u32))); \ + ~(1u << (type % bytes(__u32))); \ } while (0) #define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \ ({ \ ((chunkmap)[type / bytes (__u32)] & \ - (1 << (type % bytes (__u32)))) ? 1: 0; \ + (1u << (type % bytes (__u32)))) ? 1: 0; \ }) #define SCTP_CHUNKMAP_RESET(chunkmap) \ -- GitLab From 4798a83039ce8dd2afbe7d9395796593991d1363 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 6 Dec 2019 21:55:20 +0100 Subject: [PATCH 0031/1055] netfilter: nf_tables: validate NFT_SET_ELEM_INTERVAL_END [ Upstream commit bffc124b6fe37d0ae9b428d104efb426403bb5c9 ] Only NFTA_SET_ELEM_KEY and NFTA_SET_ELEM_FLAGS make sense for elements whose NFT_SET_ELEM_INTERVAL_END flag is set on. Fixes: 96518518cc41 ("netfilter: add nftables") Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/netfilter/nf_tables_api.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 7ef126489d4e..91490446ebb4 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -3917,14 +3917,20 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, if (nla[NFTA_SET_ELEM_DATA] == NULL && !(flags & NFT_SET_ELEM_INTERVAL_END)) return -EINVAL; - if (nla[NFTA_SET_ELEM_DATA] != NULL && - flags & NFT_SET_ELEM_INTERVAL_END) - return -EINVAL; } else { if (nla[NFTA_SET_ELEM_DATA] != NULL) return -EINVAL; } + if ((flags & NFT_SET_ELEM_INTERVAL_END) && + (nla[NFTA_SET_ELEM_DATA] || + nla[NFTA_SET_ELEM_OBJREF] || + nla[NFTA_SET_ELEM_TIMEOUT] || + nla[NFTA_SET_ELEM_EXPIRATION] || + nla[NFTA_SET_ELEM_USERDATA] || + nla[NFTA_SET_ELEM_EXPR])) + return -EINVAL; + timeout = 0; if (nla[NFTA_SET_ELEM_TIMEOUT] != NULL) { if (!(set->flags & NFT_SET_TIMEOUT)) -- GitLab From 84b33e7a2364bda397e9953782e7a6de8468aa90 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2019 10:19:09 -0800 Subject: [PATCH 0032/1055] ARM: dts: Cygnus: Fix MDIO node address/size cells [ Upstream commit fac2c2da3596d77c343988bb0d41a8c533b2e73c ] The MDIO node on Cygnus had an reversed #address-cells and #size-cells properties, correct those. Fixes: 40c26d3af60a ("ARM: dts: Cygnus: Add the ethernet switch and ethernet PHY") Reported-by: Simon Horman Reviewed-by: Ray Jui Reviewed-by: Simon Horman Signed-off-by: Florian Fainelli Signed-off-by: Sasha Levin --- arch/arm/boot/dts/bcm-cygnus.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi index 8b2c65cd61a2..b822952c29f8 100644 --- a/arch/arm/boot/dts/bcm-cygnus.dtsi +++ b/arch/arm/boot/dts/bcm-cygnus.dtsi @@ -165,8 +165,8 @@ mdio: mdio@18002000 { compatible = "brcm,iproc-mdio"; reg = <0x18002000 0x8>; - #size-cells = <1>; - #address-cells = <0>; + #size-cells = <0>; + #address-cells = <1>; status = "disabled"; gphy0: ethernet-phy@0 { -- GitLab From 0c2cabe56e1186310af9b1bb25f6ad4a429052ce Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Fri, 6 Dec 2019 15:55:00 +0800 Subject: [PATCH 0033/1055] spi: spi-cavium-thunderx: Add missing pci_release_regions() [ Upstream commit a841e2853e1afecc2ee692b8cc5bff606bc84e4c ] The driver forgets to call pci_release_regions() in probe failure and remove. Add the missed calls to fix it. Signed-off-by: Chuhong Yuan Link: https://lore.kernel.org/r/20191206075500.18525-1-hslester96@gmail.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-cavium-thunderx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/spi/spi-cavium-thunderx.c b/drivers/spi/spi-cavium-thunderx.c index 877937706240..828fbbebc3c4 100644 --- a/drivers/spi/spi-cavium-thunderx.c +++ b/drivers/spi/spi-cavium-thunderx.c @@ -81,6 +81,7 @@ static int thunderx_spi_probe(struct pci_dev *pdev, error: clk_disable_unprepare(p->clk); + pci_release_regions(pdev); spi_master_put(master); return ret; } @@ -95,6 +96,7 @@ static void thunderx_spi_remove(struct pci_dev *pdev) return; clk_disable_unprepare(p->clk); + pci_release_regions(pdev); /* Put everything in a known state. */ writeq(0, p->register_base + OCTEON_SPI_CFG(p)); } -- GitLab From 31764a701731a018ecbc2c62f950828b377c7b48 Mon Sep 17 00:00:00 2001 From: Dragos Tarcatu Date: Mon, 9 Dec 2019 18:39:39 -0600 Subject: [PATCH 0034/1055] ASoC: topology: Check return value for soc_tplg_pcm_create() [ Upstream commit a3039aef52d9ffeb67e9211899cd3e8a2953a01f ] The return value of soc_tplg_pcm_create() is currently not checked in soc_tplg_pcm_elems_load(). If an error is to occur there, the topology ignores it and continues loading. Fix that by checking the status and rejecting the topology on error. Reviewed-by: Ranjani Sridharan Signed-off-by: Dragos Tarcatu Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191210003939.15752-3-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/soc-topology.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 2d5cf263515b..72301bcad3bd 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1921,6 +1921,7 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, int count = hdr->count; int i; bool abi_match; + int ret; if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) return 0; @@ -1957,7 +1958,12 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, } /* create the FE DAIs and DAI links */ - soc_tplg_pcm_create(tplg, _pcm); + ret = soc_tplg_pcm_create(tplg, _pcm); + if (ret < 0) { + if (!abi_match) + kfree(_pcm); + return ret; + } /* offset by version-specific struct size and * real priv data size -- GitLab From d4aea1529970f3d50217913824fb93d10b98f0e2 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 30 Nov 2019 13:31:13 +0100 Subject: [PATCH 0035/1055] ARM: dts: bcm283x: Fix critical trip point [ Upstream commit 30e647a764d446723a7e0fb08d209e0104f16173 ] During definition of the CPU thermal zone of BCM283x SoC family there was a misunderstanding of the meaning "criticial trip point" and the thermal throttling range of the VideoCore firmware. The latter one takes effect when the core temperature is at least 85 degree celsius or higher So the current critical trip point doesn't make sense, because the thermal shutdown appears before the firmware has a chance to throttle the ARM core(s). Fix these unwanted shutdowns by increasing the critical trip point to a value which shouldn't be reached with working thermal throttling. Fixes: 0fe4d2181cc4 ("ARM: dts: bcm283x: Add CPU thermal zone with 1 trip point") Signed-off-by: Stefan Wahren Signed-off-by: Florian Fainelli Signed-off-by: Sasha Levin --- arch/arm/boot/dts/bcm283x.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi index 4745e3c7806b..fdb018e1278f 100644 --- a/arch/arm/boot/dts/bcm283x.dtsi +++ b/arch/arm/boot/dts/bcm283x.dtsi @@ -38,7 +38,7 @@ trips { cpu-crit { - temperature = <80000>; + temperature = <90000>; hysteresis = <0>; type = "critical"; }; -- GitLab From ec41394252a9c4f8d7f0224f16de2b6a29704e54 Mon Sep 17 00:00:00 2001 From: Paul Chaignon Date: Mon, 9 Dec 2019 19:52:52 +0100 Subject: [PATCH 0036/1055] bpf, mips: Limit to 33 tail calls [ Upstream commit e49e6f6db04e915dccb494ae10fa14888fea6f89 ] All BPF JIT compilers except RISC-V's and MIPS' enforce a 33-tail calls limit at runtime. In addition, a test was recently added, in tailcalls2, to check this limit. This patch updates the tail call limit in MIPS' JIT compiler to allow 33 tail calls. Fixes: b6bd53f9c4e8 ("MIPS: Add missing file for eBPF JIT.") Reported-by: Mahshid Khezri Signed-off-by: Paul Chaignon Signed-off-by: Daniel Borkmann Acked-by: Martin KaFai Lau Link: https://lore.kernel.org/bpf/b8eb2caac1c25453c539248e56ca22f74b5316af.1575916815.git.paul.chaignon@gmail.com Signed-off-by: Sasha Levin --- arch/mips/net/ebpf_jit.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/mips/net/ebpf_jit.c b/arch/mips/net/ebpf_jit.c index 42faa95ce664..57a7a9d68475 100644 --- a/arch/mips/net/ebpf_jit.c +++ b/arch/mips/net/ebpf_jit.c @@ -612,6 +612,7 @@ static void emit_const_to_reg(struct jit_ctx *ctx, int dst, u64 value) static int emit_bpf_tail_call(struct jit_ctx *ctx, int this_idx) { int off, b_off; + int tcc_reg; ctx->flags |= EBPF_SEEN_TC; /* @@ -624,14 +625,14 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int this_idx) b_off = b_imm(this_idx + 1, ctx); emit_instr(ctx, bne, MIPS_R_AT, MIPS_R_ZERO, b_off); /* - * if (--TCC < 0) + * if (TCC-- < 0) * goto out; */ /* Delay slot */ - emit_instr(ctx, daddiu, MIPS_R_T5, - (ctx->flags & EBPF_TCC_IN_V1) ? MIPS_R_V1 : MIPS_R_S4, -1); + tcc_reg = (ctx->flags & EBPF_TCC_IN_V1) ? MIPS_R_V1 : MIPS_R_S4; + emit_instr(ctx, daddiu, MIPS_R_T5, tcc_reg, -1); b_off = b_imm(this_idx + 1, ctx); - emit_instr(ctx, bltz, MIPS_R_T5, b_off); + emit_instr(ctx, bltz, tcc_reg, b_off); /* * prog = array->ptrs[index]; * if (prog == NULL) -- GitLab From 328133b1c1ee44e52f583482a191c152fb693fba Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 14 Nov 2019 11:39:48 +0200 Subject: [PATCH 0037/1055] ARM: dts: am437x-gp/epos-evm: fix panel compatible [ Upstream commit c6b16761c6908d3dc167a0a566578b4b0b972905 ] The LCD panel on AM4 GP EVMs and ePOS boards seems to be osd070t1718-19ts. The current dts files say osd057T0559-34ts. Possibly the panel has changed since the early EVMs, or there has been a mistake with the panel type. Update the DT files accordingly. Acked-by: Laurent Pinchart Signed-off-by: Tomi Valkeinen Signed-off-by: Tony Lindgren Signed-off-by: Sasha Levin --- arch/arm/boot/dts/am437x-gp-evm.dts | 2 +- arch/arm/boot/dts/am43x-epos-evm.dts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index afb8eb0a0a16..051823b7e5a1 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -83,7 +83,7 @@ }; lcd0: display { - compatible = "osddisplays,osd057T0559-34ts", "panel-dpi"; + compatible = "osddisplays,osd070t1718-19ts", "panel-dpi"; label = "lcd"; panel-timing { diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts index 081fa68b6f98..c4279b0b9f12 100644 --- a/arch/arm/boot/dts/am43x-epos-evm.dts +++ b/arch/arm/boot/dts/am43x-epos-evm.dts @@ -45,7 +45,7 @@ }; lcd0: display { - compatible = "osddisplays,osd057T0559-34ts", "panel-dpi"; + compatible = "osddisplays,osd070t1718-19ts", "panel-dpi"; label = "lcd"; panel-timing { -- GitLab From b50ba34bdba823b4bd26bd6c0ca940f3e43d93e9 Mon Sep 17 00:00:00 2001 From: "Daniel T. Lee" Date: Thu, 5 Dec 2019 17:01:13 +0900 Subject: [PATCH 0038/1055] samples: bpf: Replace symbol compare of trace_event [ Upstream commit bba1b2a890253528c45aa66cf856f289a215bfbc ] Previously, when this sample is added, commit 1c47910ef8013 ("samples/bpf: add perf_event+bpf example"), a symbol 'sys_read' and 'sys_write' has been used without no prefixes. But currently there are no exact symbols with these under kallsyms and this leads to failure. This commit changes exact compare to substring compare to keep compatible with exact symbol or prefixed symbol. Fixes: 1c47910ef8013 ("samples/bpf: add perf_event+bpf example") Signed-off-by: Daniel T. Lee Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191205080114.19766-2-danieltimlee@gmail.com Signed-off-by: Sasha Levin --- samples/bpf/trace_event_user.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/bpf/trace_event_user.c b/samples/bpf/trace_event_user.c index c7d525e5696e..8c7445874662 100644 --- a/samples/bpf/trace_event_user.c +++ b/samples/bpf/trace_event_user.c @@ -34,9 +34,9 @@ static void print_ksym(__u64 addr) return; sym = ksym_search(addr); printf("%s;", sym->name); - if (!strcmp(sym->name, "sys_read")) + if (!strstr(sym->name, "sys_read")) sys_read_seen = true; - else if (!strcmp(sym->name, "sys_write")) + else if (!strstr(sym->name, "sys_write")) sys_write_seen = true; } -- GitLab From f0822e783ef59454cefdcd8e32468fe92386fa94 Mon Sep 17 00:00:00 2001 From: "Daniel T. Lee" Date: Thu, 5 Dec 2019 17:01:14 +0900 Subject: [PATCH 0039/1055] samples: bpf: fix syscall_tp due to unused syscall [ Upstream commit fe3300897cbfd76c6cb825776e5ac0ca50a91ca4 ] Currently, open() is called from the user program and it calls the syscall 'sys_openat', not the 'sys_open'. This leads to an error of the program of user side, due to the fact that the counter maps are zero since no function such 'sys_open' is called. This commit adds the kernel bpf program which are attached to the tracepoint 'sys_enter_openat' and 'sys_enter_openat'. Fixes: 1da236b6be963 ("bpf: add a test case for syscalls/sys_{enter|exit}_* tracepoints") Signed-off-by: Daniel T. Lee Signed-off-by: Alexei Starovoitov Signed-off-by: Sasha Levin --- samples/bpf/syscall_tp_kern.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/samples/bpf/syscall_tp_kern.c b/samples/bpf/syscall_tp_kern.c index 9149c524d279..8833aacb9c8c 100644 --- a/samples/bpf/syscall_tp_kern.c +++ b/samples/bpf/syscall_tp_kern.c @@ -50,13 +50,27 @@ static __always_inline void count(void *map) SEC("tracepoint/syscalls/sys_enter_open") int trace_enter_open(struct syscalls_enter_open_args *ctx) { - count((void *)&enter_open_map); + count(&enter_open_map); + return 0; +} + +SEC("tracepoint/syscalls/sys_enter_openat") +int trace_enter_open_at(struct syscalls_enter_open_args *ctx) +{ + count(&enter_open_map); return 0; } SEC("tracepoint/syscalls/sys_exit_open") int trace_enter_exit(struct syscalls_exit_open_args *ctx) { - count((void *)&exit_open_map); + count(&exit_open_map); + return 0; +} + +SEC("tracepoint/syscalls/sys_exit_openat") +int trace_enter_exit_at(struct syscalls_exit_open_args *ctx) +{ + count(&exit_open_map); return 0; } -- GitLab From bea1fe7e2f8edb86e66a56e2ebb74bc9bf3c83bd Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 4 Dec 2019 14:35:24 +0200 Subject: [PATCH 0040/1055] powerpc: Ensure that swiotlb buffer is allocated from low memory [ Upstream commit 8fabc623238e68b3ac63c0dd1657bf86c1fa33af ] Some powerpc platforms (e.g. 85xx) limit DMA-able memory way below 4G. If a system has more physical memory than this limit, the swiotlb buffer is not addressable because it is allocated from memblock using top-down mode. Force memblock to bottom-up mode before calling swiotlb_init() to ensure that the swiotlb buffer is DMA-able. Reported-by: Christian Zigotzky Signed-off-by: Mike Rapoport Reviewed-by: Christoph Hellwig Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20191204123524.22919-1-rppt@kernel.org Signed-off-by: Sasha Levin --- arch/powerpc/mm/mem.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 30bf13b72e5e..3c5abfbbe60e 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -353,6 +353,14 @@ void __init mem_init(void) BUILD_BUG_ON(MMU_PAGE_COUNT > 16); #ifdef CONFIG_SWIOTLB + /* + * Some platforms (e.g. 85xx) limit DMA-able memory way below + * 4G. We force memblock to bottom-up mode to ensure that the + * memory allocated in swiotlb_init() is DMA-able. + * As it's the last memblock allocation, no need to reset it + * back to to-down. + */ + memblock_set_bottom_up(true); swiotlb_init(0); #endif -- GitLab From 58ee0e0b74e7e4d8dadc3597d3d721a9cd252a88 Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Wed, 11 Dec 2019 09:59:55 -0800 Subject: [PATCH 0041/1055] bnx2x: Do not handle requests from VFs after parity [ Upstream commit 7113f796bbbced2470cd6d7379d50d7a7a78bf34 ] Parity error from the hardware will cause PF to lose the state of their VFs due to PF's internal reload and hardware reset following the parity error. Restrict any configuration request from the VFs after the parity as it could cause unexpected hardware behavior, only way for VFs to recover would be to trigger FLR on VFs and reload them. Signed-off-by: Manish Chopra Signed-off-by: Ariel Elior Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 12 ++++++++++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h | 1 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c | 12 ++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index dbe8feec456c..b0ada7eac652 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -9995,10 +9995,18 @@ static void bnx2x_recovery_failed(struct bnx2x *bp) */ static void bnx2x_parity_recover(struct bnx2x *bp) { - bool global = false; u32 error_recovered, error_unrecovered; - bool is_parity; + bool is_parity, global = false; +#ifdef CONFIG_BNX2X_SRIOV + int vf_idx; + + for (vf_idx = 0; vf_idx < bp->requested_nr_virtfn; vf_idx++) { + struct bnx2x_virtf *vf = BP_VF(bp, vf_idx); + if (vf) + vf->state = VF_LOST; + } +#endif DP(NETIF_MSG_HW, "Handling parity\n"); while (1) { switch (bp->recovery_state) { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h index 53466f6cebab..a887bfa24c88 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h @@ -139,6 +139,7 @@ struct bnx2x_virtf { #define VF_ACQUIRED 1 /* VF acquired, but not initialized */ #define VF_ENABLED 2 /* VF Enabled */ #define VF_RESET 3 /* VF FLR'd, pending cleanup */ +#define VF_LOST 4 /* Recovery while VFs are loaded */ bool flr_clnup_stage; /* true during flr cleanup */ bool malicious; /* true if FW indicated so, until FLR */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c index 76a4668c50fe..6d5b81a971e3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c @@ -2112,6 +2112,18 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf, { int i; + if (vf->state == VF_LOST) { + /* Just ack the FW and return if VFs are lost + * in case of parity error. VFs are supposed to be timedout + * on waiting for PF response. + */ + DP(BNX2X_MSG_IOV, + "VF 0x%x lost, not handling the request\n", vf->abs_vfid); + + storm_memset_vf_mbx_ack(bp, vf->abs_vfid); + return; + } + /* check if tlv type is known */ if (bnx2x_tlv_supported(mbx->first_tlv.tl.type)) { /* Lock the per vf op mutex and note the locker's identity. -- GitLab From 9c914b0d4beb0af271049453d1e05ac278ebfabc Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Wed, 11 Dec 2019 09:59:56 -0800 Subject: [PATCH 0042/1055] bnx2x: Fix logic to get total no. of PFs per engine [ Upstream commit ee699f89bdbaa19c399804504241b5c531b48888 ] Driver doesn't calculate total number of PFs configured on a given engine correctly which messed up resources in the PFs loaded on that engine, leading driver to exceed configuration of resources (like vlan filters etc.) beyond the limit per engine, which ended up with asserts from the firmware. Signed-off-by: Manish Chopra Signed-off-by: Ariel Elior Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 4e091a11daaf..52bce009d096 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -1112,7 +1112,7 @@ static inline u8 bnx2x_get_path_func_num(struct bnx2x *bp) for (i = 0; i < E1H_FUNC_MAX / 2; i++) { u32 func_config = MF_CFG_RD(bp, - func_mf_config[BP_PORT(bp) + 2 * i]. + func_mf_config[BP_PATH(bp) + 2 * i]. config); func_num += ((func_config & FUNC_MF_CFG_FUNC_HIDE) ? 0 : 1); -- GitLab From 4f5cf943699a6331949ce4cb319de3e23b787a04 Mon Sep 17 00:00:00 2001 From: Cristian Birsan Date: Fri, 13 Dec 2019 18:33:11 +0200 Subject: [PATCH 0043/1055] net: usb: lan78xx: Fix error message format specifier [ Upstream commit 858ce8ca62ea1530f2779d0e3f934b0176e663c3 ] Display the return code as decimal integer. Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver") Signed-off-by: Cristian Birsan Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/usb/lan78xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 7d1d5b30ecc3..0aa6f3a5612d 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -497,7 +497,7 @@ static int lan78xx_read_stats(struct lan78xx_net *dev, } } else { netdev_warn(dev->net, - "Failed to read stat ret = 0x%x", ret); + "Failed to read stat ret = %d", ret); } kfree(stats); -- GitLab From c7a6c3d2c372a592c975cda98a479287ebd169d1 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Sun, 15 Dec 2019 09:34:08 -0600 Subject: [PATCH 0044/1055] rfkill: Fix incorrect check to avoid NULL pointer dereference [ Upstream commit 6fc232db9e8cd50b9b83534de9cd91ace711b2d7 ] In rfkill_register, the struct rfkill pointer is first derefernced and then checked for NULL. This patch removes the BUG_ON and returns an error to the caller in case rfkill is NULL. Signed-off-by: Aditya Pakki Link: https://lore.kernel.org/r/20191215153409.21696-1-pakki001@umn.edu Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/rfkill/core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/rfkill/core.c b/net/rfkill/core.c index 99a2e55b01cf..e31b4288f32c 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -998,10 +998,13 @@ static void rfkill_sync_work(struct work_struct *work) int __must_check rfkill_register(struct rfkill *rfkill) { static unsigned long rfkill_no; - struct device *dev = &rfkill->dev; + struct device *dev; int error; - BUG_ON(!rfkill); + if (!rfkill) + return -EINVAL; + + dev = &rfkill->dev; mutex_lock(&rfkill_global_mutex); -- GitLab From ebfcc61fb719b08d63ed463d8ddea64570fb55ce Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Wed, 11 Dec 2019 19:57:22 +0800 Subject: [PATCH 0045/1055] ASoC: wm8962: fix lambda value [ Upstream commit 556672d75ff486e0b6786056da624131679e0576 ] According to user manual, it is required that FLL_LAMBDA > 0 in all cases (Integer and Franctional modes). Fixes: 9a76f1ff6e29 ("ASoC: Add initial WM8962 CODEC driver") Signed-off-by: Shengjiu Wang Acked-by: Charles Keepax Link: https://lore.kernel.org/r/1576065442-19763-1-git-send-email-shengjiu.wang@nxp.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/wm8962.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index fd2731d171dd..0e8008d38161 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2791,7 +2791,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, if (target % Fref == 0) { fll_div->theta = 0; - fll_div->lambda = 0; + fll_div->lambda = 1; } else { gcd_fll = gcd(target, fratio * Fref); @@ -2861,7 +2861,7 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, return -EINVAL; } - if (fll_div.theta || fll_div.lambda) + if (fll_div.theta) fll1 |= WM8962_FLL_FRAC; /* Stop the FLL while we reconfigure */ -- GitLab From 2dfde10dda0e0939ae4f29aff02327962f9ef9f3 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Wed, 11 Dec 2019 23:16:00 +0100 Subject: [PATCH 0046/1055] regulator: rn5t618: fix module aliases [ Upstream commit 62a1923cc8fe095912e6213ed5de27abbf1de77e ] platform device aliases were missing, preventing autoloading of module. Fixes: 811b700630ff ("regulator: rn5t618: add driver for Ricoh RN5T618 regulators") Signed-off-by: Andreas Kemnade Link: https://lore.kernel.org/r/20191211221600.29438-1-andreas@kemnade.info Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/regulator/rn5t618-regulator.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/regulator/rn5t618-regulator.c b/drivers/regulator/rn5t618-regulator.c index 790a4a73ea2c..40b74648bd31 100644 --- a/drivers/regulator/rn5t618-regulator.c +++ b/drivers/regulator/rn5t618-regulator.c @@ -154,6 +154,7 @@ static struct platform_driver rn5t618_regulator_driver = { module_platform_driver(rn5t618_regulator_driver); +MODULE_ALIAS("platform:rn5t618-regulator"); MODULE_AUTHOR("Beniamino Galvani "); MODULE_DESCRIPTION("RN5T618 regulator driver"); MODULE_LICENSE("GPL v2"); -- GitLab From 16b9c5c49b4131a63f1e108b23ba2399c241fd87 Mon Sep 17 00:00:00 2001 From: Thomas Hebb Date: Mon, 9 Dec 2019 00:19:17 -0800 Subject: [PATCH 0047/1055] kconfig: don't crash on NULL expressions in expr_eq() [ Upstream commit 272a72103012862e3a24ea06635253ead0b6e808 ] NULL expressions are taken to always be true, as implemented by the expr_is_yes() macro and by several other functions in expr.c. As such, they ought to be valid inputs to expr_eq(), which compares two expressions. Signed-off-by: Thomas Hebb Signed-off-by: Masahiro Yamada Signed-off-by: Sasha Levin --- scripts/kconfig/expr.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index ed29bad1f03a..96420b620963 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -201,6 +201,13 @@ static int expr_eq(struct expr *e1, struct expr *e2) { int res, old_count; + /* + * A NULL expr is taken to be yes, but there's also a different way to + * represent yes. expr_is_yes() checks for either representation. + */ + if (!e1 || !e2) + return expr_is_yes(e1) && expr_is_yes(e2); + if (e1->type != e2->type) return 0; switch (e1->type) { -- GitLab From 396bf8fe4f679d8e457867b9ff60ee5fd6d99d42 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Tue, 10 Dec 2019 12:51:01 +0200 Subject: [PATCH 0048/1055] perf/x86/intel: Fix PT PMI handling [ Upstream commit 92ca7da4bdc24d63bb0bcd241c11441ddb63b80a ] Commit: ccbebba4c6bf ("perf/x86/intel/pt: Bypass PT vs. LBR exclusivity if the core supports it") skips the PT/LBR exclusivity check on CPUs where PT and LBRs coexist, but also inadvertently skips the active_events bump for PT in that case, which is a bug. If there aren't any hardware events at the same time as PT, the PMI handler will ignore PT PMIs, as active_events reads zero in that case, resulting in the "Uhhuh" spurious NMI warning and PT data loss. Fix this by always increasing active_events for PT events. Fixes: ccbebba4c6bf ("perf/x86/intel/pt: Bypass PT vs. LBR exclusivity if the core supports it") Reported-by: Vitaly Slobodskoy Signed-off-by: Alexander Shishkin Signed-off-by: Peter Zijlstra (Intel) Acked-by: Alexey Budankov Cc: Jiri Olsa Cc: Ingo Molnar Cc: Arnaldo Carvalho de Melo Link: https://lkml.kernel.org/r/20191210105101.77210-1-alexander.shishkin@linux.intel.com Signed-off-by: Sasha Levin --- arch/x86/events/core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 6ed99de2ddf5..c1f7b3cb84a9 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -375,7 +375,7 @@ int x86_add_exclusive(unsigned int what) * LBR and BTS are still mutually exclusive. */ if (x86_pmu.lbr_pt_coexist && what == x86_lbr_exclusive_pt) - return 0; + goto out; if (!atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what])) { mutex_lock(&pmc_reserve_mutex); @@ -387,6 +387,7 @@ int x86_add_exclusive(unsigned int what) mutex_unlock(&pmc_reserve_mutex); } +out: atomic_inc(&active_events); return 0; @@ -397,11 +398,15 @@ int x86_add_exclusive(unsigned int what) void x86_del_exclusive(unsigned int what) { + atomic_dec(&active_events); + + /* + * See the comment in x86_add_exclusive(). + */ if (x86_pmu.lbr_pt_coexist && what == x86_lbr_exclusive_pt) return; atomic_dec(&x86_pmu.lbr_exclusive[what]); - atomic_dec(&active_events); } int x86_setup_perfctr(struct perf_event *event) -- GitLab From 61855d6805ae078ae6bba561e6e76715436d776d Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Fri, 6 Dec 2019 10:54:23 -0600 Subject: [PATCH 0049/1055] fs: avoid softlockups in s_inodes iterators [ Upstream commit 04646aebd30b99f2cfa0182435a2ec252fcb16d0 ] Anything that walks all inodes on sb->s_inodes list without rescheduling risks softlockups. Previous efforts were made in 2 functions, see: c27d82f fs/drop_caches.c: avoid softlockups in drop_pagecache_sb() ac05fbb inode: don't softlockup when evicting inodes but there hasn't been an audit of all walkers, so do that now. This also consistently moves the cond_resched() calls to the bottom of each loop in cases where it already exists. One loop remains: remove_dquot_ref(), because I'm not quite sure how to deal with that one w/o taking the i_lock. Signed-off-by: Eric Sandeen Reviewed-by: Jan Kara Signed-off-by: Al Viro Signed-off-by: Sasha Levin --- fs/drop_caches.c | 2 +- fs/inode.c | 7 +++++++ fs/notify/fsnotify.c | 1 + fs/quota/dquot.c | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/drop_caches.c b/fs/drop_caches.c index d31b6c72b476..dc1a1d5d825b 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c @@ -35,11 +35,11 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) spin_unlock(&inode->i_lock); spin_unlock(&sb->s_inode_list_lock); - cond_resched(); invalidate_mapping_pages(inode->i_mapping, 0, -1); iput(toput_inode); toput_inode = inode; + cond_resched(); spin_lock(&sb->s_inode_list_lock); } spin_unlock(&sb->s_inode_list_lock); diff --git a/fs/inode.c b/fs/inode.c index 76f7535fe754..d2a700c5efce 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -656,6 +656,7 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty) struct inode *inode, *next; LIST_HEAD(dispose); +again: spin_lock(&sb->s_inode_list_lock); list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { spin_lock(&inode->i_lock); @@ -678,6 +679,12 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty) inode_lru_list_del(inode); spin_unlock(&inode->i_lock); list_add(&inode->i_lru, &dispose); + if (need_resched()) { + spin_unlock(&sb->s_inode_list_lock); + cond_resched(); + dispose_list(&dispose); + goto again; + } } spin_unlock(&sb->s_inode_list_lock); diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 506da82ff3f1..a308f7a7e577 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -90,6 +90,7 @@ void fsnotify_unmount_inodes(struct super_block *sb) iput_inode = inode; + cond_resched(); spin_lock(&sb->s_inode_list_lock); } spin_unlock(&sb->s_inode_list_lock); diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 3fdbdd29702b..30f5da8f4aff 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -976,6 +976,7 @@ static int add_dquot_ref(struct super_block *sb, int type) * later. */ old_inode = inode; + cond_resched(); spin_lock(&sb->s_inode_list_lock); } spin_unlock(&sb->s_inode_list_lock); -- GitLab From aa6bf9433ef76485243428754e723e71642f4a6d Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Wed, 18 Dec 2019 11:17:37 +0100 Subject: [PATCH 0050/1055] net: stmmac: Do not accept invalid MTU values [ Upstream commit eaf4fac478077d4ed57cbca2c044c4b58a96bd98 ] The maximum MTU value is determined by the maximum size of TX FIFO so that a full packet can fit in the FIFO. Add a check for this in the MTU change callback. Also check if provided and rounded MTU does not passes the maximum limit of 16K. Changes from v2: - Align MTU before checking if its valid Fixes: 7ac6653a085b ("stmmac: Move the STMicroelectronics driver") Signed-off-by: Jose Abreu Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index e6d16c48ffef..4ef923f1094a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -3597,12 +3597,24 @@ static void stmmac_set_rx_mode(struct net_device *dev) static int stmmac_change_mtu(struct net_device *dev, int new_mtu) { struct stmmac_priv *priv = netdev_priv(dev); + int txfifosz = priv->plat->tx_fifo_size; + + if (txfifosz == 0) + txfifosz = priv->dma_cap.tx_fifo_size; + + txfifosz /= priv->plat->tx_queues_to_use; if (netif_running(dev)) { netdev_err(priv->dev, "must be stopped to change its MTU\n"); return -EBUSY; } + new_mtu = STMMAC_ALIGN(new_mtu); + + /* If condition true, FIFO is too small or MTU too large */ + if ((txfifosz < new_mtu) || (new_mtu > BUF_SIZE_16KiB)) + return -EINVAL; + dev->mtu = new_mtu; netdev_update_features(dev); -- GitLab From f1cf84a64527c94c24e009e73bf2c38ce2361596 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Wed, 18 Dec 2019 11:17:40 +0100 Subject: [PATCH 0051/1055] net: stmmac: RX buffer size must be 16 byte aligned [ Upstream commit 8d558f0294fe92e04af192e221d0d0f6a180ee7b ] We need to align the RX buffer size to at least 16 byte so that IP doesn't mis-behave. This is required by HW. Changes from v2: - Align UP and not DOWN (David) Fixes: 7ac6653a085b ("stmmac: Move the STMicroelectronics driver") Signed-off-by: Jose Abreu Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 4ef923f1094a..e89466bd432d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -51,7 +51,7 @@ #include #include "dwmac1000.h" -#define STMMAC_ALIGN(x) __ALIGN_KERNEL(x, SMP_CACHE_BYTES) +#define STMMAC_ALIGN(x) ALIGN(ALIGN(x, SMP_CACHE_BYTES), 16) #define TSO_MAX_BUFF_SIZE (SZ_16K - 1) /* Module parameters */ -- GitLab From 29753fc2f8d0b406f2435c53f5e49c959c381ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B6ppner?= Date: Thu, 19 Dec 2019 09:43:50 +0100 Subject: [PATCH 0052/1055] s390/dasd/cio: Interpret ccw_device_get_mdc return value correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit dd4b3c83b9efac10d48a94c61372119fc555a077 ] The max data count (mdc) is an unsigned 16-bit integer value as per AR documentation and is received via ccw_device_get_mdc() for a specific path mask from the CIO layer. The function itself also always returns a positive mdc value or 0 in case mdc isn't supported or couldn't be determined. Though, the comment for this function describes a negative return value to indicate failures. As a result, the DASD device driver interprets the return value of ccw_device_get_mdc() incorrectly. The error case is essentially a dead code path. To fix this behaviour, check explicitly for a return value of 0 and change the comment for ccw_device_get_mdc() accordingly. This fix merely enables the error code path in the DASD functions get_fcx_max_data() and verify_fcx_max_data(). The actual functionality stays the same and is still correct. Reviewed-by: Cornelia Huck Signed-off-by: Jan Höppner Acked-by: Peter Oberparleiter Reviewed-by: Stefan Haberland Signed-off-by: Stefan Haberland Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/s390/block/dasd_eckd.c | 9 +++++---- drivers/s390/cio/device_ops.c | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 0d5e2d92e05b..81359312a987 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1133,7 +1133,8 @@ static u32 get_fcx_max_data(struct dasd_device *device) { struct dasd_eckd_private *private = device->private; int fcx_in_css, fcx_in_gneq, fcx_in_features; - int tpm, mdc; + unsigned int mdc; + int tpm; if (dasd_nofcx) return 0; @@ -1147,7 +1148,7 @@ static u32 get_fcx_max_data(struct dasd_device *device) return 0; mdc = ccw_device_get_mdc(device->cdev, 0); - if (mdc < 0) { + if (mdc == 0) { dev_warn(&device->cdev->dev, "Detecting the maximum supported data size for zHPF requests failed\n"); return 0; } else { @@ -1158,12 +1159,12 @@ static u32 get_fcx_max_data(struct dasd_device *device) static int verify_fcx_max_data(struct dasd_device *device, __u8 lpm) { struct dasd_eckd_private *private = device->private; - int mdc; + unsigned int mdc; u32 fcx_max_data; if (private->fcx_max_data) { mdc = ccw_device_get_mdc(device->cdev, lpm); - if ((mdc < 0)) { + if (mdc == 0) { dev_warn(&device->cdev->dev, "Detecting the maximum data size for zHPF " "requests failed (rc=%d) for a new path %x\n", diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index b22922ec32d1..474afec9ab87 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -595,7 +595,7 @@ EXPORT_SYMBOL(ccw_device_tm_start_timeout); * @mask: mask of paths to use * * Return the number of 64K-bytes blocks all paths at least support - * for a transport command. Return values <= 0 indicate failures. + * for a transport command. Return value 0 indicates failure. */ int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask) { -- GitLab From 66aa3bf42c2c009a14c3cf0214b95a32c11abc9e Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Thu, 19 Dec 2019 09:43:51 +0100 Subject: [PATCH 0053/1055] s390/dasd: fix memleak in path handling error case [ Upstream commit 00b39f698a4f1ee897227cace2e3937fc4412270 ] If for whatever reason the dasd_eckd_check_characteristics() function exits after at least some paths have their configuration data allocated those data is never freed again. In the error case the device->private pointer is set to NULL and dasd_eckd_uncheck_device() will exit without freeing the path data because of this NULL pointer. Fix by calling dasd_eckd_clear_conf_data() for error cases. Also use dasd_eckd_clear_conf_data() in dasd_eckd_uncheck_device() to avoid code duplication. Reported-by: Qian Cai Reviewed-by: Jan Hoeppner Signed-off-by: Stefan Haberland Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/s390/block/dasd_eckd.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 81359312a987..aa651403546f 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1768,7 +1768,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) dasd_free_block(device->block); device->block = NULL; out_err1: - kfree(private->conf_data); + dasd_eckd_clear_conf_data(device); kfree(device->private); device->private = NULL; return rc; @@ -1777,7 +1777,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device) static void dasd_eckd_uncheck_device(struct dasd_device *device) { struct dasd_eckd_private *private = device->private; - int i; if (!private) return; @@ -1787,21 +1786,7 @@ static void dasd_eckd_uncheck_device(struct dasd_device *device) private->sneq = NULL; private->vdsneq = NULL; private->gneq = NULL; - private->conf_len = 0; - for (i = 0; i < 8; i++) { - kfree(device->path[i].conf_data); - if ((__u8 *)device->path[i].conf_data == - private->conf_data) { - private->conf_data = NULL; - private->conf_len = 0; - } - device->path[i].conf_data = NULL; - device->path[i].cssid = 0; - device->path[i].ssid = 0; - device->path[i].chpid = 0; - } - kfree(private->conf_data); - private->conf_data = NULL; + dasd_eckd_clear_conf_data(device); } static struct dasd_ccw_req * -- GitLab From 62dfe5f55d2ca0b350fa76333fbb8a57b31c864a Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 18 Dec 2019 16:44:04 +0800 Subject: [PATCH 0054/1055] block: fix memleak when __blk_rq_map_user_iov() is failed [ Upstream commit 3b7995a98ad76da5597b488fa84aa5a56d43b608 ] When I doing fuzzy test, get the memleak report: BUG: memory leak unreferenced object 0xffff88837af80000 (size 4096): comm "memleak", pid 3557, jiffies 4294817681 (age 112.499s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 20 00 00 00 10 01 00 00 00 00 00 00 01 00 00 00 ............... backtrace: [<000000001c894df8>] bio_alloc_bioset+0x393/0x590 [<000000008b139a3c>] bio_copy_user_iov+0x300/0xcd0 [<00000000a998bd8c>] blk_rq_map_user_iov+0x2f1/0x5f0 [<000000005ceb7f05>] blk_rq_map_user+0xf2/0x160 [<000000006454da92>] sg_common_write.isra.21+0x1094/0x1870 [<00000000064bb208>] sg_write.part.25+0x5d9/0x950 [<000000004fc670f6>] sg_write+0x5f/0x8c [<00000000b0d05c7b>] __vfs_write+0x7c/0x100 [<000000008e177714>] vfs_write+0x1c3/0x500 [<0000000087d23f34>] ksys_write+0xf9/0x200 [<000000002c8dbc9d>] do_syscall_64+0x9f/0x4f0 [<00000000678d8e9a>] entry_SYSCALL_64_after_hwframe+0x49/0xbe If __blk_rq_map_user_iov() is failed in blk_rq_map_user_iov(), the bio(s) which is allocated before this failing will leak. The refcount of the bio(s) is init to 1 and increased to 2 by calling bio_get(), but __blk_rq_unmap_user() only decrease it to 1, so the bio cannot be freed. Fix it by calling blk_rq_unmap_user(). Reviewed-by: Bob Liu Reported-by: Hulk Robot Signed-off-by: Yang Yingliang Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- block/blk-map.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/blk-map.c b/block/blk-map.c index e31be14da8ea..f72a3af689b6 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -152,7 +152,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, return 0; unmap_rq: - __blk_rq_unmap_user(bio); + blk_rq_unmap_user(bio); fail: rq->bio = NULL; return ret; -- GitLab From 5d5d36505ddf5ad6d2d7b3d2486778b86f53efbc Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 20 Dec 2019 21:00:19 +0100 Subject: [PATCH 0055/1055] parisc: Fix compiler warnings in debug_core.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 75cf9797006a3a9f29a3a25c1febd6842a4a9eb2 ] Fix this compiler warning: kernel/debug/debug_core.c: In function ‘kgdb_cpu_enter’: arch/parisc/include/asm/cmpxchg.h:48:3: warning: value computed is not used [-Wunused-value] 48 | ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) arch/parisc/include/asm/atomic.h:78:30: note: in expansion of macro ‘xchg’ 78 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) | ^~~~ kernel/debug/debug_core.c:596:4: note: in expansion of macro ‘atomic_xchg’ 596 | atomic_xchg(&kgdb_active, cpu); | ^~~~~~~~~~~ Signed-off-by: Helge Deller Signed-off-by: Sasha Levin --- arch/parisc/include/asm/cmpxchg.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/parisc/include/asm/cmpxchg.h b/arch/parisc/include/asm/cmpxchg.h index f627c37dad9c..ab5c215cf46c 100644 --- a/arch/parisc/include/asm/cmpxchg.h +++ b/arch/parisc/include/asm/cmpxchg.h @@ -44,8 +44,14 @@ __xchg(unsigned long x, __volatile__ void *ptr, int size) ** if (((unsigned long)p & 0xf) == 0) ** return __ldcw(p); */ -#define xchg(ptr, x) \ - ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) +#define xchg(ptr, x) \ +({ \ + __typeof__(*(ptr)) __ret; \ + __typeof__(*(ptr)) _x_ = (x); \ + __ret = (__typeof__(*(ptr))) \ + __xchg((unsigned long)_x_, (ptr), sizeof(*(ptr))); \ + __ret; \ +}) /* bug catcher for when unsupported size is used - won't link */ extern void __cmpxchg_called_with_bad_pointer(void); -- GitLab From 3a8d4b961747e79a9d28e9f7621216045403b2bb Mon Sep 17 00:00:00 2001 From: "Chan Shu Tak, Alex" Date: Thu, 19 Dec 2019 14:16:18 +0800 Subject: [PATCH 0056/1055] llc2: Fix return statement of llc_stat_ev_rx_null_dsap_xid_c (and _test_c) [ Upstream commit af1c0e4e00f3cc76cb136ebf2e2c04e8b6446285 ] When a frame with NULL DSAP is received, llc_station_rcv is called. In turn, llc_stat_ev_rx_null_dsap_xid_c is called to check if it is a NULL XID frame. The return statement of llc_stat_ev_rx_null_dsap_xid_c returns 1 when the incoming frame is not a NULL XID frame and 0 otherwise. Hence, a NULL XID response is returned unexpectedly, e.g. when the incoming frame is a NULL TEST command. To fix the error, simply remove the conditional operator. A similar error in llc_stat_ev_rx_null_dsap_test_c is also fixed. Signed-off-by: Chan Shu Tak, Alex Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/llc/llc_station.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/llc/llc_station.c b/net/llc/llc_station.c index 204a8351efff..c29170e767a8 100644 --- a/net/llc/llc_station.c +++ b/net/llc/llc_station.c @@ -32,7 +32,7 @@ static int llc_stat_ev_rx_null_dsap_xid_c(struct sk_buff *skb) return LLC_PDU_IS_CMD(pdu) && /* command PDU */ LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID && - !pdu->dsap ? 0 : 1; /* NULL DSAP value */ + !pdu->dsap; /* NULL DSAP value */ } static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb) @@ -42,7 +42,7 @@ static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb) return LLC_PDU_IS_CMD(pdu) && /* command PDU */ LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */ LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST && - !pdu->dsap ? 0 : 1; /* NULL DSAP */ + !pdu->dsap; /* NULL DSAP */ } static int llc_station_ac_send_xid_r(struct sk_buff *skb) -- GitLab From 1051a28b7255e6624d379f2bd45713352f9470cf Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Thu, 19 Dec 2019 18:28:10 -0800 Subject: [PATCH 0057/1055] hv_netvsc: Fix unwanted rx_table reset [ Upstream commit b0689faa8efc5a3391402d7ae93bd373b7248e51 ] In existing code, the receive indirection table, rx_table, is in struct rndis_device, which will be reset when changing MTU, ringparam, etc. User configured receive indirection table values will be lost. To fix this, move rx_table to struct net_device_context, and check netif_is_rxfh_configured(), so rx_table will be set to default only if no user configured value. Fixes: ff4a44199012 ("netvsc: allow get/set of RSS indirection table") Signed-off-by: Haiyang Zhang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/hyperv/hyperv_net.h | 3 ++- drivers/net/hyperv/netvsc_drv.c | 4 ++-- drivers/net/hyperv/rndis_filter.c | 10 +++++++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 0f07b5978fa1..fc794e69e6a1 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -179,7 +179,6 @@ struct rndis_device { u8 hw_mac_adr[ETH_ALEN]; u8 rss_key[NETVSC_HASH_KEYLEN]; - u16 rx_table[ITAB_NUM]; }; @@ -741,6 +740,8 @@ struct net_device_context { u32 tx_table[VRSS_SEND_TAB_SIZE]; + u16 rx_table[ITAB_NUM]; + /* Ethtool settings */ bool udp4_l4_hash; bool udp6_l4_hash; diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 5a44b9795266..a89de5752a8c 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -1528,7 +1528,7 @@ static int netvsc_get_rxfh(struct net_device *dev, u32 *indir, u8 *key, rndis_dev = ndev->extension; if (indir) { for (i = 0; i < ITAB_NUM; i++) - indir[i] = rndis_dev->rx_table[i]; + indir[i] = ndc->rx_table[i]; } if (key) @@ -1558,7 +1558,7 @@ static int netvsc_set_rxfh(struct net_device *dev, const u32 *indir, return -EINVAL; for (i = 0; i < ITAB_NUM; i++) - rndis_dev->rx_table[i] = indir[i]; + ndc->rx_table[i] = indir[i]; } if (!key) { diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index fc1d5e14d83e..b19557c035f2 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -715,6 +715,7 @@ static int rndis_set_rss_param_msg(struct rndis_device *rdev, const u8 *rss_key, u16 flag) { struct net_device *ndev = rdev->ndev; + struct net_device_context *ndc = netdev_priv(ndev); struct rndis_request *request; struct rndis_set_request *set; struct rndis_set_complete *set_complete; @@ -754,7 +755,7 @@ static int rndis_set_rss_param_msg(struct rndis_device *rdev, /* Set indirection table entries */ itab = (u32 *)(rssp + 1); for (i = 0; i < ITAB_NUM; i++) - itab[i] = rdev->rx_table[i]; + itab[i] = ndc->rx_table[i]; /* Set hask key values */ keyp = (u8 *)((unsigned long)rssp + rssp->kashkey_offset); @@ -1204,6 +1205,7 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, struct netvsc_device_info *device_info) { struct net_device *net = hv_get_drvdata(dev); + struct net_device_context *ndc = netdev_priv(net); struct netvsc_device *net_device; struct rndis_device *rndis_device; struct ndis_recv_scale_cap rsscap; @@ -1286,9 +1288,11 @@ struct netvsc_device *rndis_filter_device_add(struct hv_device *dev, /* We will use the given number of channels if available. */ net_device->num_chn = min(net_device->max_chn, device_info->num_chn); - for (i = 0; i < ITAB_NUM; i++) - rndis_device->rx_table[i] = ethtool_rxfh_indir_default( + if (!netif_is_rxfh_configured(net)) { + for (i = 0; i < ITAB_NUM; i++) + ndc->rx_table[i] = ethtool_rxfh_indir_default( i, net_device->num_chn); + } atomic_set(&net_device->open_chn, 1); vmbus_set_sc_create_callback(dev->channel, netvsc_sc_open); -- GitLab From 7fed98f4a1e6eb77a5d66ecfdf9345e21df6ac82 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 7 Jun 2018 17:40:03 +0200 Subject: [PATCH 0058/1055] bpf: reject passing modified ctx to helper functions commit 58990d1ff3f7896ee341030e9a7c2e4002570683 upstream. As commit 28e33f9d78ee ("bpf: disallow arithmetic operations on context pointer") already describes, f1174f77b50c ("bpf/verifier: rework value tracking") removed the specific white-listed cases we had previously where we would allow for pointer arithmetic in order to further generalize it, and allow e.g. context access via modified registers. While the dereferencing of modified context pointers had been forbidden through 28e33f9d78ee, syzkaller did recently manage to trigger several KASAN splats for slab out of bounds access and use after frees by simply passing a modified context pointer to a helper function which would then do the bad access since verifier allowed it in adjust_ptr_min_max_vals(). Rejecting arithmetic on ctx pointer in adjust_ptr_min_max_vals() generally could break existing programs as there's a valid use case in tracing in combination with passing the ctx to helpers as bpf_probe_read(), where the register then becomes unknown at verification time due to adding a non-constant offset to it. An access sequence may look like the following: offset = args->filename; /* field __data_loc filename */ bpf_probe_read(&dst, len, (char *)args + offset); // args is ctx There are two options: i) we could special case the ctx and as soon as we add a constant or bounded offset to it (hence ctx type wouldn't change) we could turn the ctx into an unknown scalar, or ii) we generalize the sanity test for ctx member access into a small helper and assert it on the ctx register that was passed as a function argument. Fwiw, latter is more obvious and less complex at the same time, and one case that may potentially be legitimate in future for ctx member access at least would be for ctx to carry a const offset. Therefore, fix follows approach from ii) and adds test cases to BPF kselftests. Fixes: f1174f77b50c ("bpf/verifier: rework value tracking") Reported-by: syzbot+3d0b2441dbb71751615e@syzkaller.appspotmail.com Reported-by: syzbot+c8504affd4fdd0c1b626@syzkaller.appspotmail.com Reported-by: syzbot+e5190cb881d8660fb1a3@syzkaller.appspotmail.com Reported-by: syzbot+efae31b384d5badbd620@syzkaller.appspotmail.com Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Acked-by: Yonghong Song Acked-by: Edward Cree Signed-off-by: Alexei Starovoitov Signed-off-by: Greg Kroah-Hartman --- kernel/bpf/verifier.c | 45 ++++++++++------ tools/testing/selftests/bpf/test_verifier.c | 58 ++++++++++++++++++++- 2 files changed, 87 insertions(+), 16 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index a4875ff0bab1..be52b0529225 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1251,6 +1251,30 @@ static int check_ptr_alignment(struct bpf_verifier_env *env, return check_generic_ptr_alignment(reg, pointer_desc, off, size, strict); } +static int check_ctx_reg(struct bpf_verifier_env *env, + const struct bpf_reg_state *reg, int regno) +{ + /* Access to ctx or passing it to a helper is only allowed in + * its original, unmodified form. + */ + + if (reg->off) { + verbose("dereference of modified ctx ptr R%d off=%d disallowed\n", + regno, reg->off); + return -EACCES; + } + + if (!tnum_is_const(reg->var_off) || reg->var_off.value) { + char tn_buf[48]; + + tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); + verbose("variable ctx access var_off=%s disallowed\n", tn_buf); + return -EACCES; + } + + return 0; +} + /* truncate register to smaller size (in bytes) * must be called with size < BPF_REG_SIZE */ @@ -1320,22 +1344,10 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn verbose("R%d leaks addr into ctx\n", value_regno); return -EACCES; } - /* ctx accesses must be at a fixed offset, so that we can - * determine what type of data were returned. - */ - if (reg->off) { - verbose("dereference of modified ctx ptr R%d off=%d+%d, ctx+const is allowed, ctx+const+const is not\n", - regno, reg->off, off - reg->off); - return -EACCES; - } - if (!tnum_is_const(reg->var_off) || reg->var_off.value) { - char tn_buf[48]; + err = check_ctx_reg(env, reg, regno); + if (err < 0) + return err; - tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); - verbose("variable ctx access var_off=%s off=%d size=%d", - tn_buf, off, size); - return -EACCES; - } err = check_ctx_access(env, insn_idx, off, size, t, ®_type); if (!err && t == BPF_READ && value_regno >= 0) { /* ctx access returns either a scalar, or a @@ -1573,6 +1585,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, expected_type = PTR_TO_CTX; if (type != expected_type) goto err_type; + err = check_ctx_reg(env, reg, regno); + if (err < 0) + return err; } else if (arg_type == ARG_PTR_TO_MEM || arg_type == ARG_PTR_TO_UNINIT_MEM) { expected_type = PTR_TO_STACK; diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 913539aea645..9babb3fef8e2 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -7281,7 +7281,7 @@ static struct bpf_test tests[] = { offsetof(struct __sk_buff, mark)), BPF_EXIT_INSN(), }, - .errstr = "dereference of modified ctx ptr R1 off=68+8, ctx+const is allowed, ctx+const+const is not", + .errstr = "dereference of modified ctx ptr", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, @@ -7944,6 +7944,62 @@ static struct bpf_test tests[] = { .errstr = "BPF_XADD stores into R2 packet", .prog_type = BPF_PROG_TYPE_XDP, }, + { + "pass unmodified ctx pointer to helper", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_csum_update), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, + { + "pass modified ctx pointer to helper, 1", + .insns = { + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -612), + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_csum_update), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = REJECT, + .errstr = "dereference of modified ctx ptr", + }, + { + "pass modified ctx pointer to helper, 2", + .insns = { + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -612), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_socket_cookie), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result_unpriv = REJECT, + .result = REJECT, + .errstr_unpriv = "dereference of modified ctx ptr", + .errstr = "dereference of modified ctx ptr", + }, + { + "pass modified ctx pointer to helper, 3", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, 0), + BPF_ALU64_IMM(BPF_AND, BPF_REG_3, 4), + BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_csum_update), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = REJECT, + .errstr = "variable ctx access var_off=(0x0; 0x4)", + }, }; static int probe_filter_length(const struct bpf_insn *fp) -- GitLab From b454ac1b22af130c6fb8d34c344a98339f1cea9a Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 6 Jan 2020 22:51:57 +0100 Subject: [PATCH 0059/1055] bpf: Fix passing modified ctx to ld/abs/ind instruction commit 6d4f151acf9a4f6fab09b615f246c717ddedcf0c upstream. Anatoly has been fuzzing with kBdysch harness and reported a KASAN slab oob in one of the outcomes: [...] [ 77.359642] BUG: KASAN: slab-out-of-bounds in bpf_skb_load_helper_8_no_cache+0x71/0x130 [ 77.360463] Read of size 4 at addr ffff8880679bac68 by task bpf/406 [ 77.361119] [ 77.361289] CPU: 2 PID: 406 Comm: bpf Not tainted 5.5.0-rc2-xfstests-00157-g2187f215eba #1 [ 77.362134] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 [ 77.362984] Call Trace: [ 77.363249] dump_stack+0x97/0xe0 [ 77.363603] print_address_description.constprop.0+0x1d/0x220 [ 77.364251] ? bpf_skb_load_helper_8_no_cache+0x71/0x130 [ 77.365030] ? bpf_skb_load_helper_8_no_cache+0x71/0x130 [ 77.365860] __kasan_report.cold+0x37/0x7b [ 77.366365] ? bpf_skb_load_helper_8_no_cache+0x71/0x130 [ 77.366940] kasan_report+0xe/0x20 [ 77.367295] bpf_skb_load_helper_8_no_cache+0x71/0x130 [ 77.367821] ? bpf_skb_load_helper_8+0xf0/0xf0 [ 77.368278] ? mark_lock+0xa3/0x9b0 [ 77.368641] ? kvm_sched_clock_read+0x14/0x30 [ 77.369096] ? sched_clock+0x5/0x10 [ 77.369460] ? sched_clock_cpu+0x18/0x110 [ 77.369876] ? bpf_skb_load_helper_8+0xf0/0xf0 [ 77.370330] ___bpf_prog_run+0x16c0/0x28f0 [ 77.370755] __bpf_prog_run32+0x83/0xc0 [ 77.371153] ? __bpf_prog_run64+0xc0/0xc0 [ 77.371568] ? match_held_lock+0x1b/0x230 [ 77.371984] ? rcu_read_lock_held+0xa1/0xb0 [ 77.372416] ? rcu_is_watching+0x34/0x50 [ 77.372826] sk_filter_trim_cap+0x17c/0x4d0 [ 77.373259] ? sock_kzfree_s+0x40/0x40 [ 77.373648] ? __get_filter+0x150/0x150 [ 77.374059] ? skb_copy_datagram_from_iter+0x80/0x280 [ 77.374581] ? do_raw_spin_unlock+0xa5/0x140 [ 77.375025] unix_dgram_sendmsg+0x33a/0xa70 [ 77.375459] ? do_raw_spin_lock+0x1d0/0x1d0 [ 77.375893] ? unix_peer_get+0xa0/0xa0 [ 77.376287] ? __fget_light+0xa4/0xf0 [ 77.376670] __sys_sendto+0x265/0x280 [ 77.377056] ? __ia32_sys_getpeername+0x50/0x50 [ 77.377523] ? lock_downgrade+0x350/0x350 [ 77.377940] ? __sys_setsockopt+0x2a6/0x2c0 [ 77.378374] ? sock_read_iter+0x240/0x240 [ 77.378789] ? __sys_socketpair+0x22a/0x300 [ 77.379221] ? __ia32_sys_socket+0x50/0x50 [ 77.379649] ? mark_held_locks+0x1d/0x90 [ 77.380059] ? trace_hardirqs_on_thunk+0x1a/0x1c [ 77.380536] __x64_sys_sendto+0x74/0x90 [ 77.380938] do_syscall_64+0x68/0x2a0 [ 77.381324] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 77.381878] RIP: 0033:0x44c070 [...] After further debugging, turns out while in case of other helper functions we disallow passing modified ctx, the special case of ld/abs/ind instruction which has similar semantics (except r6 being the ctx argument) is missing such check. Modified ctx is impossible here as bpf_skb_load_helper_8_no_cache() and others are expecting skb fields in original position, hence, add check_ctx_reg() to reject any modified ctx. Issue was first introduced back in f1174f77b50c ("bpf/verifier: rework value tracking"). Fixes: f1174f77b50c ("bpf/verifier: rework value tracking") Reported-by: Anatoly Trosinenko Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20200106215157.3553-1-daniel@iogearbox.net Signed-off-by: Greg Kroah-Hartman --- kernel/bpf/verifier.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index be52b0529225..615a2e44d2a0 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3457,6 +3457,7 @@ static bool may_access_skb(enum bpf_prog_type type) static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) { struct bpf_reg_state *regs = cur_regs(env); + static const int ctx_reg = BPF_REG_6; u8 mode = BPF_MODE(insn->code); int i, err; @@ -3473,11 +3474,11 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) } /* check whether implicit source operand (register R6) is readable */ - err = check_reg_arg(env, BPF_REG_6, SRC_OP); + err = check_reg_arg(env, ctx_reg, SRC_OP); if (err) return err; - if (regs[BPF_REG_6].type != PTR_TO_CTX) { + if (regs[ctx_reg].type != PTR_TO_CTX) { verbose("at the time of BPF_LD_ABS|IND R6 != pointer to skb\n"); return -EINVAL; } @@ -3489,6 +3490,10 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) return err; } + err = check_ctx_reg(env, ®s[ctx_reg], ctx_reg); + if (err < 0) + return err; + /* reset caller saved regs to unreadable */ for (i = 0; i < CALLER_SAVED_REGS; i++) { mark_reg_not_init(regs, caller_saved[i]); -- GitLab From e9eae4143c33ebe33aa2e195c2863c6e1bf3f8cd Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Tue, 10 Sep 2019 13:58:33 -0600 Subject: [PATCH 0060/1055] PCI/switchtec: Read all 64 bits of part_event_bitmap commit 6acdf7e19b37cb3a9258603d0eab315079c19c5e upstream. The part_event_bitmap register is 64 bits wide, so read it with ioread64() instead of the 32-bit ioread32(). Fixes: 52eabba5bcdb ("switchtec: Add IOCTLs to the Switchtec driver") Link: https://lore.kernel.org/r/20190910195833.3891-1-logang@deltatee.com Reported-by: Doug Meyer Signed-off-by: Logan Gunthorpe Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org # v4.12+ Cc: Kelvin Cao Signed-off-by: Greg Kroah-Hartman --- drivers/pci/switch/switchtec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index e3aefdafae89..0941555b84a5 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -23,7 +23,7 @@ #include #include #include - +#include #include MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver"); @@ -898,7 +898,7 @@ static int ioctl_event_summary(struct switchtec_dev *stdev, u32 reg; s.global = ioread32(&stdev->mmio_sw_event->global_summary); - s.part_bitmap = ioread32(&stdev->mmio_sw_event->part_event_bitmap); + s.part_bitmap = readq(&stdev->mmio_sw_event->part_event_bitmap); s.local_part = ioread32(&stdev->mmio_part_cfg->part_event_summary); for (i = 0; i < stdev->partition_count; i++) { -- GitLab From 37d58689dfdd068c2f15f90d573f8e93fe28cf86 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 20 Sep 2017 10:02:00 +0200 Subject: [PATCH 0061/1055] mmc: block: Convert RPMB to a character device commit 97548575bef38abd06690a5a6f6816200c7e77f7 upstream. The RPMB partition on the eMMC devices is a special area used for storing cryptographically safe information signed by a special secret key. To write and read records from this special area, authentication is needed. The RPMB area is *only* and *exclusively* accessed using ioctl():s from userspace. It is not really a block device, as blocks cannot be read or written from the device, also the signed chunks that can be stored on the RPMB are actually 256 bytes, not 512 making a block device a real bad fit. Currently the RPMB partition spawns a separate block device named /dev/mmcblkNrpmb for each device with an RPMB partition, including the creation of a block queue with its own kernel thread and all overhead associated with this. On the Ux500 HREFv60 platform, for example, the two eMMCs means that two block queues with separate threads are created for no use whatsoever. I have concluded that this block device design for RPMB is actually pretty wrong. The RPMB area should have been designed to be accessed from /dev/mmcblkN directly, using ioctl()s on the main block device. It is however way too late to change that, since userspace expects to open an RPMB device in /dev/mmcblkNrpmb and we cannot break userspace. This patch tries to amend the situation using the following strategy: - Stop creating a block device for the RPMB partition/area - Instead create a custom, dynamic character device with the same name. - Make this new character device support exactly the same set of ioctl()s as the old block device. - Wrap the requests back to the same ioctl() handlers, but issue them on the block queue of the main partition/area, i.e. /dev/mmcblkN We need to create a special "rpmb" bus type in order to get udev and/or busybox hot/coldplug to instantiate the device node properly. Before the patch, this appears in 'ps aux': 101 root 0:00 [mmcqd/2rpmb] 123 root 0:00 [mmcqd/3rpmb] After applying the patch these surplus block queue threads are gone, but RPMB is as usable as ever using the userspace MMC tools, such as 'mmc rpmb read-counter'. We get instead those dynamice devices in /dev: brw-rw---- 1 root root 179, 0 Jan 1 2000 mmcblk0 brw-rw---- 1 root root 179, 1 Jan 1 2000 mmcblk0p1 brw-rw---- 1 root root 179, 2 Jan 1 2000 mmcblk0p2 brw-rw---- 1 root root 179, 5 Jan 1 2000 mmcblk0p5 brw-rw---- 1 root root 179, 8 Jan 1 2000 mmcblk2 brw-rw---- 1 root root 179, 16 Jan 1 2000 mmcblk2boot0 brw-rw---- 1 root root 179, 24 Jan 1 2000 mmcblk2boot1 crw-rw---- 1 root root 248, 0 Jan 1 2000 mmcblk2rpmb brw-rw---- 1 root root 179, 32 Jan 1 2000 mmcblk3 brw-rw---- 1 root root 179, 40 Jan 1 2000 mmcblk3boot0 brw-rw---- 1 root root 179, 48 Jan 1 2000 mmcblk3boot1 brw-rw---- 1 root root 179, 33 Jan 1 2000 mmcblk3p1 crw-rw---- 1 root root 248, 1 Jan 1 2000 mmcblk3rpmb Notice the (248,0) and (248,1) character devices for RPMB. Cc: Tomas Winkler Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson Cc: Jisheng Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/block.c | 283 ++++++++++++++++++++++++++++++++++++--- drivers/mmc/core/queue.h | 2 + 2 files changed, 263 insertions(+), 22 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index ce6dd49fbb98..0c29605dd829 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -87,6 +88,7 @@ static int max_devices; #define MAX_DEVICES 256 static DEFINE_IDA(mmc_blk_ida); +static DEFINE_IDA(mmc_rpmb_ida); /* * There is one mmc_blk_data per slot. @@ -97,6 +99,7 @@ struct mmc_blk_data { struct gendisk *disk; struct mmc_queue queue; struct list_head part; + struct list_head rpmbs; unsigned int flags; #define MMC_BLK_CMD23 (1 << 0) /* Can do SET_BLOCK_COUNT for multiblock */ @@ -126,6 +129,32 @@ struct mmc_blk_data { struct dentry *ext_csd_dentry; }; +/* Device type for RPMB character devices */ +static dev_t mmc_rpmb_devt; + +/* Bus type for RPMB character devices */ +static struct bus_type mmc_rpmb_bus_type = { + .name = "mmc_rpmb", +}; + +/** + * struct mmc_rpmb_data - special RPMB device type for these areas + * @dev: the device for the RPMB area + * @chrdev: character device for the RPMB area + * @id: unique device ID number + * @part_index: partition index (0 on first) + * @md: parent MMC block device + * @node: list item, so we can put this device on a list + */ +struct mmc_rpmb_data { + struct device dev; + struct cdev chrdev; + int id; + unsigned int part_index; + struct mmc_blk_data *md; + struct list_head node; +}; + static DEFINE_MUTEX(open_lock); module_param(perdev_minors, int, 0444); @@ -309,6 +338,7 @@ struct mmc_blk_ioc_data { struct mmc_ioc_cmd ic; unsigned char *buf; u64 buf_bytes; + struct mmc_rpmb_data *rpmb; }; static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( @@ -447,14 +477,25 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, struct mmc_request mrq = {}; struct scatterlist sg; int err; - bool is_rpmb = false; + unsigned int target_part; u32 status = 0; if (!card || !md || !idata) return -EINVAL; - if (md->area_type & MMC_BLK_DATA_AREA_RPMB) - is_rpmb = true; + /* + * The RPMB accesses comes in from the character device, so we + * need to target these explicitly. Else we just target the + * partition type for the block device the ioctl() was issued + * on. + */ + if (idata->rpmb) { + /* Support multiple RPMB partitions */ + target_part = idata->rpmb->part_index; + target_part |= EXT_CSD_PART_CONFIG_ACC_RPMB; + } else { + target_part = md->part_type; + } cmd.opcode = idata->ic.opcode; cmd.arg = idata->ic.arg; @@ -498,7 +539,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, mrq.cmd = &cmd; - err = mmc_blk_part_switch(card, md->part_type); + err = mmc_blk_part_switch(card, target_part); if (err) return err; @@ -508,7 +549,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, return err; } - if (is_rpmb) { + if (idata->rpmb) { err = mmc_set_blockcount(card, data.blocks, idata->ic.write_flag & (1 << 31)); if (err) @@ -566,7 +607,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp)); - if (is_rpmb) { + if (idata->rpmb) { /* * Ensure RPMB command has completed by polling CMD13 * "Send Status". @@ -582,7 +623,8 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md, } static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, - struct mmc_ioc_cmd __user *ic_ptr) + struct mmc_ioc_cmd __user *ic_ptr, + struct mmc_rpmb_data *rpmb) { struct mmc_blk_ioc_data *idata; struct mmc_blk_ioc_data *idatas[1]; @@ -594,6 +636,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, idata = mmc_blk_ioctl_copy_from_user(ic_ptr); if (IS_ERR(idata)) return PTR_ERR(idata); + /* This will be NULL on non-RPMB ioctl():s */ + idata->rpmb = rpmb; card = md->queue.card; if (IS_ERR(card)) { @@ -613,7 +657,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, goto cmd_done; } idatas[0] = idata; - req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; + req_to_mmc_queue_req(req)->drv_op = + rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL; req_to_mmc_queue_req(req)->drv_op_data = idatas; req_to_mmc_queue_req(req)->ioc_count = 1; blk_execute_rq(mq->queue, NULL, req, 0); @@ -628,7 +673,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md, } static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, - struct mmc_ioc_multi_cmd __user *user) + struct mmc_ioc_multi_cmd __user *user, + struct mmc_rpmb_data *rpmb) { struct mmc_blk_ioc_data **idata = NULL; struct mmc_ioc_cmd __user *cmds = user->cmds; @@ -659,6 +705,8 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, num_of_cmds = i; goto cmd_err; } + /* This will be NULL on non-RPMB ioctl():s */ + idata[i]->rpmb = rpmb; } card = md->queue.card; @@ -679,7 +727,8 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md, err = PTR_ERR(req); goto cmd_err; } - req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL; + req_to_mmc_queue_req(req)->drv_op = + rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL; req_to_mmc_queue_req(req)->drv_op_data = idata; req_to_mmc_queue_req(req)->ioc_count = num_of_cmds; blk_execute_rq(mq->queue, NULL, req, 0); @@ -727,7 +776,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, if (!md) return -EINVAL; ret = mmc_blk_ioctl_cmd(md, - (struct mmc_ioc_cmd __user *)arg); + (struct mmc_ioc_cmd __user *)arg, + NULL); mmc_blk_put(md); return ret; case MMC_IOC_MULTI_CMD: @@ -738,7 +788,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode, if (!md) return -EINVAL; ret = mmc_blk_ioctl_multi_cmd(md, - (struct mmc_ioc_multi_cmd __user *)arg); + (struct mmc_ioc_multi_cmd __user *)arg, + NULL); mmc_blk_put(md); return ret; default: @@ -1210,17 +1261,19 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) struct mmc_queue_req *mq_rq; struct mmc_card *card = mq->card; struct mmc_blk_data *md = mq->blkdata; - struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev); struct mmc_blk_ioc_data **idata; + bool rpmb_ioctl; u8 **ext_csd; u32 status; int ret; int i; mq_rq = req_to_mmc_queue_req(req); + rpmb_ioctl = (mq_rq->drv_op == MMC_DRV_OP_IOCTL_RPMB); switch (mq_rq->drv_op) { case MMC_DRV_OP_IOCTL: + case MMC_DRV_OP_IOCTL_RPMB: idata = mq_rq->drv_op_data; for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) { ret = __mmc_blk_ioctl_cmd(card, md, idata[i]); @@ -1228,8 +1281,8 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) break; } /* Always switch back to main area after RPMB access */ - if (md->area_type & MMC_BLK_DATA_AREA_RPMB) - mmc_blk_part_switch(card, main_md->part_type); + if (rpmb_ioctl) + mmc_blk_part_switch(card, 0); break; case MMC_DRV_OP_BOOT_WP: ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, @@ -2114,6 +2167,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, spin_lock_init(&md->lock); INIT_LIST_HEAD(&md->part); + INIT_LIST_HEAD(&md->rpmbs); md->usage = 1; ret = mmc_init_queue(&md->queue, card, &md->lock, subname); @@ -2232,6 +2286,154 @@ static int mmc_blk_alloc_part(struct mmc_card *card, return 0; } +/** + * mmc_rpmb_ioctl() - ioctl handler for the RPMB chardev + * @filp: the character device file + * @cmd: the ioctl() command + * @arg: the argument from userspace + * + * This will essentially just redirect the ioctl()s coming in over to + * the main block device spawning the RPMB character device. + */ +static long mmc_rpmb_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct mmc_rpmb_data *rpmb = filp->private_data; + int ret; + + switch (cmd) { + case MMC_IOC_CMD: + ret = mmc_blk_ioctl_cmd(rpmb->md, + (struct mmc_ioc_cmd __user *)arg, + rpmb); + break; + case MMC_IOC_MULTI_CMD: + ret = mmc_blk_ioctl_multi_cmd(rpmb->md, + (struct mmc_ioc_multi_cmd __user *)arg, + rpmb); + break; + default: + ret = -EINVAL; + break; + } + + return 0; +} + +#ifdef CONFIG_COMPAT +static long mmc_rpmb_ioctl_compat(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return mmc_rpmb_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + +static int mmc_rpmb_chrdev_open(struct inode *inode, struct file *filp) +{ + struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev, + struct mmc_rpmb_data, chrdev); + + get_device(&rpmb->dev); + filp->private_data = rpmb; + mutex_lock(&open_lock); + rpmb->md->usage++; + mutex_unlock(&open_lock); + + return nonseekable_open(inode, filp); +} + +static int mmc_rpmb_chrdev_release(struct inode *inode, struct file *filp) +{ + struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev, + struct mmc_rpmb_data, chrdev); + + put_device(&rpmb->dev); + mutex_lock(&open_lock); + rpmb->md->usage--; + mutex_unlock(&open_lock); + + return 0; +} + +static const struct file_operations mmc_rpmb_fileops = { + .release = mmc_rpmb_chrdev_release, + .open = mmc_rpmb_chrdev_open, + .owner = THIS_MODULE, + .llseek = no_llseek, + .unlocked_ioctl = mmc_rpmb_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = mmc_rpmb_ioctl_compat, +#endif +}; + + +static int mmc_blk_alloc_rpmb_part(struct mmc_card *card, + struct mmc_blk_data *md, + unsigned int part_index, + sector_t size, + const char *subname) +{ + int devidx, ret; + char rpmb_name[DISK_NAME_LEN]; + char cap_str[10]; + struct mmc_rpmb_data *rpmb; + + /* This creates the minor number for the RPMB char device */ + devidx = ida_simple_get(&mmc_rpmb_ida, 0, max_devices, GFP_KERNEL); + if (devidx < 0) + return devidx; + + rpmb = kzalloc(sizeof(*rpmb), GFP_KERNEL); + if (!rpmb) + return -ENOMEM; + + snprintf(rpmb_name, sizeof(rpmb_name), + "mmcblk%u%s", card->host->index, subname ? subname : ""); + + rpmb->id = devidx; + rpmb->part_index = part_index; + rpmb->dev.init_name = rpmb_name; + rpmb->dev.bus = &mmc_rpmb_bus_type; + rpmb->dev.devt = MKDEV(MAJOR(mmc_rpmb_devt), rpmb->id); + rpmb->dev.parent = &card->dev; + device_initialize(&rpmb->dev); + dev_set_drvdata(&rpmb->dev, rpmb); + rpmb->md = md; + + cdev_init(&rpmb->chrdev, &mmc_rpmb_fileops); + rpmb->chrdev.owner = THIS_MODULE; + ret = cdev_device_add(&rpmb->chrdev, &rpmb->dev); + if (ret) { + pr_err("%s: could not add character device\n", rpmb_name); + goto out_remove_ida; + } + + list_add(&rpmb->node, &md->rpmbs); + + string_get_size((u64)size, 512, STRING_UNITS_2, + cap_str, sizeof(cap_str)); + + pr_info("%s: %s %s partition %u %s, chardev (%d:%d)\n", + rpmb_name, mmc_card_id(card), + mmc_card_name(card), EXT_CSD_PART_CONFIG_ACC_RPMB, cap_str, + MAJOR(mmc_rpmb_devt), rpmb->id); + + return 0; + +out_remove_ida: + ida_simple_remove(&mmc_rpmb_ida, rpmb->id); + kfree(rpmb); + return ret; +} + +static void mmc_blk_remove_rpmb_part(struct mmc_rpmb_data *rpmb) +{ + cdev_device_del(&rpmb->chrdev, &rpmb->dev); + device_del(&rpmb->dev); + ida_simple_remove(&mmc_rpmb_ida, rpmb->id); + kfree(rpmb); +} + /* MMC Physical partitions consist of two boot partitions and * up to four general purpose partitions. * For each partition enabled in EXT_CSD a block device will be allocatedi @@ -2240,13 +2442,26 @@ static int mmc_blk_alloc_part(struct mmc_card *card, static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) { - int idx, ret = 0; + int idx, ret; if (!mmc_card_mmc(card)) return 0; for (idx = 0; idx < card->nr_parts; idx++) { - if (card->part[idx].size) { + if (card->part[idx].area_type & MMC_BLK_DATA_AREA_RPMB) { + /* + * RPMB partitions does not provide block access, they + * are only accessed using ioctl():s. Thus create + * special RPMB block devices that do not have a + * backing block queue for these. + */ + ret = mmc_blk_alloc_rpmb_part(card, md, + card->part[idx].part_cfg, + card->part[idx].size >> 9, + card->part[idx].name); + if (ret) + return ret; + } else if (card->part[idx].size) { ret = mmc_blk_alloc_part(card, md, card->part[idx].part_cfg, card->part[idx].size >> 9, @@ -2258,7 +2473,7 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) } } - return ret; + return 0; } static void mmc_blk_remove_req(struct mmc_blk_data *md) @@ -2295,7 +2510,15 @@ static void mmc_blk_remove_parts(struct mmc_card *card, { struct list_head *pos, *q; struct mmc_blk_data *part_md; + struct mmc_rpmb_data *rpmb; + /* Remove RPMB partitions */ + list_for_each_safe(pos, q, &md->rpmbs) { + rpmb = list_entry(pos, struct mmc_rpmb_data, node); + list_del(pos); + mmc_blk_remove_rpmb_part(rpmb); + } + /* Remove block partitions */ list_for_each_safe(pos, q, &md->part) { part_md = list_entry(pos, struct mmc_blk_data, part); list_del(pos); @@ -2649,6 +2872,17 @@ static int __init mmc_blk_init(void) { int res; + res = bus_register(&mmc_rpmb_bus_type); + if (res < 0) { + pr_err("mmcblk: could not register RPMB bus type\n"); + return res; + } + res = alloc_chrdev_region(&mmc_rpmb_devt, 0, MAX_DEVICES, "rpmb"); + if (res < 0) { + pr_err("mmcblk: failed to allocate rpmb chrdev region\n"); + goto out_bus_unreg; + } + if (perdev_minors != CONFIG_MMC_BLOCK_MINORS) pr_info("mmcblk: using %d minors per device\n", perdev_minors); @@ -2656,16 +2890,20 @@ static int __init mmc_blk_init(void) res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); if (res) - goto out; + goto out_chrdev_unreg; res = mmc_register_driver(&mmc_driver); if (res) - goto out2; + goto out_blkdev_unreg; return 0; - out2: + +out_blkdev_unreg: unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); - out: +out_chrdev_unreg: + unregister_chrdev_region(mmc_rpmb_devt, MAX_DEVICES); +out_bus_unreg: + bus_unregister(&mmc_rpmb_bus_type); return res; } @@ -2673,6 +2911,7 @@ static void __exit mmc_blk_exit(void) { mmc_unregister_driver(&mmc_driver); unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); + unregister_chrdev_region(mmc_rpmb_devt, MAX_DEVICES); } module_init(mmc_blk_init); diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index 6bfba32ffa66..15c80421321e 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -36,12 +36,14 @@ struct mmc_blk_request { /** * enum mmc_drv_op - enumerates the operations in the mmc_queue_req * @MMC_DRV_OP_IOCTL: ioctl operation + * @MMC_DRV_OP_IOCTL_RPMB: RPMB-oriented ioctl operation * @MMC_DRV_OP_BOOT_WP: write protect boot partitions * @MMC_DRV_OP_GET_CARD_STATUS: get card status * @MMC_DRV_OP_GET_EXT_CSD: get the EXT CSD from an eMMC card */ enum mmc_drv_op { MMC_DRV_OP_IOCTL, + MMC_DRV_OP_IOCTL_RPMB, MMC_DRV_OP_BOOT_WP, MMC_DRV_OP_GET_CARD_STATUS, MMC_DRV_OP_GET_EXT_CSD, -- GitLab From ae4e8ce0d86159bbba7cfaa44f6276d38b1f2200 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 20 Sep 2017 10:02:01 +0200 Subject: [PATCH 0062/1055] mmc: block: Delete mmc_access_rpmb() commit 14f4ca7e4d2825f9f71e22905ae177b899959f1d upstream. This function is used by the block layer queue to bail out of requests if the current request is towards an RPMB "block device". This was done to avoid boot time scanning of this "block device" which was never really a block device, thus duct-taping over the fact that it was badly engineered. This problem is now gone as we removed the offending RPMB block device in another patch and replaced it with a character device. Cc: Tomas Winkler Signed-off-by: Linus Walleij Signed-off-by: Ulf Hansson Cc: Jisheng Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/block.c | 12 ------------ drivers/mmc/core/queue.c | 2 +- drivers/mmc/core/queue.h | 2 -- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 0c29605dd829..b3d8717963d8 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -1239,18 +1239,6 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type) md->reset_done &= ~type; } -int mmc_access_rpmb(struct mmc_queue *mq) -{ - struct mmc_blk_data *md = mq->blkdata; - /* - * If this is a RPMB partition access, return ture - */ - if (md && md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB) - return true; - - return false; -} - /* * The non-block commands come back from the block layer after it queued it and * processed it with all other requests and then they get issued in this diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 0a4e77a5ba33..f74f9ef460cc 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -30,7 +30,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) { struct mmc_queue *mq = q->queuedata; - if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq))) + if (mq && mmc_card_removed(mq->card)) return BLKPREP_KILL; req->rq_flags |= RQF_DONTPREP; diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h index 15c80421321e..547b457c4251 100644 --- a/drivers/mmc/core/queue.h +++ b/drivers/mmc/core/queue.h @@ -84,6 +84,4 @@ extern void mmc_queue_resume(struct mmc_queue *); extern unsigned int mmc_queue_map_sg(struct mmc_queue *, struct mmc_queue_req *); -extern int mmc_access_rpmb(struct mmc_queue *); - #endif -- GitLab From 3879a509ac7f02e0ba899d22cad53d366b656f67 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 4 Oct 2017 11:10:07 +0200 Subject: [PATCH 0063/1055] mmc: block: Fix bug when removing RPMB chardev commit 1c87f73578497a6c3cc77bcbfd2e5bf15fe753c7 upstream. I forgot to account for the fact that the device core holds a reference to a device added with device_initialize() that need to be released with a corresponding put_device() to reach a 0 refcount at the end of the lifecycle. This led to a NULL pointer reference when freeing the device when e.g. unbidning the host device in sysfs. Fix this and use the device .release() callback to free the IDA and free:ing the memory used by the RPMB device. Before this patch: /sys/bus/amba/drivers/mmci-pl18x$ echo 80114000.sdi4_per2 > unbind [ 29.797332] mmc3: card 0001 removed [ 29.810791] Unable to handle kernel NULL pointer dereference at virtual address 00000050 [ 29.818878] pgd = de70c000 [ 29.821624] [00000050] *pgd=1e70a831, *pte=00000000, *ppte=00000000 [ 29.827911] Internal error: Oops: 17 [#1] PREEMPT SMP ARM [ 29.833282] Modules linked in: [ 29.836334] CPU: 1 PID: 154 Comm: sh Not tainted 4.14.0-rc3-00039-g83318e309566-dirty #736 [ 29.844604] Hardware name: ST-Ericsson Ux5x0 platform (Device Tree Support) [ 29.851562] task: de572700 task.stack: de742000 [ 29.856079] PC is at kernfs_find_ns+0x8/0x100 [ 29.860443] LR is at kernfs_find_and_get_ns+0x30/0x48 After this patch: /sys/bus/amba/drivers/mmci-pl18x$ echo 80005000.sdi4_per2 > unbind [ 20.623382] mmc3: card 0001 removed Fixes: 97548575bef3 ("mmc: block: Convert RPMB to a character device") Reported-by: Adrian Hunter Signed-off-by: Linus Walleij Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson Cc: Jisheng Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/block.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index b3d8717963d8..df9903ee1fae 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -2323,9 +2323,7 @@ static int mmc_rpmb_chrdev_open(struct inode *inode, struct file *filp) get_device(&rpmb->dev); filp->private_data = rpmb; - mutex_lock(&open_lock); - rpmb->md->usage++; - mutex_unlock(&open_lock); + mmc_blk_get(rpmb->md->disk); return nonseekable_open(inode, filp); } @@ -2336,9 +2334,7 @@ static int mmc_rpmb_chrdev_release(struct inode *inode, struct file *filp) struct mmc_rpmb_data, chrdev); put_device(&rpmb->dev); - mutex_lock(&open_lock); - rpmb->md->usage--; - mutex_unlock(&open_lock); + mmc_blk_put(rpmb->md); return 0; } @@ -2354,6 +2350,13 @@ static const struct file_operations mmc_rpmb_fileops = { #endif }; +static void mmc_blk_rpmb_device_release(struct device *dev) +{ + struct mmc_rpmb_data *rpmb = dev_get_drvdata(dev); + + ida_simple_remove(&mmc_rpmb_ida, rpmb->id); + kfree(rpmb); +} static int mmc_blk_alloc_rpmb_part(struct mmc_card *card, struct mmc_blk_data *md, @@ -2372,8 +2375,10 @@ static int mmc_blk_alloc_rpmb_part(struct mmc_card *card, return devidx; rpmb = kzalloc(sizeof(*rpmb), GFP_KERNEL); - if (!rpmb) + if (!rpmb) { + ida_simple_remove(&mmc_rpmb_ida, devidx); return -ENOMEM; + } snprintf(rpmb_name, sizeof(rpmb_name), "mmcblk%u%s", card->host->index, subname ? subname : ""); @@ -2384,6 +2389,7 @@ static int mmc_blk_alloc_rpmb_part(struct mmc_card *card, rpmb->dev.bus = &mmc_rpmb_bus_type; rpmb->dev.devt = MKDEV(MAJOR(mmc_rpmb_devt), rpmb->id); rpmb->dev.parent = &card->dev; + rpmb->dev.release = mmc_blk_rpmb_device_release; device_initialize(&rpmb->dev); dev_set_drvdata(&rpmb->dev, rpmb); rpmb->md = md; @@ -2393,7 +2399,7 @@ static int mmc_blk_alloc_rpmb_part(struct mmc_card *card, ret = cdev_device_add(&rpmb->chrdev, &rpmb->dev); if (ret) { pr_err("%s: could not add character device\n", rpmb_name); - goto out_remove_ida; + goto out_put_device; } list_add(&rpmb->node, &md->rpmbs); @@ -2408,18 +2414,16 @@ static int mmc_blk_alloc_rpmb_part(struct mmc_card *card, return 0; -out_remove_ida: - ida_simple_remove(&mmc_rpmb_ida, rpmb->id); - kfree(rpmb); +out_put_device: + put_device(&rpmb->dev); return ret; } static void mmc_blk_remove_rpmb_part(struct mmc_rpmb_data *rpmb) + { cdev_device_del(&rpmb->chrdev, &rpmb->dev); - device_del(&rpmb->dev); - ida_simple_remove(&mmc_rpmb_ida, rpmb->id); - kfree(rpmb); + put_device(&rpmb->dev); } /* MMC Physical partitions consist of two boot partitions and -- GitLab From a52f6b2f57b6695fa46d1b3cb37c54e16efabf53 Mon Sep 17 00:00:00 2001 From: Alexander Kappner Date: Wed, 28 Mar 2018 15:18:31 -0700 Subject: [PATCH 0064/1055] mmc: core: Prevent bus reference leak in mmc_blk_init() commit d0a0852b9f81cf5f793bf2eae7336ed40a1a1815 upstream. Upon module load, mmc_block allocates a bus with bus_registeri() in mmc_blk_init(). This reference never gets freed during module unload, which leads to subsequent re-insertions of the module fails and a WARN() splat is triggered. Fix the bug by dropping the reference for the bus in mmc_blk_exit(). Signed-off-by: Alexander Kappner Fixes: 97548575bef3 ("mmc: block: Convert RPMB to a character device") Cc: Reviewed-by: Shawn Lin Signed-off-by: Ulf Hansson Cc: Jisheng Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/block.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index df9903ee1fae..a9ce192828b8 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -2904,6 +2904,7 @@ static void __exit mmc_blk_exit(void) mmc_unregister_driver(&mmc_driver); unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); unregister_chrdev_region(mmc_rpmb_devt, MAX_DEVICES); + bus_unregister(&mmc_rpmb_bus_type); } module_init(mmc_blk_init); -- GitLab From 0f65291617d4117379ba702130040d2db283c2fb Mon Sep 17 00:00:00 2001 From: Mathieu Malaterre Date: Wed, 16 May 2018 21:20:20 +0200 Subject: [PATCH 0065/1055] mmc: block: propagate correct returned value in mmc_rpmb_ioctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b25b750df99bcba29317d3f9d9f93c4ec58890e6 upstream. In commit 97548575bef3 ("mmc: block: Convert RPMB to a character device") a new function `mmc_rpmb_ioctl` was added. The final return is simply returning a value of `0` instead of propagating the correct return code. Discovered during a compilation with W=1, silence the following gcc warning drivers/mmc/core/block.c:2470:6: warning: variable ‘ret’ set but not used [-Wunused-but-set-variable] Signed-off-by: Mathieu Malaterre Reviewed-by: Shawn Lin Fixes: 97548575bef3 ("mmc: block: Convert RPMB to a character device") Cc: stable@vger.kernel.org # v4.15+ Signed-off-by: Ulf Hansson Cc: Jisheng Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index a9ce192828b8..916b88ee2de4 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -2305,7 +2305,7 @@ static long mmc_rpmb_ioctl(struct file *filp, unsigned int cmd, break; } - return 0; + return ret; } #ifdef CONFIG_COMPAT -- GitLab From 887b0296a905f8d5cc090ca08d309918fc24bf24 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 6 Jan 2020 06:45:37 -0800 Subject: [PATCH 0066/1055] gtp: fix bad unlock balance in gtp_encap_enable_socket [ Upstream commit 90d72256addff9e5f8ad645e8f632750dd1f8935 ] WARNING: bad unlock balance detected! 5.5.0-rc5-syzkaller #0 Not tainted ------------------------------------- syz-executor921/9688 is trying to release lock (sk_lock-AF_INET6) at: [] gtp_encap_enable_socket+0x146/0x400 drivers/net/gtp.c:830 but there are no more locks to release! other info that might help us debug this: 2 locks held by syz-executor921/9688: #0: ffffffff8a4d8840 (rtnl_mutex){+.+.}, at: rtnl_lock net/core/rtnetlink.c:72 [inline] #0: ffffffff8a4d8840 (rtnl_mutex){+.+.}, at: rtnetlink_rcv_msg+0x405/0xaf0 net/core/rtnetlink.c:5421 #1: ffff88809304b560 (slock-AF_INET6){+...}, at: spin_lock_bh include/linux/spinlock.h:343 [inline] #1: ffff88809304b560 (slock-AF_INET6){+...}, at: release_sock+0x20/0x1c0 net/core/sock.c:2951 stack backtrace: CPU: 0 PID: 9688 Comm: syz-executor921 Not tainted 5.5.0-rc5-syzkaller #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+0x197/0x210 lib/dump_stack.c:118 print_unlock_imbalance_bug kernel/locking/lockdep.c:4008 [inline] print_unlock_imbalance_bug.cold+0x114/0x123 kernel/locking/lockdep.c:3984 __lock_release kernel/locking/lockdep.c:4242 [inline] lock_release+0x5f2/0x960 kernel/locking/lockdep.c:4503 sock_release_ownership include/net/sock.h:1496 [inline] release_sock+0x17c/0x1c0 net/core/sock.c:2961 gtp_encap_enable_socket+0x146/0x400 drivers/net/gtp.c:830 gtp_encap_enable drivers/net/gtp.c:852 [inline] gtp_newlink+0x9fc/0xc60 drivers/net/gtp.c:666 __rtnl_newlink+0x109e/0x1790 net/core/rtnetlink.c:3305 rtnl_newlink+0x69/0xa0 net/core/rtnetlink.c:3363 rtnetlink_rcv_msg+0x45e/0xaf0 net/core/rtnetlink.c:5424 netlink_rcv_skb+0x177/0x450 net/netlink/af_netlink.c:2477 rtnetlink_rcv+0x1d/0x30 net/core/rtnetlink.c:5442 netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline] netlink_unicast+0x58c/0x7d0 net/netlink/af_netlink.c:1328 netlink_sendmsg+0x91c/0xea0 net/netlink/af_netlink.c:1917 sock_sendmsg_nosec net/socket.c:639 [inline] sock_sendmsg+0xd7/0x130 net/socket.c:659 ____sys_sendmsg+0x753/0x880 net/socket.c:2330 ___sys_sendmsg+0x100/0x170 net/socket.c:2384 __sys_sendmsg+0x105/0x1d0 net/socket.c:2417 __do_sys_sendmsg net/socket.c:2426 [inline] __se_sys_sendmsg net/socket.c:2424 [inline] __x64_sys_sendmsg+0x78/0xb0 net/socket.c:2424 do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x445d49 Code: e8 bc b7 02 00 48 83 c4 18 c3 0f 1f 80 00 00 00 00 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 2b 12 fc ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007f8019074db8 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00000000006dac38 RCX: 0000000000445d49 RDX: 0000000000000000 RSI: 0000000020000180 RDI: 0000000000000003 RBP: 00000000006dac30 R08: 0000000000000004 R09: 0000000000000000 R10: 0000000000000008 R11: 0000000000000246 R12: 00000000006dac3c R13: 00007ffea687f6bf R14: 00007f80190759c0 R15: 20c49ba5e353f7cf Fixes: e198987e7dd7 ("gtp: fix suspicious RCU usage") Signed-off-by: Eric Dumazet Reported-by: syzbot Cc: Taehee Yoo Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/gtp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 35905e9ee9ec..25be27826a22 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -816,7 +816,7 @@ static struct sock *gtp_encap_enable_socket(int fd, int type, lock_sock(sock->sk); if (sock->sk->sk_user_data) { sk = ERR_PTR(-EBUSY); - goto out_sock; + goto out_rel_sock; } sk = sock->sk; @@ -829,8 +829,9 @@ static struct sock *gtp_encap_enable_socket(int fd, int type, setup_udp_tunnel_sock(sock_net(sock->sk), sock, &tuncfg); -out_sock: +out_rel_sock: release_sock(sock->sk); +out_sock: sockfd_put(sock); return sk; } -- GitLab From 4a953272f2d2db63bba97137b64b3f1770634e00 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 6 Jan 2020 12:30:48 -0800 Subject: [PATCH 0067/1055] macvlan: do not assume mac_header is set in macvlan_broadcast() [ Upstream commit 96cc4b69581db68efc9749ef32e9cf8e0160c509 ] Use of eth_hdr() in tx path is error prone. Many drivers call skb_reset_mac_header() before using it, but others do not. Commit 6d1ccff62780 ("net: reset mac header in dev_start_xmit()") attempted to fix this generically, but commit d346a3fae3ff ("packet: introduce PACKET_QDISC_BYPASS socket option") brought back the macvlan bug. Lets add a new helper, so that tx paths no longer have to call skb_reset_mac_header() only to get a pointer to skb->data. Hopefully we will be able to revert 6d1ccff62780 ("net: reset mac header in dev_start_xmit()") and save few cycles in transmit fast path. BUG: KASAN: use-after-free in __get_unaligned_cpu32 include/linux/unaligned/packed_struct.h:19 [inline] BUG: KASAN: use-after-free in mc_hash drivers/net/macvlan.c:251 [inline] BUG: KASAN: use-after-free in macvlan_broadcast+0x547/0x620 drivers/net/macvlan.c:277 Read of size 4 at addr ffff8880a4932401 by task syz-executor947/9579 CPU: 0 PID: 9579 Comm: syz-executor947 Not tainted 5.5.0-rc4-syzkaller #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+0x197/0x210 lib/dump_stack.c:118 print_address_description.constprop.0.cold+0xd4/0x30b mm/kasan/report.c:374 __kasan_report.cold+0x1b/0x41 mm/kasan/report.c:506 kasan_report+0x12/0x20 mm/kasan/common.c:639 __asan_report_load_n_noabort+0xf/0x20 mm/kasan/generic_report.c:145 __get_unaligned_cpu32 include/linux/unaligned/packed_struct.h:19 [inline] mc_hash drivers/net/macvlan.c:251 [inline] macvlan_broadcast+0x547/0x620 drivers/net/macvlan.c:277 macvlan_queue_xmit drivers/net/macvlan.c:520 [inline] macvlan_start_xmit+0x402/0x77f drivers/net/macvlan.c:559 __netdev_start_xmit include/linux/netdevice.h:4447 [inline] netdev_start_xmit include/linux/netdevice.h:4461 [inline] dev_direct_xmit+0x419/0x630 net/core/dev.c:4079 packet_direct_xmit+0x1a9/0x250 net/packet/af_packet.c:240 packet_snd net/packet/af_packet.c:2966 [inline] packet_sendmsg+0x260d/0x6220 net/packet/af_packet.c:2991 sock_sendmsg_nosec net/socket.c:639 [inline] sock_sendmsg+0xd7/0x130 net/socket.c:659 __sys_sendto+0x262/0x380 net/socket.c:1985 __do_sys_sendto net/socket.c:1997 [inline] __se_sys_sendto net/socket.c:1993 [inline] __x64_sys_sendto+0xe1/0x1a0 net/socket.c:1993 do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x442639 Code: 18 89 d0 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 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 5b 10 fc ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007ffc13549e08 EFLAGS: 00000246 ORIG_RAX: 000000000000002c RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 0000000000442639 RDX: 000000000000000e RSI: 0000000020000080 RDI: 0000000000000003 RBP: 0000000000000004 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 0000000000403bb0 R14: 0000000000000000 R15: 0000000000000000 Allocated by task 9389: save_stack+0x23/0x90 mm/kasan/common.c:72 set_track mm/kasan/common.c:80 [inline] __kasan_kmalloc mm/kasan/common.c:513 [inline] __kasan_kmalloc.constprop.0+0xcf/0xe0 mm/kasan/common.c:486 kasan_kmalloc+0x9/0x10 mm/kasan/common.c:527 __do_kmalloc mm/slab.c:3656 [inline] __kmalloc+0x163/0x770 mm/slab.c:3665 kmalloc include/linux/slab.h:561 [inline] tomoyo_realpath_from_path+0xc5/0x660 security/tomoyo/realpath.c:252 tomoyo_get_realpath security/tomoyo/file.c:151 [inline] tomoyo_path_perm+0x230/0x430 security/tomoyo/file.c:822 tomoyo_inode_getattr+0x1d/0x30 security/tomoyo/tomoyo.c:129 security_inode_getattr+0xf2/0x150 security/security.c:1222 vfs_getattr+0x25/0x70 fs/stat.c:115 vfs_statx_fd+0x71/0xc0 fs/stat.c:145 vfs_fstat include/linux/fs.h:3265 [inline] __do_sys_newfstat+0x9b/0x120 fs/stat.c:378 __se_sys_newfstat fs/stat.c:375 [inline] __x64_sys_newfstat+0x54/0x80 fs/stat.c:375 do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294 entry_SYSCALL_64_after_hwframe+0x49/0xbe Freed by task 9389: save_stack+0x23/0x90 mm/kasan/common.c:72 set_track mm/kasan/common.c:80 [inline] kasan_set_free_info mm/kasan/common.c:335 [inline] __kasan_slab_free+0x102/0x150 mm/kasan/common.c:474 kasan_slab_free+0xe/0x10 mm/kasan/common.c:483 __cache_free mm/slab.c:3426 [inline] kfree+0x10a/0x2c0 mm/slab.c:3757 tomoyo_realpath_from_path+0x1a7/0x660 security/tomoyo/realpath.c:289 tomoyo_get_realpath security/tomoyo/file.c:151 [inline] tomoyo_path_perm+0x230/0x430 security/tomoyo/file.c:822 tomoyo_inode_getattr+0x1d/0x30 security/tomoyo/tomoyo.c:129 security_inode_getattr+0xf2/0x150 security/security.c:1222 vfs_getattr+0x25/0x70 fs/stat.c:115 vfs_statx_fd+0x71/0xc0 fs/stat.c:145 vfs_fstat include/linux/fs.h:3265 [inline] __do_sys_newfstat+0x9b/0x120 fs/stat.c:378 __se_sys_newfstat fs/stat.c:375 [inline] __x64_sys_newfstat+0x54/0x80 fs/stat.c:375 do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294 entry_SYSCALL_64_after_hwframe+0x49/0xbe The buggy address belongs to the object at ffff8880a4932000 which belongs to the cache kmalloc-4k of size 4096 The buggy address is located 1025 bytes inside of 4096-byte region [ffff8880a4932000, ffff8880a4933000) The buggy address belongs to the page: page:ffffea0002924c80 refcount:1 mapcount:0 mapping:ffff8880aa402000 index:0x0 compound_mapcount: 0 raw: 00fffe0000010200 ffffea0002846208 ffffea00028f3888 ffff8880aa402000 raw: 0000000000000000 ffff8880a4932000 0000000100000001 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff8880a4932300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff8880a4932380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb >ffff8880a4932400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ^ ffff8880a4932480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff8880a4932500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb Fixes: b863ceb7ddce ("[NET]: Add macvlan driver") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/macvlan.c | 2 +- include/linux/if_ether.h | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 8d5f88a538fc..2b977655834c 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -263,7 +263,7 @@ static void macvlan_broadcast(struct sk_buff *skb, struct net_device *src, enum macvlan_mode mode) { - const struct ethhdr *eth = eth_hdr(skb); + const struct ethhdr *eth = skb_eth_hdr(skb); const struct macvlan_dev *vlan; struct sk_buff *nskb; unsigned int i; diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 548fd535fd02..d433f5e292c9 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -28,6 +28,14 @@ static inline struct ethhdr *eth_hdr(const struct sk_buff *skb) return (struct ethhdr *)skb_mac_header(skb); } +/* Prefer this version in TX path, instead of + * skb_reset_mac_header() + eth_hdr() + */ +static inline struct ethhdr *skb_eth_hdr(const struct sk_buff *skb) +{ + return (struct ethhdr *)skb->data; +} + static inline struct ethhdr *inner_eth_hdr(const struct sk_buff *skb) { return (struct ethhdr *)skb_inner_mac_header(skb); -- GitLab From 19716758430e63e0cf6097cdde2a72b6ac28dc75 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 4 Jan 2020 23:14:51 +0100 Subject: [PATCH 0068/1055] net: dsa: mv88e6xxx: Preserve priority when setting CPU port. [ Upstream commit d8dc2c9676e614ef62f54a155b50076888c8a29a ] The 6390 family uses an extended register to set the port connected to the CPU. The lower 5 bits indicate the port, the upper three bits are the priority of the frames as they pass through the switch, what egress queue they should use, etc. Since frames being set to the CPU are typically management frames, BPDU, IGMP, ARP, etc set the priority to 7, the reset default, and the highest. Fixes: 33641994a676 ("net: dsa: mv88e6xxx: Monitor and Management tables") Signed-off-by: Andrew Lunn Tested-by: Chris Healy Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/dsa/mv88e6xxx/global1.c | 5 +++++ drivers/net/dsa/mv88e6xxx/global1.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c index d76d7c7ea819..544b6a9cc01a 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.c +++ b/drivers/net/dsa/mv88e6xxx/global1.c @@ -313,6 +313,11 @@ int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port) { u16 ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST; + /* Use the default high priority for management frames sent to + * the CPU. + */ + port |= MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST_MGMTPRI; + return mv88e6390_g1_monitor_write(chip, ptr, port); } diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 950b914f9251..d82e8956cbd5 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -189,6 +189,7 @@ #define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST 0x2000 #define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST 0x2100 #define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST 0x3000 +#define MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST_MGMTPRI 0x00e0 #define MV88E6390_G1_MONITOR_MGMT_CTL_DATA_MASK 0x00ff /* Offset 0x1C: Global Control 2 */ -- GitLab From fee038c31896073d7b0b7c1b1183f02579f44a4e Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 6 Jan 2020 11:09:45 +0800 Subject: [PATCH 0069/1055] net: stmmac: dwmac-sun8i: Allow all RGMII modes [ Upstream commit f1239d8aa84dad8fe4b6cc1356f40fc8e842db47 ] Allow all the RGMII modes to be used. This would allow us to represent the hardware better in the device tree with RGMII_ID where in most cases the PHY's internal delay for both RX and TX are used. Fixes: 9f93ac8d4085 ("net-next: stmmac: Add dwmac-sun8i") Signed-off-by: Chen-Yu Tsai Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index a62128a444a6..149fd0d5e069 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -724,6 +724,9 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv) /* default */ break; case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: reg |= SYSCON_EPIT | SYSCON_ETCS_INT_GMII; break; case PHY_INTERFACE_MODE_RMII: -- GitLab From 8835b0eff11a61f5c5df0b3c4737cfdde28b1a41 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 6 Jan 2020 11:09:22 +0800 Subject: [PATCH 0070/1055] net: stmmac: dwmac-sunxi: Allow all RGMII modes [ Upstream commit 52cc73e5404c7ba0cbfc50cb4c265108c84b3d5a ] Allow all the RGMII modes to be used. This would allow us to represent the hardware better in the device tree with RGMII_ID where in most cases the PHY's internal delay for both RX and TX are used. Fixes: af0bd4e9ba80 ("net: stmmac: sunxi platform extensions for GMAC in Allwinner A20 SoC's") Signed-off-by: Chen-Yu Tsai Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c index 62ccbd47c1db..fc1fa0f9f338 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c @@ -53,7 +53,7 @@ static int sun7i_gmac_init(struct platform_device *pdev, void *priv) * rate, which then uses the auto-reparenting feature of the * clock driver, and enabling/disabling the clock. */ - if (gmac->interface == PHY_INTERFACE_MODE_RGMII) { + if (phy_interface_mode_is_rgmii(gmac->interface)) { clk_set_rate(gmac->tx_clk, SUN7I_GMAC_GMII_RGMII_RATE); clk_prepare_enable(gmac->tx_clk); gmac->clk_enabled = 1; -- GitLab From a45335027cece5e979c1bb1a603604b2f34f32f8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 7 Jan 2020 10:57:01 -0800 Subject: [PATCH 0071/1055] net: usb: lan78xx: fix possible skb leak [ Upstream commit 47240ba0cd09bb6fe6db9889582048324999dfa4 ] If skb_linearize() fails, we need to free the skb. TSO makes skb bigger, and this bug might be the reason Raspberry Pi 3B+ users had to disable TSO. Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver") Signed-off-by: Eric Dumazet Reported-by: RENARD Pierre-Francois Cc: Stefan Wahren Cc: Woojung Huh Cc: Microchip Linux Driver Support Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/lan78xx.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 0aa6f3a5612d..c23f35dba718 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -2604,11 +2604,6 @@ static int lan78xx_stop(struct net_device *net) return 0; } -static int lan78xx_linearize(struct sk_buff *skb) -{ - return skb_linearize(skb); -} - static struct sk_buff *lan78xx_tx_prep(struct lan78xx_net *dev, struct sk_buff *skb, gfp_t flags) { @@ -2619,8 +2614,10 @@ static struct sk_buff *lan78xx_tx_prep(struct lan78xx_net *dev, return NULL; } - if (lan78xx_linearize(skb) < 0) + if (skb_linearize(skb)) { + dev_kfree_skb_any(skb); return NULL; + } tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN_MASK_) | TX_CMD_A_FCS_; -- GitLab From 73a6f18d8390abc233212085ba4f06088f9fb075 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 6 Jan 2020 06:10:39 -0800 Subject: [PATCH 0072/1055] pkt_sched: fq: do not accept silly TCA_FQ_QUANTUM [ Upstream commit d9e15a2733067c9328fb56d98fe8e574fa19ec31 ] As diagnosed by Florian : If TCA_FQ_QUANTUM is set to 0x80000000, fq_deueue() can loop forever in : if (f->credit <= 0) { f->credit += q->quantum; goto begin; } ... because f->credit is either 0 or -2147483648. Let's limit TCA_FQ_QUANTUM to no more than 1 << 20 : This max value should limit risks of breaking user setups while fixing this bug. Fixes: afe4fd062416 ("pkt_sched: fq: Fair Queue packet scheduler") Signed-off-by: Eric Dumazet Diagnosed-by: Florian Westphal Reported-by: syzbot+dc9071cc5a85950bdfce@syzkaller.appspotmail.com Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_fq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index f50eb87cfe79..7a944f508cae 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -734,7 +734,7 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt) if (tb[TCA_FQ_QUANTUM]) { u32 quantum = nla_get_u32(tb[TCA_FQ_QUANTUM]); - if (quantum > 0) + if (quantum > 0 && quantum <= (1 << 20)) q->quantum = quantum; else err = -EINVAL; -- GitLab From bb275c92aaa05ba8fdf6919950cede0c03f62253 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 19 Dec 2019 17:10:16 +0100 Subject: [PATCH 0073/1055] USB: core: fix check for duplicate endpoints commit 3e4f8e21c4f27bcf30a48486b9dcc269512b79ff upstream. Amend the endpoint-descriptor sanity checks to detect all duplicate endpoint addresses in a configuration. Commit 0a8fd1346254 ("USB: fix problems with duplicate endpoint addresses") added a check for duplicate endpoint addresses within a single alternate setting, but did not look for duplicate addresses in other interfaces. The current check would also not detect all duplicate addresses when one endpoint is as a (bi-directional) control endpoint. This specifically avoids overwriting the endpoint entries in struct usb_device when enabling a duplicate endpoint, something which could potentially lead to crashes or leaks, for example, when endpoints are later disabled. Cc: stable Signed-off-by: Johan Hovold Acked-by: Alan Stern Link: https://lore.kernel.org/r/20191219161016.6695-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 70 ++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index cfb8f1126cf8..1f525d5f6d2d 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -203,9 +203,58 @@ static const unsigned short super_speed_maxpacket_maxes[4] = { [USB_ENDPOINT_XFER_INT] = 1024, }; -static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, - int asnum, struct usb_host_interface *ifp, int num_ep, - unsigned char *buffer, int size) +static bool endpoint_is_duplicate(struct usb_endpoint_descriptor *e1, + struct usb_endpoint_descriptor *e2) +{ + if (e1->bEndpointAddress == e2->bEndpointAddress) + return true; + + if (usb_endpoint_xfer_control(e1) || usb_endpoint_xfer_control(e2)) { + if (usb_endpoint_num(e1) == usb_endpoint_num(e2)) + return true; + } + + return false; +} + +/* + * Check for duplicate endpoint addresses in other interfaces and in the + * altsetting currently being parsed. + */ +static bool config_endpoint_is_duplicate(struct usb_host_config *config, + int inum, int asnum, struct usb_endpoint_descriptor *d) +{ + struct usb_endpoint_descriptor *epd; + struct usb_interface_cache *intfc; + struct usb_host_interface *alt; + int i, j, k; + + for (i = 0; i < config->desc.bNumInterfaces; ++i) { + intfc = config->intf_cache[i]; + + for (j = 0; j < intfc->num_altsetting; ++j) { + alt = &intfc->altsetting[j]; + + if (alt->desc.bInterfaceNumber == inum && + alt->desc.bAlternateSetting != asnum) + continue; + + for (k = 0; k < alt->desc.bNumEndpoints; ++k) { + epd = &alt->endpoint[k].desc; + + if (endpoint_is_duplicate(epd, d)) + return true; + } + } + } + + return false; +} + +static int usb_parse_endpoint(struct device *ddev, int cfgno, + struct usb_host_config *config, int inum, int asnum, + struct usb_host_interface *ifp, int num_ep, + unsigned char *buffer, int size) { unsigned char *buffer0 = buffer; struct usb_endpoint_descriptor *d; @@ -242,13 +291,10 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, goto skip_to_next_endpoint_or_interface_descriptor; /* Check for duplicate endpoint addresses */ - for (i = 0; i < ifp->desc.bNumEndpoints; ++i) { - if (ifp->endpoint[i].desc.bEndpointAddress == - d->bEndpointAddress) { - dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n", - cfgno, inum, asnum, d->bEndpointAddress); - goto skip_to_next_endpoint_or_interface_descriptor; - } + if (config_endpoint_is_duplicate(config, inum, asnum, d)) { + dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n", + cfgno, inum, asnum, d->bEndpointAddress); + goto skip_to_next_endpoint_or_interface_descriptor; } endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints]; @@ -522,8 +568,8 @@ static int usb_parse_interface(struct device *ddev, int cfgno, if (((struct usb_descriptor_header *) buffer)->bDescriptorType == USB_DT_INTERFACE) break; - retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt, - num_ep, buffer, size); + retval = usb_parse_endpoint(ddev, cfgno, config, inum, asnum, + alt, num_ep, buffer, size); if (retval < 0) return retval; ++n; -- GitLab From 7eff1139e85c78b0c96afe587792cabf19d0fb2a Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Fri, 13 Dec 2019 14:56:15 +0100 Subject: [PATCH 0074/1055] USB: serial: option: add Telit ME910G1 0x110a composition commit 0d3010fa442429f8780976758719af05592ff19f upstream. This patch adds the following Telit ME910G1 composition: 0x110a: tty, tty, tty, rmnet Signed-off-by: Daniele Palmas Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 8d349f2e5656..dc9a1139e7e1 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1175,6 +1175,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1102, 0xff), /* Telit ME910 (ECM) */ .driver_info = NCTRL(0) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x110a, 0xff), /* Telit ME910G1 */ + .driver_info = NCTRL(0) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4), -- GitLab From 2e2d29bacd3f70b13a3abfc7b7033aacdb4c2aee Mon Sep 17 00:00:00 2001 From: Xin Long Date: Sat, 4 Jan 2020 14:15:02 +0800 Subject: [PATCH 0075/1055] sctp: free cmd->obj.chunk for the unprocessed SCTP_CMD_REPLY [ Upstream commit be7a7729207797476b6666f046d765bdf9630407 ] This patch is to fix a memleak caused by no place to free cmd->obj.chunk for the unprocessed SCTP_CMD_REPLY. This issue occurs when failing to process a cmd while there're still SCTP_CMD_REPLY cmds on the cmd seq with an allocated chunk in cmd->obj.chunk. So fix it by freeing cmd->obj.chunk for each SCTP_CMD_REPLY cmd left on the cmd seq when any cmd returns error. While at it, also remove 'nomem' label. Reported-by: syzbot+107c4aff5f392bf1517f@syzkaller.appspotmail.com Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Xin Long Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/sm_sideeffect.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index bf0c61adb09c..482bb0a5d4d3 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1359,8 +1359,10 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, /* Generate an INIT ACK chunk. */ new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC, 0); - if (!new_obj) - goto nomem; + if (!new_obj) { + error = -ENOMEM; + break; + } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(new_obj)); @@ -1382,7 +1384,8 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, if (!new_obj) { if (cmd->obj.chunk) sctp_chunk_free(cmd->obj.chunk); - goto nomem; + error = -ENOMEM; + break; } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(new_obj)); @@ -1429,8 +1432,10 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, /* Generate a SHUTDOWN chunk. */ new_obj = sctp_make_shutdown(asoc, chunk); - if (!new_obj) - goto nomem; + if (!new_obj) { + error = -ENOMEM; + break; + } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(new_obj)); break; @@ -1760,11 +1765,17 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, break; } - if (error) + if (error) { + cmd = sctp_next_cmd(commands); + while (cmd) { + if (cmd->verb == SCTP_CMD_REPLY) + sctp_chunk_free(cmd->obj.chunk); + cmd = sctp_next_cmd(commands); + } break; + } } -out: /* If this is in response to a received chunk, wait until * we are done with the packet to open the queue so that we don't * send multiple packets in response to a single request. @@ -1779,8 +1790,5 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, sp->data_ready_signalled = 0; return error; -nomem: - error = -ENOMEM; - goto out; } -- GitLab From ab31605bdb67483047f3cc48f49b0ad63ec20465 Mon Sep 17 00:00:00 2001 From: Pengcheng Yang Date: Mon, 30 Dec 2019 17:54:41 +0800 Subject: [PATCH 0076/1055] tcp: fix "old stuff" D-SACK causing SACK to be treated as D-SACK [ Upstream commit c9655008e7845bcfdaac10a1ed8554ec167aea88 ] When we receive a D-SACK, where the sequence number satisfies: undo_marker <= start_seq < end_seq <= prior_snd_una we consider this is a valid D-SACK and tcp_is_sackblock_valid() returns true, then this D-SACK is discarded as "old stuff", but the variable first_sack_index is not marked as negative in tcp_sacktag_write_queue(). If this D-SACK also carries a SACK that needs to be processed (for example, the previous SACK segment was lost), this SACK will be treated as a D-SACK in the following processing of tcp_sacktag_write_queue(), which will eventually lead to incorrect updates of undo_retrans and reordering. Fixes: fd6dad616d4f ("[TCP]: Earlier SACK block verification & simplify access to them") Signed-off-by: Pengcheng Yang Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 55253ba0681f..d2b1c39c4223 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1750,8 +1750,11 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb, } /* Ignore very old stuff early */ - if (!after(sp[used_sacks].end_seq, prior_snd_una)) + if (!after(sp[used_sacks].end_seq, prior_snd_una)) { + if (i == 0) + first_sack_index = -1; continue; + } used_sacks++; } -- GitLab From 36821b48f5203d5490349e514c2774ff9784bebc Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Thu, 2 Jan 2020 17:23:45 +0800 Subject: [PATCH 0077/1055] vxlan: fix tos value before xmit [ Upstream commit 71130f29979c7c7956b040673e6b9d5643003176 ] Before ip_tunnel_ecn_encap() and udp_tunnel_xmit_skb() we should filter tos value by RT_TOS() instead of using config tos directly. vxlan_get_route() would filter the tos to fl4.flowi4_tos but we didn't return it back, as geneve_get_v4_rt() did. So we have to use RT_TOS() directly in function ip_tunnel_ecn_encap(). Fixes: 206aaafcd279 ("VXLAN: Use IP Tunnels tunnel ENC encap API") Fixes: 1400615d64cf ("vxlan: allow setting ipv6 traffic class") Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/vxlan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 153a81ece9fe..5aa7d5091f4d 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2216,7 +2216,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, skb_dst_update_pmtu(skb, mtu); } - tos = ip_tunnel_ecn_encap(tos, old_iph, skb); + tos = ip_tunnel_ecn_encap(RT_TOS(tos), old_iph, skb); ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); err = vxlan_build_skb(skb, ndst, sizeof(struct iphdr), vni, md, flags, udp_sum); @@ -2257,7 +2257,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, skb_dst_update_pmtu(skb, mtu); } - tos = ip_tunnel_ecn_encap(tos, old_iph, skb); + tos = ip_tunnel_ecn_encap(RT_TOS(tos), old_iph, skb); ttl = ttl ? : ip6_dst_hoplimit(ndst); skb_scrub_packet(skb, xnet); err = vxlan_build_skb(skb, ndst, sizeof(struct ipv6hdr), -- GitLab From 841d685ca1154db46d409883a48d15409819a838 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 7 Jan 2020 01:42:25 -0800 Subject: [PATCH 0078/1055] vlan: vlan_changelink() should propagate errors [ Upstream commit eb8ef2a3c50092bb018077c047b8dba1ce0e78e3 ] Both vlan_dev_change_flags() and vlan_dev_set_egress_priority() can return an error. vlan_changelink() should not ignore them. Fixes: 07b5b17e157b ("[VLAN]: Use rtnl_link API") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/8021q/vlan_netlink.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index 5e831de3103e..ef7e18a27719 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -95,11 +95,13 @@ static int vlan_changelink(struct net_device *dev, struct nlattr *tb[], struct ifla_vlan_flags *flags; struct ifla_vlan_qos_mapping *m; struct nlattr *attr; - int rem; + int rem, err; if (data[IFLA_VLAN_FLAGS]) { flags = nla_data(data[IFLA_VLAN_FLAGS]); - vlan_dev_change_flags(dev, flags->flags, flags->mask); + err = vlan_dev_change_flags(dev, flags->flags, flags->mask); + if (err) + return err; } if (data[IFLA_VLAN_INGRESS_QOS]) { nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) { @@ -110,7 +112,9 @@ static int vlan_changelink(struct net_device *dev, struct nlattr *tb[], if (data[IFLA_VLAN_EGRESS_QOS]) { nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) { m = nla_data(attr); - vlan_dev_set_egress_priority(dev, m->from, m->to); + err = vlan_dev_set_egress_priority(dev, m->from, m->to); + if (err) + return err; } } return 0; -- GitLab From a56f6034450677945452a72800dc84354959026e Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 6 Jan 2020 18:01:56 +0000 Subject: [PATCH 0079/1055] net: sch_prio: When ungrafting, replace with FIFO [ Upstream commit 240ce7f6428ff5188b9eedc066e1e4d645b8635f ] When a child Qdisc is removed from one of the PRIO Qdisc's bands, it is replaced unconditionally by a NOOP qdisc. As a result, any traffic hitting that band gets dropped. That is incorrect--no Qdisc was explicitly added when PRIO was created, and after removal, none should have to be added either. Fix PRIO by first attempting to create a default Qdisc and only falling back to noop when that fails. This pattern of attempting to create an invisible FIFO, using NOOP only as a fallback, is also seen in other Qdiscs. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Petr Machata Acked-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_prio.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index c60777351de1..ff6bc7cf6cbd 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -244,8 +244,14 @@ static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, struct prio_sched_data *q = qdisc_priv(sch); unsigned long band = arg - 1; - if (new == NULL) - new = &noop_qdisc; + if (!new) { + new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, + TC_H_MAKE(sch->handle, arg)); + if (!new) + new = &noop_qdisc; + else + qdisc_hash_add(new, true); + } *old = qdisc_replace(sch, new, &q->queues[band]); return 0; -- GitLab From 9df7257626785ede4905f8813adc78ba740d3f72 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 7 Jan 2020 01:42:24 -0800 Subject: [PATCH 0080/1055] vlan: fix memory leak in vlan_dev_set_egress_priority [ Upstream commit 9bbd917e0bec9aebdbd0c8dbc966caec15eb33e9 ] There are few cases where the ndo_uninit() handler might be not called if an error happens while device is initialized. Since vlan_newlink() calls vlan_changelink() before trying to register the netdevice, we need to make sure vlan_dev_uninit() has been called at least once, or we might leak allocated memory. BUG: memory leak unreferenced object 0xffff888122a206c0 (size 32): comm "syz-executor511", pid 7124, jiffies 4294950399 (age 32.240s) hex dump (first 32 bytes): 00 00 00 00 00 00 61 73 00 00 00 00 00 00 00 00 ......as........ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<000000000eb3bb85>] kmemleak_alloc_recursive include/linux/kmemleak.h:43 [inline] [<000000000eb3bb85>] slab_post_alloc_hook mm/slab.h:586 [inline] [<000000000eb3bb85>] slab_alloc mm/slab.c:3320 [inline] [<000000000eb3bb85>] kmem_cache_alloc_trace+0x145/0x2c0 mm/slab.c:3549 [<000000007b99f620>] kmalloc include/linux/slab.h:556 [inline] [<000000007b99f620>] vlan_dev_set_egress_priority+0xcc/0x150 net/8021q/vlan_dev.c:194 [<000000007b0cb745>] vlan_changelink+0xd6/0x140 net/8021q/vlan_netlink.c:126 [<0000000065aba83a>] vlan_newlink+0x135/0x200 net/8021q/vlan_netlink.c:181 [<00000000fb5dd7a2>] __rtnl_newlink+0x89a/0xb80 net/core/rtnetlink.c:3305 [<00000000ae4273a1>] rtnl_newlink+0x4e/0x80 net/core/rtnetlink.c:3363 [<00000000decab39f>] rtnetlink_rcv_msg+0x178/0x4b0 net/core/rtnetlink.c:5424 [<00000000accba4ee>] netlink_rcv_skb+0x61/0x170 net/netlink/af_netlink.c:2477 [<00000000319fe20f>] rtnetlink_rcv+0x1d/0x30 net/core/rtnetlink.c:5442 [<00000000d51938dc>] netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline] [<00000000d51938dc>] netlink_unicast+0x223/0x310 net/netlink/af_netlink.c:1328 [<00000000e539ac79>] netlink_sendmsg+0x2c0/0x570 net/netlink/af_netlink.c:1917 [<000000006250c27e>] sock_sendmsg_nosec net/socket.c:639 [inline] [<000000006250c27e>] sock_sendmsg+0x54/0x70 net/socket.c:659 [<00000000e2a156d1>] ____sys_sendmsg+0x2d0/0x300 net/socket.c:2330 [<000000008c87466e>] ___sys_sendmsg+0x8a/0xd0 net/socket.c:2384 [<00000000110e3054>] __sys_sendmsg+0x80/0xf0 net/socket.c:2417 [<00000000d71077c8>] __do_sys_sendmsg net/socket.c:2426 [inline] [<00000000d71077c8>] __se_sys_sendmsg net/socket.c:2424 [inline] [<00000000d71077c8>] __x64_sys_sendmsg+0x23/0x30 net/socket.c:2424 Fixe: 07b5b17e157b ("[VLAN]: Use rtnl_link API") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/8021q/vlan.h | 1 + net/8021q/vlan_dev.c | 3 ++- net/8021q/vlan_netlink.c | 9 +++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 0e7afdf86127..235bed825e3a 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -110,6 +110,7 @@ int vlan_check_real_dev(struct net_device *real_dev, void vlan_setup(struct net_device *dev); int register_vlan_dev(struct net_device *dev); void unregister_vlan_dev(struct net_device *dev, struct list_head *head); +void vlan_dev_uninit(struct net_device *dev); bool vlan_dev_inherit_address(struct net_device *dev, struct net_device *real_dev); diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index ac4c93c999b0..ed3717dc2d20 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -610,7 +610,8 @@ static int vlan_dev_init(struct net_device *dev) return 0; } -static void vlan_dev_uninit(struct net_device *dev) +/* Note: this function might be called multiple times for the same device. */ +void vlan_dev_uninit(struct net_device *dev) { struct vlan_priority_tci_mapping *pm; struct vlan_dev_priv *vlan = vlan_dev_priv(dev); diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index ef7e18a27719..fdf39dd5e755 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -161,10 +161,11 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev, return -EINVAL; err = vlan_changelink(dev, tb, data, extack); - if (err < 0) - return err; - - return register_vlan_dev(dev); + if (!err) + err = register_vlan_dev(dev); + if (err) + vlan_dev_uninit(dev); + return err; } static inline size_t vlan_qos_map_size(unsigned int n) -- GitLab From 6d0c334a400db31751c787c411e7187ab59a3f1d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 12 Jan 2020 12:12:09 +0100 Subject: [PATCH 0081/1055] Linux 4.14.164 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 35a71a78d1d2..f2aa55cea457 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 163 +SUBLEVEL = 164 EXTRAVERSION = NAME = Petit Gorille -- GitLab From ac137d538b497aca88389fa5f45fec3c359a5dba Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Fri, 17 Nov 2017 15:30:42 -0800 Subject: [PATCH 0082/1055] UPSTREAM: kcov: remove pointless current != NULL check (Upstream commit fcf4edac049a8bca41658970292e2dfdbc9d5f62.) __sanitizer_cov_trace_pc() is a hot code, so it's worth to remove pointless '!current' check. Current is never NULL. Link: http://lkml.kernel.org/r/20170929162221.32500-1-aryabinin@virtuozzo.com Signed-off-by: Andrey Ryabinin Acked-by: Dmitry Vyukov Acked-by: Mark Rutland Cc: Andrey Konovalov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: I2c07ed1a805ff2e9e569adc5aa59386e47f5bb23 --- kernel/kcov.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/kcov.c b/kernel/kcov.c index f1e060b04ef6..dd12f62cfaae 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -62,7 +62,7 @@ void notrace __sanitizer_cov_trace_pc(void) * We are interested in code coverage as a function of a syscall inputs, * so we ignore code executed in interrupts. */ - if (!t || !in_task()) + if (!in_task()) return; mode = READ_ONCE(t->kcov_mode); if (mode == KCOV_MODE_TRACE) { -- GitLab From fccb16d96f3ee4055a8a023edfbb1e7f00bc6c75 Mon Sep 17 00:00:00 2001 From: Victor Chibotaru Date: Fri, 17 Nov 2017 15:30:46 -0800 Subject: [PATCH 0083/1055] BACKPORT: kcov: support comparison operands collection (Upstream commit ded97d2c2b2c5f1dcced0bc57133f7753b037dfc.) Enables kcov to collect comparison operands from instrumented code. This is done by using Clang's -fsanitize=trace-cmp instrumentation (currently not available for GCC). The comparison operands help a lot in fuzz testing. E.g. they are used in Syzkaller to cover the interiors of conditional statements with way less attempts and thus make previously unreachable code reachable. To allow separate collection of coverage and comparison operands two different work modes are implemented. Mode selection is now done via a KCOV_ENABLE ioctl call with corresponding argument value. Link: http://lkml.kernel.org/r/20171011095459.70721-1-glider@google.com Signed-off-by: Victor Chibotaru Signed-off-by: Alexander Potapenko Cc: Dmitry Vyukov Cc: Andrey Konovalov Cc: Mark Rutland Cc: Alexander Popov Cc: Andrey Ryabinin Cc: Kees Cook Cc: Vegard Nossum Cc: Quentin Casasnovas Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Change-Id: I227775c812f342423102cd28fd68b235579c60d3 Signed-off-by: Andrey Konovalov Bug: 147413187 --- include/linux/kcov.h | 12 ++- include/uapi/linux/kcov.h | 24 +++++ kernel/kcov.c | 214 +++++++++++++++++++++++++++++++------- 3 files changed, 211 insertions(+), 39 deletions(-) diff --git a/include/linux/kcov.h b/include/linux/kcov.h index f5d8ce4f4f86..3ecf6f5e3a5f 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -8,19 +8,23 @@ struct task_struct; #ifdef CONFIG_KCOV -void kcov_task_init(struct task_struct *t); -void kcov_task_exit(struct task_struct *t); - enum kcov_mode { /* Coverage collection is not enabled yet. */ KCOV_MODE_DISABLED = 0, + /* KCOV was initialized, but tracing mode hasn't been chosen yet. */ + KCOV_MODE_INIT = 1, /* * Tracing coverage collection mode. * Covered PCs are collected in a per-task buffer. */ - KCOV_MODE_TRACE = 1, + KCOV_MODE_TRACE_PC = 2, + /* Collecting comparison operands mode. */ + KCOV_MODE_TRACE_CMP = 3, }; +void kcov_task_init(struct task_struct *t); +void kcov_task_exit(struct task_struct *t); + #else static inline void kcov_task_init(struct task_struct *t) {} diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h index 33eabbb8ada1..9529867717a8 100644 --- a/include/uapi/linux/kcov.h +++ b/include/uapi/linux/kcov.h @@ -8,4 +8,28 @@ #define KCOV_ENABLE _IO('c', 100) #define KCOV_DISABLE _IO('c', 101) +enum { + /* + * Tracing coverage collection mode. + * Covered PCs are collected in a per-task buffer. + * In new KCOV version the mode is chosen by calling + * ioctl(fd, KCOV_ENABLE, mode). In older versions the mode argument + * was supposed to be 0 in such a call. So, for reasons of backward + * compatibility, we have chosen the value KCOV_TRACE_PC to be 0. + */ + KCOV_TRACE_PC = 0, + /* Collecting comparison operands mode. */ + KCOV_TRACE_CMP = 1, +}; + +/* + * The format for the types of collected comparisons. + * + * Bit 0 shows whether one of the arguments is a compile-time constant. + * Bits 1 & 2 contain log2 of the argument size, up to 8 bytes. + */ +#define KCOV_CMP_CONST (1 << 0) +#define KCOV_CMP_SIZE(n) ((n) << 1) +#define KCOV_CMP_MASK KCOV_CMP_SIZE(3) + #endif /* _LINUX_KCOV_IOCTLS_H */ diff --git a/kernel/kcov.c b/kernel/kcov.c index dd12f62cfaae..05e3f9f0f096 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -22,13 +22,21 @@ #include #include +/* Number of 64-bit words written per one comparison: */ +#define KCOV_WORDS_PER_CMP 4 + /* * kcov descriptor (one per opened debugfs file). * State transitions of the descriptor: * - initial state after open() * - then there must be a single ioctl(KCOV_INIT_TRACE) call * - then, mmap() call (several calls are allowed but not useful) - * - then, repeated enable/disable for a task (only one task a time allowed) + * - then, ioctl(KCOV_ENABLE, arg), where arg is + * KCOV_TRACE_PC - to trace only the PCs + * or + * KCOV_TRACE_CMP - to trace only the comparison operands + * - then, ioctl(KCOV_DISABLE) to disable the task. + * Enabling/disabling ioctls can be repeated (only one task a time allowed). */ struct kcov { /* @@ -48,51 +56,176 @@ struct kcov { struct task_struct *t; }; -/* - * Entry point from instrumented code. - * This is called once per basic-block/edge. - */ -void notrace __sanitizer_cov_trace_pc(void) +static bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t) { - struct task_struct *t; enum kcov_mode mode; - t = current; /* * We are interested in code coverage as a function of a syscall inputs, * so we ignore code executed in interrupts. */ if (!in_task()) - return; + return false; mode = READ_ONCE(t->kcov_mode); - if (mode == KCOV_MODE_TRACE) { - unsigned long *area; - unsigned long pos; - unsigned long ip = _RET_IP_; + /* + * There is some code that runs in interrupts but for which + * in_interrupt() returns false (e.g. preempt_schedule_irq()). + * READ_ONCE()/barrier() effectively provides load-acquire wrt + * interrupts, there are paired barrier()/WRITE_ONCE() in + * kcov_ioctl_locked(). + */ + barrier(); + return mode == needed_mode; +} +static unsigned long canonicalize_ip(unsigned long ip) +{ #ifdef CONFIG_RANDOMIZE_BASE - ip -= kaslr_offset(); + ip -= kaslr_offset(); #endif + return ip; +} - /* - * There is some code that runs in interrupts but for which - * in_interrupt() returns false (e.g. preempt_schedule_irq()). - * READ_ONCE()/barrier() effectively provides load-acquire wrt - * interrupts, there are paired barrier()/WRITE_ONCE() in - * kcov_ioctl_locked(). - */ - barrier(); - area = t->kcov_area; - /* The first word is number of subsequent PCs. */ - pos = READ_ONCE(area[0]) + 1; - if (likely(pos < t->kcov_size)) { - area[pos] = ip; - WRITE_ONCE(area[0], pos); - } +/* + * Entry point from instrumented code. + * This is called once per basic-block/edge. + */ +void notrace __sanitizer_cov_trace_pc(void) +{ + struct task_struct *t; + unsigned long *area; + unsigned long ip = canonicalize_ip(_RET_IP_); + unsigned long pos; + + t = current; + if (!check_kcov_mode(KCOV_MODE_TRACE_PC, t)) + return; + + area = t->kcov_area; + /* The first 64-bit word is the number of subsequent PCs. */ + pos = READ_ONCE(area[0]) + 1; + if (likely(pos < t->kcov_size)) { + area[pos] = ip; + WRITE_ONCE(area[0], pos); } } EXPORT_SYMBOL(__sanitizer_cov_trace_pc); +#ifdef CONFIG_KCOV_ENABLE_COMPARISONS +static void write_comp_data(u64 type, u64 arg1, u64 arg2, u64 ip) +{ + struct task_struct *t; + u64 *area; + u64 count, start_index, end_pos, max_pos; + + t = current; + if (!check_kcov_mode(KCOV_MODE_TRACE_CMP, t)) + return; + + ip = canonicalize_ip(ip); + + /* + * We write all comparison arguments and types as u64. + * The buffer was allocated for t->kcov_size unsigned longs. + */ + area = (u64 *)t->kcov_area; + max_pos = t->kcov_size * sizeof(unsigned long); + + count = READ_ONCE(area[0]); + + /* Every record is KCOV_WORDS_PER_CMP 64-bit words. */ + start_index = 1 + count * KCOV_WORDS_PER_CMP; + end_pos = (start_index + KCOV_WORDS_PER_CMP) * sizeof(u64); + if (likely(end_pos <= max_pos)) { + area[start_index] = type; + area[start_index + 1] = arg1; + area[start_index + 2] = arg2; + area[start_index + 3] = ip; + WRITE_ONCE(area[0], count + 1); + } +} + +void notrace __sanitizer_cov_trace_cmp1(u8 arg1, u8 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(0), arg1, arg2, _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_cmp1); + +void notrace __sanitizer_cov_trace_cmp2(u16 arg1, u16 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(1), arg1, arg2, _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_cmp2); + +void notrace __sanitizer_cov_trace_cmp4(u16 arg1, u16 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(2), arg1, arg2, _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_cmp4); + +void notrace __sanitizer_cov_trace_cmp8(u64 arg1, u64 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(3), arg1, arg2, _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_cmp8); + +void notrace __sanitizer_cov_trace_const_cmp1(u8 arg1, u8 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(0) | KCOV_CMP_CONST, arg1, arg2, + _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp1); + +void notrace __sanitizer_cov_trace_const_cmp2(u16 arg1, u16 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(1) | KCOV_CMP_CONST, arg1, arg2, + _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp2); + +void notrace __sanitizer_cov_trace_const_cmp4(u16 arg1, u16 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(2) | KCOV_CMP_CONST, arg1, arg2, + _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp4); + +void notrace __sanitizer_cov_trace_const_cmp8(u64 arg1, u64 arg2) +{ + write_comp_data(KCOV_CMP_SIZE(3) | KCOV_CMP_CONST, arg1, arg2, + _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp8); + +void notrace __sanitizer_cov_trace_switch(u64 val, u64 *cases) +{ + u64 i; + u64 count = cases[0]; + u64 size = cases[1]; + u64 type = KCOV_CMP_CONST; + + switch (size) { + case 8: + type |= KCOV_CMP_SIZE(0); + break; + case 16: + type |= KCOV_CMP_SIZE(1); + break; + case 32: + type |= KCOV_CMP_SIZE(2); + break; + case 64: + type |= KCOV_CMP_SIZE(3); + break; + default: + return; + } + for (i = 0; i < count; i++) + write_comp_data(type, cases[i + 2], val, _RET_IP_); +} +EXPORT_SYMBOL(__sanitizer_cov_trace_switch); +#endif /* ifdef CONFIG_KCOV_ENABLE_COMPARISONS */ + static void kcov_get(struct kcov *kcov) { atomic_inc(&kcov->refcount); @@ -130,6 +263,7 @@ void kcov_task_exit(struct task_struct *t) /* Just to not leave dangling references behind. */ kcov_task_init(t); kcov->t = NULL; + kcov->mode = KCOV_MODE_INIT; spin_unlock(&kcov->lock); kcov_put(kcov); } @@ -148,7 +282,7 @@ static int kcov_mmap(struct file *filep, struct vm_area_struct *vma) spin_lock(&kcov->lock); size = kcov->size * sizeof(unsigned long); - if (kcov->mode == KCOV_MODE_DISABLED || vma->vm_pgoff != 0 || + if (kcov->mode != KCOV_MODE_INIT || vma->vm_pgoff != 0 || vma->vm_end - vma->vm_start != size) { res = -EINVAL; goto exit; @@ -177,6 +311,7 @@ static int kcov_open(struct inode *inode, struct file *filep) kcov = kzalloc(sizeof(*kcov), GFP_KERNEL); if (!kcov) return -ENOMEM; + kcov->mode = KCOV_MODE_DISABLED; atomic_set(&kcov->refcount, 1); spin_lock_init(&kcov->lock); filep->private_data = kcov; @@ -212,7 +347,7 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, if (size < 2 || size > INT_MAX / sizeof(unsigned long)) return -EINVAL; kcov->size = size; - kcov->mode = KCOV_MODE_TRACE; + kcov->mode = KCOV_MODE_INIT; return 0; case KCOV_ENABLE: /* @@ -222,17 +357,25 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, * at task exit or voluntary by KCOV_DISABLE. After that it can * be enabled for another task. */ - unused = arg; - if (unused != 0 || kcov->mode == KCOV_MODE_DISABLED || - kcov->area == NULL) + if (kcov->mode != KCOV_MODE_INIT || !kcov->area) return -EINVAL; t = current; if (kcov->t != NULL || t->kcov != NULL) return -EBUSY; + if (arg == KCOV_TRACE_PC) + kcov->mode = KCOV_MODE_TRACE_PC; + else if (arg == KCOV_TRACE_CMP) +#ifdef CONFIG_KCOV_ENABLE_COMPARISONS + kcov->mode = KCOV_MODE_TRACE_CMP; +#else + return -ENOTSUPP; +#endif + else + return -EINVAL; /* Cache in task struct for performance. */ t->kcov_size = kcov->size; t->kcov_area = kcov->area; - /* See comment in __sanitizer_cov_trace_pc(). */ + /* See comment in check_kcov_mode(). */ barrier(); WRITE_ONCE(t->kcov_mode, kcov->mode); t->kcov = kcov; @@ -250,6 +393,7 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, return -EINVAL; kcov_task_init(t); kcov->t = NULL; + kcov->mode = KCOV_MODE_INIT; kcov_put(kcov); return 0; default: -- GitLab From 3283a3b899f3d54c89a700249d177ede43fae2d5 Mon Sep 17 00:00:00 2001 From: Victor Chibotaru Date: Fri, 17 Nov 2017 15:30:50 -0800 Subject: [PATCH 0084/1055] BACKPORT: Makefile: support flag -fsanitizer-coverage=trace-cmp (Upstream commit d677a4d6019385488e794cc47bd3d6f9c2aab874.) The flag enables Clang instrumentation of comparison operations (currently not supported by GCC). This instrumentation is needed by the new KCOV device to collect comparison operands. Link: http://lkml.kernel.org/r/20171011095459.70721-2-glider@google.com Signed-off-by: Victor Chibotaru Signed-off-by: Alexander Potapenko Cc: Dmitry Vyukov Cc: Andrey Konovalov Cc: Mark Rutland Cc: Alexander Popov Cc: Andrey Ryabinin Cc: Kees Cook Cc: Vegard Nossum Cc: Quentin Casasnovas Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Change-Id: Id294d9cc7619fb351a8929d11d45e532f86d2c36 Signed-off-by: Andrey Konovalov Bug: 147413187 --- Makefile | 4 ++-- lib/Kconfig.debug | 10 ++++++++++ scripts/Makefile.kcov | 7 +++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 scripts/Makefile.kcov diff --git a/Makefile b/Makefile index a4ec8f733611..e121b0021c92 100644 --- a/Makefile +++ b/Makefile @@ -650,8 +650,7 @@ KBUILD_AFLAGS += $(call cc-option,-fno-PIE) CFLAGS_GCOV := -fprofile-arcs -ftest-coverage \ $(call cc-option,-fno-tree-loop-im) \ $(call cc-disable-warning,maybe-uninitialized,) -CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) -export CFLAGS_GCOV CFLAGS_KCOV +export CFLAGS_GCOV # Make toolchain changes before including arch/$(SRCARCH)/Makefile to ensure # ar/cc/ld-* macros return correct values. @@ -706,6 +705,7 @@ ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC) $(KBUILD_CFLA KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO endif +include scripts/Makefile.kcov include scripts/Makefile.gcc-plugins ifdef CONFIG_READABLE_ASM diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 81a10bd78d8d..5bc743f4d402 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -756,6 +756,16 @@ config KCOV For more details, see Documentation/dev-tools/kcov.rst. +config KCOV_ENABLE_COMPARISONS + bool "Enable comparison operands collection by KCOV" + depends on KCOV + default n + help + KCOV also exposes operands of every comparison in the instrumented + code along with operand sizes and PCs of the comparison instructions. + These operands can be used by fuzzing engines to improve the quality + of fuzzing coverage. + config KCOV_INSTRUMENT_ALL bool "Instrument all code by default" depends on KCOV diff --git a/scripts/Makefile.kcov b/scripts/Makefile.kcov new file mode 100644 index 000000000000..5cc72037e423 --- /dev/null +++ b/scripts/Makefile.kcov @@ -0,0 +1,7 @@ +ifdef CONFIG_KCOV +CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) +ifeq ($(CONFIG_KCOV_ENABLE_COMPARISONS),y) +CFLAGS_KCOV += $(call cc-option,-fsanitize-coverage=trace-cmp,) +endif + +endif -- GitLab From 6e61cc02a75888d648e8a7221b70a19163d95eed Mon Sep 17 00:00:00 2001 From: Victor Chibotaru Date: Fri, 17 Nov 2017 15:30:53 -0800 Subject: [PATCH 0085/1055] UPSTREAM: kcov: update documentation (Upstream commit c512ac01d8a841033da8ec538a83f80fb0b4d1fe.) The updated documentation describes new KCOV mode for collecting comparison operands. Link: http://lkml.kernel.org/r/20171011095459.70721-3-glider@google.com Signed-off-by: Victor Chibotaru Signed-off-by: Alexander Potapenko Cc: Dmitry Vyukov Cc: Andrey Konovalov Cc: Mark Rutland Cc: Alexander Popov Cc: Andrey Ryabinin Cc: Kees Cook Cc: Vegard Nossum Cc: Quentin Casasnovas Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: I5e50446e3c908962de518bc5131a864b0e95b082 --- Documentation/dev-tools/kcov.rst | 99 ++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 4 deletions(-) diff --git a/Documentation/dev-tools/kcov.rst b/Documentation/dev-tools/kcov.rst index 44886c91e112..c2f6452e38ed 100644 --- a/Documentation/dev-tools/kcov.rst +++ b/Documentation/dev-tools/kcov.rst @@ -12,19 +12,30 @@ To achieve this goal it does not collect coverage in soft/hard interrupts and instrumentation of some inherently non-deterministic parts of kernel is disabled (e.g. scheduler, locking). -Usage ------ +kcov is also able to collect comparison operands from the instrumented code +(this feature currently requires that the kernel is compiled with clang). + +Prerequisites +------------- Configure the kernel with:: CONFIG_KCOV=y CONFIG_KCOV requires gcc built on revision 231296 or later. + +If the comparison operands need to be collected, set:: + + CONFIG_KCOV_ENABLE_COMPARISONS=y + Profiling data will only become accessible once debugfs has been mounted:: mount -t debugfs none /sys/kernel/debug -The following program demonstrates kcov usage from within a test program: +Coverage collection +------------------- +The following program demonstrates coverage collection from within a test +program using kcov: .. code-block:: c @@ -44,6 +55,9 @@ The following program demonstrates kcov usage from within a test program: #define KCOV_DISABLE _IO('c', 101) #define COVER_SIZE (64<<10) + #define KCOV_TRACE_PC 0 + #define KCOV_TRACE_CMP 1 + int main(int argc, char **argv) { int fd; @@ -64,7 +78,7 @@ The following program demonstrates kcov usage from within a test program: if ((void*)cover == MAP_FAILED) perror("mmap"), exit(1); /* Enable coverage collection on the current thread. */ - if (ioctl(fd, KCOV_ENABLE, 0)) + if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_PC)) perror("ioctl"), exit(1); /* Reset coverage from the tail of the ioctl() call. */ __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); @@ -111,3 +125,80 @@ The interface is fine-grained to allow efficient forking of test processes. That is, a parent process opens /sys/kernel/debug/kcov, enables trace mode, mmaps coverage buffer and then forks child processes in a loop. Child processes only need to enable coverage (disable happens automatically on thread end). + +Comparison operands collection +------------------------------ +Comparison operands collection is similar to coverage collection: + +.. code-block:: c + + /* Same includes and defines as above. */ + + /* Number of 64-bit words per record. */ + #define KCOV_WORDS_PER_CMP 4 + + /* + * The format for the types of collected comparisons. + * + * Bit 0 shows whether one of the arguments is a compile-time constant. + * Bits 1 & 2 contain log2 of the argument size, up to 8 bytes. + */ + + #define KCOV_CMP_CONST (1 << 0) + #define KCOV_CMP_SIZE(n) ((n) << 1) + #define KCOV_CMP_MASK KCOV_CMP_SIZE(3) + + int main(int argc, char **argv) + { + int fd; + uint64_t *cover, type, arg1, arg2, is_const, size; + unsigned long n, i; + + fd = open("/sys/kernel/debug/kcov", O_RDWR); + if (fd == -1) + perror("open"), exit(1); + if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE)) + perror("ioctl"), exit(1); + /* + * Note that the buffer pointer is of type uint64_t*, because all + * the comparison operands are promoted to uint64_t. + */ + cover = (uint64_t *)mmap(NULL, COVER_SIZE * sizeof(unsigned long), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if ((void*)cover == MAP_FAILED) + perror("mmap"), exit(1); + /* Note KCOV_TRACE_CMP instead of KCOV_TRACE_PC. */ + if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_CMP)) + perror("ioctl"), exit(1); + __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); + read(-1, NULL, 0); + /* Read number of comparisons collected. */ + n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + for (i = 0; i < n; i++) { + type = cover[i * KCOV_WORDS_PER_CMP + 1]; + /* arg1 and arg2 - operands of the comparison. */ + arg1 = cover[i * KCOV_WORDS_PER_CMP + 2]; + arg2 = cover[i * KCOV_WORDS_PER_CMP + 3]; + /* ip - caller address. */ + ip = cover[i * KCOV_WORDS_PER_CMP + 4]; + /* size of the operands. */ + size = 1 << ((type & KCOV_CMP_MASK) >> 1); + /* is_const - true if either operand is a compile-time constant.*/ + is_const = type & KCOV_CMP_CONST; + printf("ip: 0x%lx type: 0x%lx, arg1: 0x%lx, arg2: 0x%lx, " + "size: %lu, %s\n", + ip, type, arg1, arg2, size, + is_const ? "const" : "non-const"); + } + if (ioctl(fd, KCOV_DISABLE, 0)) + perror("ioctl"), exit(1); + /* Free resources. */ + if (munmap(cover, COVER_SIZE * sizeof(unsigned long))) + perror("munmap"), exit(1); + if (close(fd)) + perror("close"), exit(1); + return 0; + } + +Note that the kcov modes (coverage collection or comparison operands) are +mutually exclusive. -- GitLab From 13ffffd3bab5b9c0cd52b0d0f4a2a3120954f131 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 14 Dec 2017 15:33:02 -0800 Subject: [PATCH 0086/1055] UPSTREAM: kcov: fix comparison callback signature (Upstream commit 689d77f001cd22da31cc943170e1f6f2e8197035.) Fix a silly copy-paste bug. We truncated u32 args to u16. Link: http://lkml.kernel.org/r/20171207101134.107168-1-dvyukov@google.com Fixes: ded97d2c2b2c ("kcov: support comparison operands collection") Signed-off-by: Dmitry Vyukov Cc: syzkaller@googlegroups.com Cc: Alexander Potapenko Cc: Vegard Nossum Cc: Quentin Casasnovas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: If15ae4d86c445e908c355975ccf5cf53e296b27d --- kernel/kcov.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/kcov.c b/kernel/kcov.c index 05e3f9f0f096..5be9a60a959f 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -157,7 +157,7 @@ void notrace __sanitizer_cov_trace_cmp2(u16 arg1, u16 arg2) } EXPORT_SYMBOL(__sanitizer_cov_trace_cmp2); -void notrace __sanitizer_cov_trace_cmp4(u16 arg1, u16 arg2) +void notrace __sanitizer_cov_trace_cmp4(u32 arg1, u32 arg2) { write_comp_data(KCOV_CMP_SIZE(2), arg1, arg2, _RET_IP_); } @@ -183,7 +183,7 @@ void notrace __sanitizer_cov_trace_const_cmp2(u16 arg1, u16 arg2) } EXPORT_SYMBOL(__sanitizer_cov_trace_const_cmp2); -void notrace __sanitizer_cov_trace_const_cmp4(u16 arg1, u16 arg2) +void notrace __sanitizer_cov_trace_const_cmp4(u32 arg1, u32 arg2) { write_comp_data(KCOV_CMP_SIZE(2) | KCOV_CMP_CONST, arg1, arg2, _RET_IP_); -- GitLab From 0f0fe8e7a521002f7c3b34a5907035e402db1840 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 13 Apr 2018 14:06:10 +0900 Subject: [PATCH 0087/1055] UPSTREAM: gcc-plugins: fix build condition of SANCOV plugin (Upstream commit 642ef99be932c4071274b28eaf3d3d85bbb6e78c.) Since commit d677a4d60193 ("Makefile: support flag -fsanitizer-coverage=trace-cmp"), you miss to build the SANCOV plugin under some circumstances. CONFIG_KCOV=y CONFIG_KCOV_ENABLE_COMPARISONS=y Your compiler does not support -fsanitize-coverage=trace-pc Your compiler does not support -fsanitize-coverage=trace-cmp Under this condition, $(CFLAGS_KCOV) is not empty but contains a space, so the following ifeq-conditional is false. ifeq ($(CFLAGS_KCOV),) Then, scripts/Makefile.gcc-plugins misses to add sancov_plugin.so to gcc-plugin-y while the SANCOV plugin is necessary as an alternative means. Fixes: d677a4d60193 ("Makefile: support flag -fsanitizer-coverage=trace-cmp") Signed-off-by: Masahiro Yamada Acked-by: Kees Cook Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: Ifa747836a53f74563fcff44e9d95948e9589b552 --- scripts/Makefile.gcc-plugins | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins index b2a95af7df18..7f5c86246138 100644 --- a/scripts/Makefile.gcc-plugins +++ b/scripts/Makefile.gcc-plugins @@ -14,7 +14,7 @@ ifdef CONFIG_GCC_PLUGINS endif ifdef CONFIG_GCC_PLUGIN_SANCOV - ifeq ($(CFLAGS_KCOV),) + ifeq ($(strip $(CFLAGS_KCOV)),) # It is needed because of the gcc-plugin.sh and gcc version checks. gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so -- GitLab From c093b585dac3962f3a54772bc8ef2031bd1f1990 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 28 May 2018 18:22:04 +0900 Subject: [PATCH 0088/1055] BACKPORT: kcov: test compiler capability in Kconfig and correct dependency Work around missing cc-option support in Kconfig by checking required compiler flags in Makefile. (Upstream commit 5aadfdeb8de001ca04d500586e3b033404c28617.) As Documentation/kbuild/kconfig-language.txt notes, 'select' should be be used with care - it forces a lower limit of another symbol, ignoring the dependency. Currently, KCOV can select GCC_PLUGINS even if arch does not select HAVE_GCC_PLUGINS. This could cause the unmet direct dependency. Now that Kconfig can test compiler capability, let's handle this in a more sophisticated way. There are two ways to enable KCOV; use the compiler that natively supports -fsanitize-coverage=trace-pc, or build the SANCOV plugin if the compiler has ability to build GCC plugins. Hence, the correct dependency for KCOV is: depends on CC_HAS_SANCOV_TRACE_PC || GCC_PLUGINS You do not need to build the SANCOV plugin if the compiler already supports -fsanitize-coverage=trace-pc. Hence, the select should be: select GCC_PLUGIN_SANCOV if !CC_HAS_SANCOV_TRACE_PC With this, GCC_PLUGIN_SANCOV is selected only when necessary, so scripts/Makefile.gcc-plugins can be cleaner. I also cleaned up Kconfig and scripts/Makefile.kcov as well. Signed-off-by: Masahiro Yamada Reviewed-by: Kees Cook Change-Id: Iad9110eb7b6ecef6dfcec38cf483699c1b85af01 Signed-off-by: Andrey Konovalov Bug: 147413187 --- lib/Kconfig.debug | 14 ++++++++++---- scripts/Makefile.gcc-plugins | 8 ++------ scripts/Makefile.kcov | 24 +++++++++++++++++++++--- scripts/gcc-plugins/Makefile | 4 ---- 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 5bc743f4d402..ec057b40021b 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -740,12 +740,17 @@ config ARCH_HAS_KCOV only for x86_64. KCOV requires testing on other archs, and most likely disabling of instrumentation for some early boot code. +# Upstream uses $(cc-option, -fsanitize-coverage=trace-pc), which requires +# cc-option support. Here we instead check CC in scripts/Makefile.kcov. +config CC_HAS_SANCOV_TRACE_PC + def_bool ARCH_HAS_KCOV + config KCOV bool "Code coverage for fuzzing" depends on ARCH_HAS_KCOV + depends on CC_HAS_SANCOV_TRACE_PC || GCC_PLUGINS select DEBUG_FS - select GCC_PLUGINS if !COMPILE_TEST - select GCC_PLUGIN_SANCOV if !COMPILE_TEST + select GCC_PLUGIN_SANCOV if !CC_HAS_SANCOV_TRACE_PC help KCOV exposes kernel code coverage information in a form suitable for coverage-guided fuzzing (randomized testing). @@ -756,10 +761,11 @@ config KCOV For more details, see Documentation/dev-tools/kcov.rst. +# Upstream uses $(cc-option, -fsanitize-coverage=trace-cmp), which requires +# cc-option support. Here we instead check CC in scripts/Makefile.kcov. config KCOV_ENABLE_COMPARISONS bool "Enable comparison operands collection by KCOV" depends on KCOV - default n help KCOV also exposes operands of every comparison in the instrumented code along with operand sizes and PCs of the comparison instructions. @@ -769,7 +775,7 @@ config KCOV_ENABLE_COMPARISONS config KCOV_INSTRUMENT_ALL bool "Instrument all code by default" depends on KCOV - default y if KCOV + default y help If you are doing generic system call fuzzing (like e.g. syzkaller), then you will want to instrument the whole kernel and you should diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins index 7f5c86246138..708c8f6a5717 100644 --- a/scripts/Makefile.gcc-plugins +++ b/scripts/Makefile.gcc-plugins @@ -14,16 +14,12 @@ ifdef CONFIG_GCC_PLUGINS endif ifdef CONFIG_GCC_PLUGIN_SANCOV - ifeq ($(strip $(CFLAGS_KCOV)),) # It is needed because of the gcc-plugin.sh and gcc version checks. gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so - ifneq ($(PLUGINCC),) - CFLAGS_KCOV := $(SANCOV_PLUGIN) - else + ifeq ($(PLUGINCC),) $(warning warning: cannot use CONFIG_KCOV: -fsanitize-coverage=trace-pc is not supported by compiler) endif - endif endif gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so @@ -38,7 +34,7 @@ ifdef CONFIG_GCC_PLUGINS GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR - export SANCOV_PLUGIN DISABLE_LATENT_ENTROPY_PLUGIN + export DISABLE_LATENT_ENTROPY_PLUGIN ifneq ($(PLUGINCC),) # SANCOV_PLUGIN can be only in CFLAGS_KCOV because avoid duplication. diff --git a/scripts/Makefile.kcov b/scripts/Makefile.kcov index 5cc72037e423..945724d226e8 100644 --- a/scripts/Makefile.kcov +++ b/scripts/Makefile.kcov @@ -1,7 +1,25 @@ ifdef CONFIG_KCOV -CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) -ifeq ($(CONFIG_KCOV_ENABLE_COMPARISONS),y) -CFLAGS_KCOV += $(call cc-option,-fsanitize-coverage=trace-cmp,) + +ifeq ($(call cc-option, -fsanitize-coverage=trace-pc -Werror),) + ifneq ($(CONFIG_COMPILE_TEST),y) + $(error Cannot use CONFIG_KCOV: \ + -fsanitize-coverage=trace-pc is not supported by compiler) + endif +endif + +ifdef CONFIG_KCOV_ENABLE_COMPARISONS + ifeq ($(call cc-option, -fsanitize-coverage=trace-cmp -Werror),) + ifneq ($(CONFIG_COMPILE_TEST),y) + $(error Cannot use CONFIG_KCOV_ENABLE_COMPARISONS: \ + -fsanitize-coverage=trace-cmp is not supported by compiler) + endif + endif endif +kcov-flags-$(CONFIG_CC_HAS_SANCOV_TRACE_PC) += -fsanitize-coverage=trace-pc +kcov-flags-$(CONFIG_KCOV_ENABLE_COMPARISONS) += -fsanitize-coverage=trace-cmp +kcov-flags-$(CONFIG_GCC_PLUGIN_SANCOV) += -fplugin=$(objtree)/scripts/gcc-plugins/sancov_plugin.so + +export CFLAGS_KCOV := $(kcov-flags-y) + endif diff --git a/scripts/gcc-plugins/Makefile b/scripts/gcc-plugins/Makefile index e2ff425f4c7e..ea465799ced5 100644 --- a/scripts/gcc-plugins/Makefile +++ b/scripts/gcc-plugins/Makefile @@ -13,10 +13,6 @@ else export HOST_EXTRACXXFLAGS endif -ifneq ($(CFLAGS_KCOV), $(SANCOV_PLUGIN)) - GCC_PLUGIN := $(filter-out $(SANCOV_PLUGIN), $(GCC_PLUGIN)) -endif - export HOSTLIBS $(obj)/randomize_layout_plugin.o: $(objtree)/$(obj)/randomize_layout_seed.h -- GitLab From bef2ed2af64863db5e14c49f15cf776182a4fd90 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 14 Jun 2018 15:27:37 -0700 Subject: [PATCH 0089/1055] UPSTREAM: kcov: prefault the kcov_area (Upstream commit dc55daff9040a90adce97208e776ee0bf515ab12.) On many architectures the vmalloc area is lazily faulted in upon first access. This is problematic for KCOV, as __sanitizer_cov_trace_pc accesses the (vmalloc'd) kcov_area, and fault handling code may be instrumented. If an access to kcov_area faults, this will result in mutual recursion through the fault handling code and __sanitizer_cov_trace_pc(), eventually leading to stack corruption and/or overflow. We can avoid this by faulting in the kcov_area before __sanitizer_cov_trace_pc() is permitted to access it. Once it has been faulted in, it will remain present in the process page tables, and will not fault again. [akpm@linux-foundation.org: code cleanup] [akpm@linux-foundation.org: add comment explaining kcov_fault_in_area()] [akpm@linux-foundation.org: fancier code comment from Mark] Link: http://lkml.kernel.org/r/20180504135535.53744-3-mark.rutland@arm.com Signed-off-by: Mark Rutland Acked-by: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Ingo Molnar Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Bug: 147413187 Change-Id: Id90248e11b7a0ea2c5d28faf6e55515cd7dc4987 --- kernel/kcov.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/kernel/kcov.c b/kernel/kcov.c index 5be9a60a959f..cf250392c55c 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -324,6 +324,21 @@ static int kcov_close(struct inode *inode, struct file *filep) return 0; } +/* + * Fault in a lazily-faulted vmalloc area before it can be used by + * __santizer_cov_trace_pc(), to avoid recursion issues if any code on the + * vmalloc fault handling path is instrumented. + */ +static void kcov_fault_in_area(struct kcov *kcov) +{ + unsigned long stride = PAGE_SIZE / sizeof(unsigned long); + unsigned long *area = kcov->area; + unsigned long offset; + + for (offset = 0; offset < kcov->size; offset += stride) + READ_ONCE(area[offset]); +} + static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, unsigned long arg) { @@ -372,6 +387,7 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, #endif else return -EINVAL; + kcov_fault_in_area(kcov); /* Cache in task struct for performance. */ t->kcov_size = kcov->size; t->kcov_area = kcov->area; -- GitLab From cc7a64cd0df7ddc308e2d1d7dbe40f9ec611342e Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 14 Jun 2018 15:27:41 -0700 Subject: [PATCH 0090/1055] BACKPORT: sched/core / kcov: avoid kcov_area during task switch (Upstream commit 0ed557aa813922f6f32adec69e266532091c895b.) During a context switch, we first switch_mm() to the next task's mm, then switch_to() that new task. This means that vmalloc'd regions which had previously been faulted in can transiently disappear in the context of the prev task. Functions instrumented by KCOV may try to access a vmalloc'd kcov_area during this window, and as the fault handling code is instrumented, this results in a recursive fault. We must avoid accessing any kcov_area during this window. We can do so with a new flag in kcov_mode, set prior to switching the mm, and cleared once the new task is live. Since task_struct::kcov_mode isn't always a specific enum kcov_mode value, this is made an unsigned int. The manipulation is hidden behind kcov_{prepare,finish}_switch() helpers, which are empty for !CONFIG_KCOV kernels. The code uses macros because I can't use static inline functions without a circular include dependency between and , since the definition of task_struct uses things defined in Link: http://lkml.kernel.org/r/20180504135535.53744-4-mark.rutland@arm.com Signed-off-by: Mark Rutland Acked-by: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Ingo Molnar Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Change-Id: I58f8a16210e6e58b3cca5b9e6976da305bc9a83a Signed-off-by: Andrey Konovalov Bug: 147413187 --- include/linux/kcov.h | 14 ++++++++++++++ include/linux/sched.h | 2 +- kernel/kcov.c | 2 +- kernel/sched/core.c | 3 +++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/linux/kcov.h b/include/linux/kcov.h index 3ecf6f5e3a5f..b76a1807028d 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -22,13 +22,27 @@ enum kcov_mode { KCOV_MODE_TRACE_CMP = 3, }; +#define KCOV_IN_CTXSW (1 << 30) + void kcov_task_init(struct task_struct *t); void kcov_task_exit(struct task_struct *t); +#define kcov_prepare_switch(t) \ +do { \ + (t)->kcov_mode |= KCOV_IN_CTXSW; \ +} while (0) + +#define kcov_finish_switch(t) \ +do { \ + (t)->kcov_mode &= ~KCOV_IN_CTXSW; \ +} while (0) + #else static inline void kcov_task_init(struct task_struct *t) {} static inline void kcov_task_exit(struct task_struct *t) {} +static inline void kcov_prepare_switch(struct task_struct *t) {} +static inline void kcov_finish_switch(struct task_struct *t) {} #endif /* CONFIG_KCOV */ #endif /* _LINUX_KCOV_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 605ed53d26b6..ebea6e14a6bf 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1185,7 +1185,7 @@ struct task_struct { #ifdef CONFIG_KCOV /* Coverage collection mode enabled for this task (0 if disabled): */ - enum kcov_mode kcov_mode; + unsigned int kcov_mode; /* Size of the kcov_area: */ unsigned int kcov_size; diff --git a/kernel/kcov.c b/kernel/kcov.c index cf250392c55c..3ebd09efe72a 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -58,7 +58,7 @@ struct kcov { static bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t) { - enum kcov_mode mode; + unsigned int mode; /* * We are interested in code coverage as a function of a syscall inputs, diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 0b830e61ddde..c0b4be91cd8d 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -2657,6 +2658,7 @@ static inline void prepare_task_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next) { + kcov_prepare_switch(prev); sched_info_switch(rq, prev, next); perf_event_task_sched_out(prev, next); fire_sched_out_preempt_notifiers(prev, next); @@ -2734,6 +2736,7 @@ static struct rq *finish_task_switch(struct task_struct *prev) smp_mb__after_unlock_lock(); finish_lock_switch(rq, prev); finish_arch_post_lock_switch(); + kcov_finish_switch(current); fire_sched_in_preempt_notifiers(current); if (mm) -- GitLab From d1ad2a37ed7e1161f9a04927853b1476e9b33f46 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Fri, 30 Nov 2018 14:10:05 -0800 Subject: [PATCH 0091/1055] UPSTREAM: kernel/kcov.c: mark funcs in __sanitizer_cov_trace_pc() as notrace (Upstream commit 903e8ff86753e6f327bb92166a0665e4ecb8e2e7.) Since __sanitizer_cov_trace_pc() is marked as notrace, function calls in __sanitizer_cov_trace_pc() shouldn't be traced either. ftrace_graph_caller() gets called for each function that isn't marked 'notrace', like canonicalize_ip(). This is the call trace from a run: [ 139.644550] ftrace_graph_caller+0x1c/0x24 [ 139.648352] canonicalize_ip+0x18/0x28 [ 139.652313] __sanitizer_cov_trace_pc+0x14/0x58 [ 139.656184] sched_clock+0x34/0x1e8 [ 139.659759] trace_clock_local+0x40/0x88 [ 139.663722] ftrace_push_return_trace+0x8c/0x1f0 [ 139.667767] prepare_ftrace_return+0xa8/0x100 [ 139.671709] ftrace_graph_caller+0x1c/0x24 Rework so that check_kcov_mode() and canonicalize_ip() that are called from __sanitizer_cov_trace_pc() are also marked as notrace. Link: http://lkml.kernel.org/r/20181128081239.18317-1-anders.roxell@linaro.org Signed-off-by: Arnd Bergmann Signen-off-by: Anders Roxell Co-developed-by: Arnd Bergmann Acked-by: Steven Rostedt (VMware) Cc: Dmitry Vyukov Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: I3f07daa04361aa6020bf6843aeeb57663bd8d169 --- kernel/kcov.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/kcov.c b/kernel/kcov.c index 3ebd09efe72a..97959d7b77e2 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -56,7 +56,7 @@ struct kcov { struct task_struct *t; }; -static bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t) +static notrace bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t) { unsigned int mode; @@ -78,7 +78,7 @@ static bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t) return mode == needed_mode; } -static unsigned long canonicalize_ip(unsigned long ip) +static notrace unsigned long canonicalize_ip(unsigned long ip) { #ifdef CONFIG_RANDOMIZE_BASE ip -= kaslr_offset(); -- GitLab From 37638f9a197402ed0ba2c134852760114416a3e1 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Thu, 3 Jan 2019 15:28:24 -0800 Subject: [PATCH 0092/1055] UPSTREAM: kernel/kcov.c: mark write_comp_data() as notrace (Upstream commit 634724431607f6f46c495dfef801a1c8b44a96d9.) Since __sanitizer_cov_trace_const_cmp4 is marked as notrace, the function called from __sanitizer_cov_trace_const_cmp4 shouldn't be traceable either. ftrace_graph_caller() gets called every time func write_comp_data() gets called if it isn't marked 'notrace'. This is the backtrace from gdb: #0 ftrace_graph_caller () at ../arch/arm64/kernel/entry-ftrace.S:179 #1 0xffffff8010201920 in ftrace_caller () at ../arch/arm64/kernel/entry-ftrace.S:151 #2 0xffffff8010439714 in write_comp_data (type=5, arg1=0, arg2=0, ip=18446743524224276596) at ../kernel/kcov.c:116 #3 0xffffff8010439894 in __sanitizer_cov_trace_const_cmp4 (arg1=, arg2=) at ../kernel/kcov.c:188 #4 0xffffff8010201874 in prepare_ftrace_return (self_addr=18446743524226602768, parent=0xffffff801014b918, frame_pointer=18446743524223531344) at ./include/generated/atomic-instrumented.h:27 #5 0xffffff801020194c in ftrace_graph_caller () at ../arch/arm64/kernel/entry-ftrace.S:182 Rework so that write_comp_data() that are called from __sanitizer_cov_trace_*_cmp*() are marked as 'notrace'. Commit 903e8ff86753 ("kernel/kcov.c: mark funcs in __sanitizer_cov_trace_pc() as notrace") missed to mark write_comp_data() as 'notrace'. When that patch was created gcc-7 was used. In lib/Kconfig.debug config KCOV_ENABLE_COMPARISONS depends on $(cc-option,-fsanitize-coverage=trace-cmp) That code path isn't hit with gcc-7. However, it were that with gcc-8. Link: http://lkml.kernel.org/r/20181206143011.23719-1-anders.roxell@linaro.org Signed-off-by: Anders Roxell Signed-off-by: Arnd Bergmann Co-developed-by: Arnd Bergmann Acked-by: Steven Rostedt (VMware) Cc: Will Deacon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: I12a04221abd2f26f4943f7f36c74fdd24af1c4ad --- kernel/kcov.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/kcov.c b/kernel/kcov.c index 97959d7b77e2..c2277dbdbfb1 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -112,7 +112,7 @@ void notrace __sanitizer_cov_trace_pc(void) EXPORT_SYMBOL(__sanitizer_cov_trace_pc); #ifdef CONFIG_KCOV_ENABLE_COMPARISONS -static void write_comp_data(u64 type, u64 arg1, u64 arg2, u64 ip) +static void notrace write_comp_data(u64 type, u64 arg1, u64 arg2, u64 ip) { struct task_struct *t; u64 *area; -- GitLab From 6d9fd0993c21d848bcfc46eb7cfe04085b4b5c0d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 7 Mar 2019 16:29:56 -0800 Subject: [PATCH 0093/1055] UPSTREAM: kcov: no need to check return value of debugfs_create functions (Upstream commit ec9672d57670d495404f36ab8b651bfefc0ea10b.) When calling debugfs functions, there is no need to ever check the return value. The function can work or not, but the code logic should never do something different based on this. Link: http://lkml.kernel.org/r/20190122152151.16139-46-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman Cc: Andrey Ryabinin Cc: Mark Rutland Cc: Arnd Bergmann Cc: "Steven Rostedt (VMware)" Cc: Dmitry Vyukov Cc: Anders Roxell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: I8ed5dc6aeba3dda8b91ceea4fed5cd9ef058461f --- kernel/kcov.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/kcov.c b/kernel/kcov.c index c2277dbdbfb1..5b0bb281c1a0 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -444,10 +444,8 @@ static int __init kcov_init(void) * there is no need to protect it against removal races. The * use of debugfs_create_file_unsafe() is actually safe here. */ - if (!debugfs_create_file_unsafe("kcov", 0600, NULL, NULL, &kcov_fops)) { - pr_err("failed to create kcov in debugfs\n"); - return -ENOMEM; - } + debugfs_create_file_unsafe("kcov", 0600, NULL, NULL, &kcov_fops); + return 0; } -- GitLab From 3a3cd9cd27ec7d3a7037524d14bbf615951a62ef Mon Sep 17 00:00:00 2001 From: Elena Reshetova Date: Thu, 7 Mar 2019 16:30:00 -0800 Subject: [PATCH 0094/1055] UPSTREAM: kcov: convert kcov.refcount to refcount_t (Upstream commit 39e07cb60860e3162fc377380b8a60409315681e.) atomic_t variables are currently used to implement reference counters with the following properties: - counter is initialized to 1 using atomic_set() - a resource is freed upon counter reaching zero - once counter reaches zero, its further increments aren't allowed - counter schema uses basic atomic operations (set, inc, inc_not_zero, dec_and_test, etc.) Such atomic variables should be converted to a newly provided refcount_t type and API that prevents accidental counter overflows and underflows. This is important since overflows and underflows can lead to use-after-free situation and be exploitable. The variable kcov.refcount is used as pure reference counter. Convert it to refcount_t and fix up the operations. **Important note for maintainers: Some functions from refcount_t API defined in lib/refcount.c have different memory ordering guarantees than their atomic counterparts. The full comparison can be seen in https://lkml.org/lkml/2017/11/15/57 and it is hopefully soon in state to be merged to the documentation tree. Normally the differences should not matter since refcount_t provides enough guarantees to satisfy the refcounting use cases, but in some rare cases it might matter. Please double check that you don't have some undocumented memory guarantees for this variable usage. For the kcov.refcount it might make a difference in following places: - kcov_put(): decrement in refcount_dec_and_test() only provides RELEASE ordering and control dependency on success vs. fully ordered atomic counterpart Link: http://lkml.kernel.org/r/1547634429-772-1-git-send-email-elena.reshetova@intel.com Signed-off-by: Elena Reshetova Suggested-by: Kees Cook Reviewed-by: David Windsor Reviewed-by: Hans Liljestrand Reviewed-by: Dmitry Vyukov Reviewed-by: Andrea Parri Cc: Mark Rutland Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: Ie22524d133af5ab86dcc5cadde4bdca931625d3a --- kernel/kcov.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/kernel/kcov.c b/kernel/kcov.c index 5b0bb281c1a0..2ee38727844a 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -20,6 +20,7 @@ #include #include #include +#include #include /* Number of 64-bit words written per one comparison: */ @@ -44,7 +45,7 @@ struct kcov { * - opened file descriptor * - task with enabled coverage (we can't unwire it from another task) */ - atomic_t refcount; + refcount_t refcount; /* The lock protects mode, size, area and t. */ spinlock_t lock; enum kcov_mode mode; @@ -228,12 +229,12 @@ EXPORT_SYMBOL(__sanitizer_cov_trace_switch); static void kcov_get(struct kcov *kcov) { - atomic_inc(&kcov->refcount); + refcount_inc(&kcov->refcount); } static void kcov_put(struct kcov *kcov) { - if (atomic_dec_and_test(&kcov->refcount)) { + if (refcount_dec_and_test(&kcov->refcount)) { vfree(kcov->area); kfree(kcov); } @@ -312,7 +313,7 @@ static int kcov_open(struct inode *inode, struct file *filep) if (!kcov) return -ENOMEM; kcov->mode = KCOV_MODE_DISABLED; - atomic_set(&kcov->refcount, 1); + refcount_set(&kcov->refcount, 1); spin_lock_init(&kcov->lock); filep->private_data = kcov; return nonseekable_open(inode, filep); -- GitLab From 9b5f12321a8dff8aab4475b922146fa0acb0f7b3 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 18 Apr 2019 17:50:37 -0700 Subject: [PATCH 0095/1055] UPSTREAM: kcov: improve CONFIG_ARCH_HAS_KCOV help text (Upstream commit 40453c4f9bb6d166a56a102a8c51dd24b0801557.) The help text for CONFIG_ARCH_HAS_KCOV is stale, and describes the feature as being enabled only for x86_64, when it is now enabled for several architectures, including arm, arm64, powerpc, and s390. Let's remove that stale help text, and update it along the lines of hat for ARCH_HAS_FORTIFY_SOURCE, better describing when an architecture should select CONFIG_ARCH_HAS_KCOV. Link: http://lkml.kernel.org/r/20190412102733.5154-1-mark.rutland@arm.com Signed-off-by: Mark Rutland Acked-by: Dmitry Vyukov Cc: Kees Cook Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: If1a6cce383c704fc96ea9a267459b665d32fb8bd --- lib/Kconfig.debug | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index ec057b40021b..65ac0511546e 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -736,9 +736,9 @@ endmenu # "Memory Debugging" config ARCH_HAS_KCOV bool help - KCOV does not have any arch-specific code, but currently it is enabled - only for x86_64. KCOV requires testing on other archs, and most likely - disabling of instrumentation for some early boot code. + An architecture should select this when it can successfully + build and run with CONFIG_KCOV. This typically requires + disabling instrumentation for some early boot code. # Upstream uses $(cc-option, -fsanitize-coverage=trace-pc), which requires # cc-option support. Here we instead check CC in scripts/Makefile.kcov. -- GitLab From 5627b215f9825bf9a7fa16626fdf70727f9220d2 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Wed, 4 Dec 2019 16:52:43 -0800 Subject: [PATCH 0096/1055] BACKPORT: kcov: remote coverage support Workaround missing struct_size() support by calculating the size manually. (Upstream commit eec028c9386ed1a692aa01a85b55952202b41619.) Patch series " kcov: collect coverage from usb and vhost", v3. This patchset extends kcov to allow collecting coverage from backgound kernel threads. This extension requires custom annotations for each of the places where coverage collection is desired. This patchset implements this for hub events in the USB subsystem and for vhost workers. See the first patch description for details about the kcov extension. The other two patches apply this kcov extension to USB and vhost. Examples of other subsystems that might potentially benefit from this when custom annotations are added (the list is based on process_one_work() callers for bugs recently reported by syzbot): 1. fs: writeback wb_workfn() worker, 2. net: addrconf_dad_work()/addrconf_verify_work() workers, 3. net: neigh_periodic_work() worker, 4. net/p9: p9_write_work()/p9_read_work() workers, 5. block: blk_mq_run_work_fn() worker. These patches have been used to enable coverage-guided USB fuzzing with syzkaller for the last few years, see the details here: https://github.com/google/syzkaller/blob/master/docs/linux/external_fuzzing_usb.md This patchset has been pushed to the public Linux kernel Gerrit instance: https://linux-review.googlesource.com/c/linux/kernel/git/torvalds/linux/+/1524 This patch (of 3): Add background thread coverage collection ability to kcov. With KCOV_ENABLE coverage is collected only for syscalls that are issued from the current process. With KCOV_REMOTE_ENABLE it's possible to collect coverage for arbitrary parts of the kernel code, provided that those parts are annotated with kcov_remote_start()/kcov_remote_stop(). This allows to collect coverage from two types of kernel background threads: the global ones, that are spawned during kernel boot in a limited number of instances (e.g. one USB hub_event() worker thread is spawned per USB HCD); and the local ones, that are spawned when a user interacts with some kernel interface (e.g. vhost workers). To enable collecting coverage from a global background thread, a unique global handle must be assigned and passed to the corresponding kcov_remote_start() call. Then a userspace process can pass a list of such handles to the KCOV_REMOTE_ENABLE ioctl in the handles array field of the kcov_remote_arg struct. This will attach the used kcov device to the code sections, that are referenced by those handles. Since there might be many local background threads spawned from different userspace processes, we can't use a single global handle per annotation. Instead, the userspace process passes a non-zero handle through the common_handle field of the kcov_remote_arg struct. This common handle gets saved to the kcov_handle field in the current task_struct and needs to be passed to the newly spawned threads via custom annotations. Those threads should in turn be annotated with kcov_remote_start()/kcov_remote_stop(). Internally kcov stores handles as u64 integers. The top byte of a handle is used to denote the id of a subsystem that this handle belongs to, and the lower 4 bytes are used to denote the id of a thread instance within that subsystem. A reserved value 0 is used as a subsystem id for common handles as they don't belong to a particular subsystem. The bytes 4-7 are currently reserved and must be zero. In the future the number of bytes used for the subsystem or handle ids might be increased. When a particular userspace process collects coverage by via a common handle, kcov will collect coverage for each code section that is annotated to use the common handle obtained as kcov_handle from the current task_struct. However non common handles allow to collect coverage selectively from different subsystems. Link: http://lkml.kernel.org/r/e90e315426a384207edbec1d6aa89e43008e4caf.1572366574.git.andreyknvl@google.com Signed-off-by: Andrey Konovalov Cc: Dmitry Vyukov Cc: Greg Kroah-Hartman Cc: Alan Stern Cc: "Michael S. Tsirkin" Cc: Jason Wang Cc: Arnd Bergmann Cc: Steven Rostedt Cc: David Windsor Cc: Elena Reshetova Cc: Anders Roxell Cc: Alexander Potapenko Cc: Marco Elver Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Andrey Konovalov Change-Id: I868c4846a412bfbae16086017e113813571df377 Signed-off-by: Andrey Konovalov Bug: 147413187 --- Documentation/dev-tools/kcov.rst | 129 ++++++++ include/linux/kcov.h | 23 ++ include/linux/sched.h | 8 + include/uapi/linux/kcov.h | 28 ++ kernel/kcov.c | 547 +++++++++++++++++++++++++++++-- 5 files changed, 700 insertions(+), 35 deletions(-) diff --git a/Documentation/dev-tools/kcov.rst b/Documentation/dev-tools/kcov.rst index c2f6452e38ed..b37e8e743af1 100644 --- a/Documentation/dev-tools/kcov.rst +++ b/Documentation/dev-tools/kcov.rst @@ -34,6 +34,7 @@ Profiling data will only become accessible once debugfs has been mounted:: Coverage collection ------------------- + The following program demonstrates coverage collection from within a test program using kcov: @@ -128,6 +129,7 @@ only need to enable coverage (disable happens automatically on thread end). Comparison operands collection ------------------------------ + Comparison operands collection is similar to coverage collection: .. code-block:: c @@ -202,3 +204,130 @@ Comparison operands collection is similar to coverage collection: Note that the kcov modes (coverage collection or comparison operands) are mutually exclusive. + +Remote coverage collection +-------------------------- + +With KCOV_ENABLE coverage is collected only for syscalls that are issued +from the current process. With KCOV_REMOTE_ENABLE it's possible to collect +coverage for arbitrary parts of the kernel code, provided that those parts +are annotated with kcov_remote_start()/kcov_remote_stop(). + +This allows to collect coverage from two types of kernel background +threads: the global ones, that are spawned during kernel boot in a limited +number of instances (e.g. one USB hub_event() worker thread is spawned per +USB HCD); and the local ones, that are spawned when a user interacts with +some kernel interface (e.g. vhost workers). + +To enable collecting coverage from a global background thread, a unique +global handle must be assigned and passed to the corresponding +kcov_remote_start() call. Then a userspace process can pass a list of such +handles to the KCOV_REMOTE_ENABLE ioctl in the handles array field of the +kcov_remote_arg struct. This will attach the used kcov device to the code +sections, that are referenced by those handles. + +Since there might be many local background threads spawned from different +userspace processes, we can't use a single global handle per annotation. +Instead, the userspace process passes a non-zero handle through the +common_handle field of the kcov_remote_arg struct. This common handle gets +saved to the kcov_handle field in the current task_struct and needs to be +passed to the newly spawned threads via custom annotations. Those threads +should in turn be annotated with kcov_remote_start()/kcov_remote_stop(). + +Internally kcov stores handles as u64 integers. The top byte of a handle +is used to denote the id of a subsystem that this handle belongs to, and +the lower 4 bytes are used to denote the id of a thread instance within +that subsystem. A reserved value 0 is used as a subsystem id for common +handles as they don't belong to a particular subsystem. The bytes 4-7 are +currently reserved and must be zero. In the future the number of bytes +used for the subsystem or handle ids might be increased. + +When a particular userspace proccess collects coverage by via a common +handle, kcov will collect coverage for each code section that is annotated +to use the common handle obtained as kcov_handle from the current +task_struct. However non common handles allow to collect coverage +selectively from different subsystems. + +.. code-block:: c + + struct kcov_remote_arg { + unsigned trace_mode; + unsigned area_size; + unsigned num_handles; + uint64_t common_handle; + uint64_t handles[0]; + }; + + #define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) + #define KCOV_DISABLE _IO('c', 101) + #define KCOV_REMOTE_ENABLE _IOW('c', 102, struct kcov_remote_arg) + + #define COVER_SIZE (64 << 10) + + #define KCOV_TRACE_PC 0 + + #define KCOV_SUBSYSTEM_COMMON (0x00ull << 56) + #define KCOV_SUBSYSTEM_USB (0x01ull << 56) + + #define KCOV_SUBSYSTEM_MASK (0xffull << 56) + #define KCOV_INSTANCE_MASK (0xffffffffull) + + static inline __u64 kcov_remote_handle(__u64 subsys, __u64 inst) + { + if (subsys & ~KCOV_SUBSYSTEM_MASK || inst & ~KCOV_INSTANCE_MASK) + return 0; + return subsys | inst; + } + + #define KCOV_COMMON_ID 0x42 + #define KCOV_USB_BUS_NUM 1 + + int main(int argc, char **argv) + { + int fd; + unsigned long *cover, n, i; + struct kcov_remote_arg *arg; + + fd = open("/sys/kernel/debug/kcov", O_RDWR); + if (fd == -1) + perror("open"), exit(1); + if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE)) + perror("ioctl"), exit(1); + cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if ((void*)cover == MAP_FAILED) + perror("mmap"), exit(1); + + /* Enable coverage collection via common handle and from USB bus #1. */ + arg = calloc(1, sizeof(*arg) + sizeof(uint64_t)); + if (!arg) + perror("calloc"), exit(1); + arg->trace_mode = KCOV_TRACE_PC; + arg->area_size = COVER_SIZE; + arg->num_handles = 1; + arg->common_handle = kcov_remote_handle(KCOV_SUBSYSTEM_COMMON, + KCOV_COMMON_ID); + arg->handles[0] = kcov_remote_handle(KCOV_SUBSYSTEM_USB, + KCOV_USB_BUS_NUM); + if (ioctl(fd, KCOV_REMOTE_ENABLE, arg)) + perror("ioctl"), free(arg), exit(1); + free(arg); + + /* + * Here the user needs to trigger execution of a kernel code section + * that is either annotated with the common handle, or to trigger some + * activity on USB bus #1. + */ + sleep(2); + + n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + for (i = 0; i < n; i++) + printf("0x%lx\n", cover[i + 1]); + if (ioctl(fd, KCOV_DISABLE, 0)) + perror("ioctl"), exit(1); + if (munmap(cover, COVER_SIZE * sizeof(unsigned long))) + perror("munmap"), exit(1); + if (close(fd)) + perror("close"), exit(1); + return 0; + } diff --git a/include/linux/kcov.h b/include/linux/kcov.h index b76a1807028d..a10e84707d82 100644 --- a/include/linux/kcov.h +++ b/include/linux/kcov.h @@ -37,12 +37,35 @@ do { \ (t)->kcov_mode &= ~KCOV_IN_CTXSW; \ } while (0) +/* See Documentation/dev-tools/kcov.rst for usage details. */ +void kcov_remote_start(u64 handle); +void kcov_remote_stop(void); +u64 kcov_common_handle(void); + +static inline void kcov_remote_start_common(u64 id) +{ + kcov_remote_start(kcov_remote_handle(KCOV_SUBSYSTEM_COMMON, id)); +} + +static inline void kcov_remote_start_usb(u64 id) +{ + kcov_remote_start(kcov_remote_handle(KCOV_SUBSYSTEM_USB, id)); +} + #else static inline void kcov_task_init(struct task_struct *t) {} static inline void kcov_task_exit(struct task_struct *t) {} static inline void kcov_prepare_switch(struct task_struct *t) {} static inline void kcov_finish_switch(struct task_struct *t) {} +static inline void kcov_remote_start(u64 handle) {} +static inline void kcov_remote_stop(void) {} +static inline u64 kcov_common_handle(void) +{ + return 0; +} +static inline void kcov_remote_start_common(u64 id) {} +static inline void kcov_remote_start_usb(u64 id) {} #endif /* CONFIG_KCOV */ #endif /* _LINUX_KCOV_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index ebea6e14a6bf..445d83cc6721 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1184,6 +1184,8 @@ struct task_struct { #endif /* CONFIG_TRACING */ #ifdef CONFIG_KCOV + /* See kernel/kcov.c for more details. */ + /* Coverage collection mode enabled for this task (0 if disabled): */ unsigned int kcov_mode; @@ -1195,6 +1197,12 @@ struct task_struct { /* KCOV descriptor wired with this task or NULL: */ struct kcov *kcov; + + /* KCOV common handle for remote coverage collection: */ + u64 kcov_handle; + + /* KCOV sequence number: */ + int kcov_sequence; #endif #ifdef CONFIG_MEMCG diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h index 9529867717a8..409d3ad1e6e2 100644 --- a/include/uapi/linux/kcov.h +++ b/include/uapi/linux/kcov.h @@ -4,9 +4,24 @@ #include +/* + * Argument for KCOV_REMOTE_ENABLE ioctl, see Documentation/dev-tools/kcov.rst + * and the comment before kcov_remote_start() for usage details. + */ +struct kcov_remote_arg { + unsigned int trace_mode; /* KCOV_TRACE_PC or KCOV_TRACE_CMP */ + unsigned int area_size; /* Length of coverage buffer in words */ + unsigned int num_handles; /* Size of handles array */ + __u64 common_handle; + __u64 handles[0]; +}; + +#define KCOV_REMOTE_MAX_HANDLES 0x100 + #define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) #define KCOV_ENABLE _IO('c', 100) #define KCOV_DISABLE _IO('c', 101) +#define KCOV_REMOTE_ENABLE _IOW('c', 102, struct kcov_remote_arg) enum { /* @@ -32,4 +47,17 @@ enum { #define KCOV_CMP_SIZE(n) ((n) << 1) #define KCOV_CMP_MASK KCOV_CMP_SIZE(3) +#define KCOV_SUBSYSTEM_COMMON (0x00ull << 56) +#define KCOV_SUBSYSTEM_USB (0x01ull << 56) + +#define KCOV_SUBSYSTEM_MASK (0xffull << 56) +#define KCOV_INSTANCE_MASK (0xffffffffull) + +static inline __u64 kcov_remote_handle(__u64 subsys, __u64 inst) +{ + if (subsys & ~KCOV_SUBSYSTEM_MASK || inst & ~KCOV_INSTANCE_MASK) + return 0; + return subsys | inst; +} + #endif /* _LINUX_KCOV_IOCTLS_H */ diff --git a/kernel/kcov.c b/kernel/kcov.c index 2ee38727844a..2f0048ef4b64 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -21,8 +22,11 @@ #include #include #include +#include #include +#define kcov_debug(fmt, ...) pr_debug("%s: " fmt, __func__, ##__VA_ARGS__) + /* Number of 64-bit words written per one comparison: */ #define KCOV_WORDS_PER_CMP 4 @@ -44,19 +48,100 @@ struct kcov { * Reference counter. We keep one for: * - opened file descriptor * - task with enabled coverage (we can't unwire it from another task) + * - each code section for remote coverage collection */ refcount_t refcount; /* The lock protects mode, size, area and t. */ spinlock_t lock; enum kcov_mode mode; - /* Size of arena (in long's for KCOV_MODE_TRACE). */ - unsigned size; + /* Size of arena (in long's). */ + unsigned int size; /* Coverage buffer shared with user space. */ void *area; /* Task for which we collect coverage, or NULL. */ struct task_struct *t; + /* Collecting coverage from remote (background) threads. */ + bool remote; + /* Size of remote area (in long's). */ + unsigned int remote_size; + /* + * Sequence is incremented each time kcov is reenabled, used by + * kcov_remote_stop(), see the comment there. + */ + int sequence; }; +struct kcov_remote_area { + struct list_head list; + unsigned int size; +}; + +struct kcov_remote { + u64 handle; + struct kcov *kcov; + struct hlist_node hnode; +}; + +static DEFINE_SPINLOCK(kcov_remote_lock); +static DEFINE_HASHTABLE(kcov_remote_map, 4); +static struct list_head kcov_remote_areas = LIST_HEAD_INIT(kcov_remote_areas); + +/* Must be called with kcov_remote_lock locked. */ +static struct kcov_remote *kcov_remote_find(u64 handle) +{ + struct kcov_remote *remote; + + hash_for_each_possible(kcov_remote_map, remote, hnode, handle) { + if (remote->handle == handle) + return remote; + } + return NULL; +} + +static struct kcov_remote *kcov_remote_add(struct kcov *kcov, u64 handle) +{ + struct kcov_remote *remote; + + if (kcov_remote_find(handle)) + return ERR_PTR(-EEXIST); + remote = kmalloc(sizeof(*remote), GFP_ATOMIC); + if (!remote) + return ERR_PTR(-ENOMEM); + remote->handle = handle; + remote->kcov = kcov; + hash_add(kcov_remote_map, &remote->hnode, handle); + return remote; +} + +/* Must be called with kcov_remote_lock locked. */ +static struct kcov_remote_area *kcov_remote_area_get(unsigned int size) +{ + struct kcov_remote_area *area; + struct list_head *pos; + + kcov_debug("size = %u\n", size); + list_for_each(pos, &kcov_remote_areas) { + area = list_entry(pos, struct kcov_remote_area, list); + if (area->size == size) { + list_del(&area->list); + kcov_debug("rv = %px\n", area); + return area; + } + } + kcov_debug("rv = NULL\n"); + return NULL; +} + +/* Must be called with kcov_remote_lock locked. */ +static void kcov_remote_area_put(struct kcov_remote_area *area, + unsigned int size) +{ + kcov_debug("area = %px, size = %u\n", area, size); + INIT_LIST_HEAD(&area->list); + area->size = size; + list_add(&area->list, &kcov_remote_areas); +} + static notrace bool check_kcov_mode(enum kcov_mode needed_mode, struct task_struct *t) { unsigned int mode; @@ -73,7 +158,7 @@ static notrace bool check_kcov_mode(enum kcov_mode needed_mode, struct task_stru * in_interrupt() returns false (e.g. preempt_schedule_irq()). * READ_ONCE()/barrier() effectively provides load-acquire wrt * interrupts, there are paired barrier()/WRITE_ONCE() in - * kcov_ioctl_locked(). + * kcov_start(). */ barrier(); return mode == needed_mode; @@ -227,6 +312,78 @@ void notrace __sanitizer_cov_trace_switch(u64 val, u64 *cases) EXPORT_SYMBOL(__sanitizer_cov_trace_switch); #endif /* ifdef CONFIG_KCOV_ENABLE_COMPARISONS */ +static void kcov_start(struct task_struct *t, unsigned int size, + void *area, enum kcov_mode mode, int sequence) +{ + kcov_debug("t = %px, size = %u, area = %px\n", t, size, area); + /* Cache in task struct for performance. */ + t->kcov_size = size; + t->kcov_area = area; + /* See comment in check_kcov_mode(). */ + barrier(); + WRITE_ONCE(t->kcov_mode, mode); + t->kcov_sequence = sequence; +} + +static void kcov_stop(struct task_struct *t) +{ + WRITE_ONCE(t->kcov_mode, KCOV_MODE_DISABLED); + barrier(); + t->kcov_size = 0; + t->kcov_area = NULL; +} + +static void kcov_task_reset(struct task_struct *t) +{ + kcov_stop(t); + t->kcov = NULL; + t->kcov_sequence = 0; + t->kcov_handle = 0; +} + +void kcov_task_init(struct task_struct *t) +{ + kcov_task_reset(t); + t->kcov_handle = current->kcov_handle; +} + +static void kcov_reset(struct kcov *kcov) +{ + kcov->t = NULL; + kcov->mode = KCOV_MODE_INIT; + kcov->remote = false; + kcov->remote_size = 0; + kcov->sequence++; +} + +static void kcov_remote_reset(struct kcov *kcov) +{ + int bkt; + struct kcov_remote *remote; + struct hlist_node *tmp; + + spin_lock(&kcov_remote_lock); + hash_for_each_safe(kcov_remote_map, bkt, tmp, remote, hnode) { + if (remote->kcov != kcov) + continue; + kcov_debug("removing handle %llx\n", remote->handle); + hash_del(&remote->hnode); + kfree(remote); + } + /* Do reset before unlock to prevent races with kcov_remote_start(). */ + kcov_reset(kcov); + spin_unlock(&kcov_remote_lock); +} + +static void kcov_disable(struct task_struct *t, struct kcov *kcov) +{ + kcov_task_reset(t); + if (kcov->remote) + kcov_remote_reset(kcov); + else + kcov_reset(kcov); +} + static void kcov_get(struct kcov *kcov) { refcount_inc(&kcov->refcount); @@ -235,20 +392,12 @@ static void kcov_get(struct kcov *kcov) static void kcov_put(struct kcov *kcov) { if (refcount_dec_and_test(&kcov->refcount)) { + kcov_remote_reset(kcov); vfree(kcov->area); kfree(kcov); } } -void kcov_task_init(struct task_struct *t) -{ - WRITE_ONCE(t->kcov_mode, KCOV_MODE_DISABLED); - barrier(); - t->kcov_size = 0; - t->kcov_area = NULL; - t->kcov = NULL; -} - void kcov_task_exit(struct task_struct *t) { struct kcov *kcov; @@ -256,15 +405,36 @@ void kcov_task_exit(struct task_struct *t) kcov = t->kcov; if (kcov == NULL) return; + spin_lock(&kcov->lock); + kcov_debug("t = %px, kcov->t = %px\n", t, kcov->t); + /* + * For KCOV_ENABLE devices we want to make sure that t->kcov->t == t, + * which comes down to: + * WARN_ON(!kcov->remote && kcov->t != t); + * + * For KCOV_REMOTE_ENABLE devices, the exiting task is either: + * 2. A remote task between kcov_remote_start() and kcov_remote_stop(). + * In this case we should print a warning right away, since a task + * shouldn't be exiting when it's in a kcov coverage collection + * section. Here t points to the task that is collecting remote + * coverage, and t->kcov->t points to the thread that created the + * kcov device. Which means that to detect this case we need to + * check that t != t->kcov->t, and this gives us the following: + * WARN_ON(kcov->remote && kcov->t != t); + * + * 2. The task that created kcov exiting without calling KCOV_DISABLE, + * and then again we can make sure that t->kcov->t == t: + * WARN_ON(kcov->remote && kcov->t != t); + * + * By combining all three checks into one we get: + */ if (WARN_ON(kcov->t != t)) { spin_unlock(&kcov->lock); return; } /* Just to not leave dangling references behind. */ - kcov_task_init(t); - kcov->t = NULL; - kcov->mode = KCOV_MODE_INIT; + kcov_disable(t, kcov); spin_unlock(&kcov->lock); kcov_put(kcov); } @@ -313,6 +483,7 @@ static int kcov_open(struct inode *inode, struct file *filep) if (!kcov) return -ENOMEM; kcov->mode = KCOV_MODE_DISABLED; + kcov->sequence = 1; refcount_set(&kcov->refcount, 1); spin_lock_init(&kcov->lock); filep->private_data = kcov; @@ -325,6 +496,20 @@ static int kcov_close(struct inode *inode, struct file *filep) return 0; } +static int kcov_get_mode(unsigned long arg) +{ + if (arg == KCOV_TRACE_PC) + return KCOV_MODE_TRACE_PC; + else if (arg == KCOV_TRACE_CMP) +#ifdef CONFIG_KCOV_ENABLE_COMPARISONS + return KCOV_MODE_TRACE_CMP; +#else + return -ENOTSUPP; +#endif + else + return -EINVAL; +} + /* * Fault in a lazily-faulted vmalloc area before it can be used by * __santizer_cov_trace_pc(), to avoid recursion issues if any code on the @@ -340,14 +525,35 @@ static void kcov_fault_in_area(struct kcov *kcov) READ_ONCE(area[offset]); } +static inline bool kcov_check_handle(u64 handle, bool common_valid, + bool uncommon_valid, bool zero_valid) +{ + if (handle & ~(KCOV_SUBSYSTEM_MASK | KCOV_INSTANCE_MASK)) + return false; + switch (handle & KCOV_SUBSYSTEM_MASK) { + case KCOV_SUBSYSTEM_COMMON: + return (handle & KCOV_INSTANCE_MASK) ? + common_valid : zero_valid; + case KCOV_SUBSYSTEM_USB: + return uncommon_valid; + default: + return false; + } + return false; +} + static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, unsigned long arg) { struct task_struct *t; unsigned long size, unused; + int mode, i; + struct kcov_remote_arg *remote_arg; + struct kcov_remote *remote; switch (cmd) { case KCOV_INIT_TRACE: + kcov_debug("KCOV_INIT_TRACE\n"); /* * Enable kcov in trace mode and setup buffer size. * Must happen before anything else. @@ -366,6 +572,7 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, kcov->mode = KCOV_MODE_INIT; return 0; case KCOV_ENABLE: + kcov_debug("KCOV_ENABLE\n"); /* * Enable coverage for the current task. * At this point user must have been enabled trace mode, @@ -378,29 +585,20 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, t = current; if (kcov->t != NULL || t->kcov != NULL) return -EBUSY; - if (arg == KCOV_TRACE_PC) - kcov->mode = KCOV_MODE_TRACE_PC; - else if (arg == KCOV_TRACE_CMP) -#ifdef CONFIG_KCOV_ENABLE_COMPARISONS - kcov->mode = KCOV_MODE_TRACE_CMP; -#else - return -ENOTSUPP; -#endif - else - return -EINVAL; + mode = kcov_get_mode(arg); + if (mode < 0) + return mode; kcov_fault_in_area(kcov); - /* Cache in task struct for performance. */ - t->kcov_size = kcov->size; - t->kcov_area = kcov->area; - /* See comment in check_kcov_mode(). */ - barrier(); - WRITE_ONCE(t->kcov_mode, kcov->mode); + kcov->mode = mode; + kcov_start(t, kcov->size, kcov->area, kcov->mode, + kcov->sequence); t->kcov = kcov; kcov->t = t; - /* This is put either in kcov_task_exit() or in KCOV_DISABLE. */ + /* Put either in kcov_task_exit() or in KCOV_DISABLE. */ kcov_get(kcov); return 0; case KCOV_DISABLE: + kcov_debug("KCOV_DISABLE\n"); /* Disable coverage for the current task. */ unused = arg; if (unused != 0 || current->kcov != kcov) @@ -408,11 +606,65 @@ static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, t = current; if (WARN_ON(kcov->t != t)) return -EINVAL; - kcov_task_init(t); - kcov->t = NULL; - kcov->mode = KCOV_MODE_INIT; + kcov_disable(t, kcov); kcov_put(kcov); return 0; + case KCOV_REMOTE_ENABLE: + kcov_debug("KCOV_REMOTE_ENABLE\n"); + if (kcov->mode != KCOV_MODE_INIT || !kcov->area) + return -EINVAL; + t = current; + if (kcov->t != NULL || t->kcov != NULL) + return -EBUSY; + remote_arg = (struct kcov_remote_arg *)arg; + mode = kcov_get_mode(remote_arg->trace_mode); + if (mode < 0) + return mode; + if (remote_arg->area_size > LONG_MAX / sizeof(unsigned long)) + return -EINVAL; + kcov->mode = mode; + t->kcov = kcov; + kcov->t = t; + kcov->remote = true; + kcov->remote_size = remote_arg->area_size; + spin_lock(&kcov_remote_lock); + for (i = 0; i < remote_arg->num_handles; i++) { + kcov_debug("handle %llx\n", remote_arg->handles[i]); + if (!kcov_check_handle(remote_arg->handles[i], + false, true, false)) { + spin_unlock(&kcov_remote_lock); + kcov_disable(t, kcov); + return -EINVAL; + } + remote = kcov_remote_add(kcov, remote_arg->handles[i]); + if (IS_ERR(remote)) { + spin_unlock(&kcov_remote_lock); + kcov_disable(t, kcov); + return PTR_ERR(remote); + } + } + if (remote_arg->common_handle) { + kcov_debug("common handle %llx\n", + remote_arg->common_handle); + if (!kcov_check_handle(remote_arg->common_handle, + true, false, false)) { + spin_unlock(&kcov_remote_lock); + kcov_disable(t, kcov); + return -EINVAL; + } + remote = kcov_remote_add(kcov, + remote_arg->common_handle); + if (IS_ERR(remote)) { + spin_unlock(&kcov_remote_lock); + kcov_disable(t, kcov); + return PTR_ERR(remote); + } + t->kcov_handle = remote_arg->common_handle; + } + spin_unlock(&kcov_remote_lock); + /* Put either in kcov_task_exit() or in KCOV_DISABLE. */ + kcov_get(kcov); + return 0; default: return -ENOTTY; } @@ -422,11 +674,35 @@ static long kcov_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { struct kcov *kcov; int res; + struct kcov_remote_arg *remote_arg = NULL; + unsigned int remote_num_handles; + unsigned long remote_arg_size; + + if (cmd == KCOV_REMOTE_ENABLE) { + if (get_user(remote_num_handles, (unsigned __user *)(arg + + offsetof(struct kcov_remote_arg, num_handles)))) + return -EFAULT; + if (remote_num_handles > KCOV_REMOTE_MAX_HANDLES) + return -EINVAL; + remote_arg_size = sizeof(*remote_arg) + + sizeof(remote_arg->handles[0]) * remote_num_handles; + remote_arg = memdup_user((void __user *)arg, remote_arg_size); + if (IS_ERR(remote_arg)) + return PTR_ERR(remote_arg); + if (remote_arg->num_handles != remote_num_handles) { + kfree(remote_arg); + return -EINVAL; + } + arg = (unsigned long)remote_arg; + } kcov = filep->private_data; spin_lock(&kcov->lock); res = kcov_ioctl_locked(kcov, cmd, arg); spin_unlock(&kcov->lock); + + kfree(remote_arg); + return res; } @@ -438,6 +714,207 @@ static const struct file_operations kcov_fops = { .release = kcov_close, }; +/* + * kcov_remote_start() and kcov_remote_stop() can be used to annotate a section + * of code in a kernel background thread to allow kcov to be used to collect + * coverage from that part of code. + * + * The handle argument of kcov_remote_start() identifies a code section that is + * used for coverage collection. A userspace process passes this handle to + * KCOV_REMOTE_ENABLE ioctl to make the used kcov device start collecting + * coverage for the code section identified by this handle. + * + * The usage of these annotations in the kernel code is different depending on + * the type of the kernel thread whose code is being annotated. + * + * For global kernel threads that are spawned in a limited number of instances + * (e.g. one USB hub_event() worker thread is spawned per USB HCD), each + * instance must be assigned a unique 4-byte instance id. The instance id is + * then combined with a 1-byte subsystem id to get a handle via + * kcov_remote_handle(subsystem_id, instance_id). + * + * For local kernel threads that are spawned from system calls handler when a + * user interacts with some kernel interface (e.g. vhost workers), a handle is + * passed from a userspace process as the common_handle field of the + * kcov_remote_arg struct (note, that the user must generate a handle by using + * kcov_remote_handle() with KCOV_SUBSYSTEM_COMMON as the subsystem id and an + * arbitrary 4-byte non-zero number as the instance id). This common handle + * then gets saved into the task_struct of the process that issued the + * KCOV_REMOTE_ENABLE ioctl. When this proccess issues system calls that spawn + * kernel threads, the common handle must be retrived via kcov_common_handle() + * and passed to the spawned threads via custom annotations. Those kernel + * threads must in turn be annotated with kcov_remote_start(common_handle) and + * kcov_remote_stop(). All of the threads that are spawned by the same process + * obtain the same handle, hence the name "common". + * + * See Documentation/dev-tools/kcov.rst for more details. + * + * Internally, this function looks up the kcov device associated with the + * provided handle, allocates an area for coverage collection, and saves the + * pointers to kcov and area into the current task_struct to allow coverage to + * be collected via __sanitizer_cov_trace_pc() + * In turns kcov_remote_stop() clears those pointers from task_struct to stop + * collecting coverage and copies all collected coverage into the kcov area. + */ +void kcov_remote_start(u64 handle) +{ + struct kcov_remote *remote; + void *area; + struct task_struct *t; + unsigned int size; + enum kcov_mode mode; + int sequence; + + if (WARN_ON(!kcov_check_handle(handle, true, true, true))) + return; + if (WARN_ON(!in_task())) + return; + t = current; + /* + * Check that kcov_remote_start is not called twice + * nor called by user tasks (with enabled kcov). + */ + if (WARN_ON(t->kcov)) + return; + + kcov_debug("handle = %llx\n", handle); + + spin_lock(&kcov_remote_lock); + remote = kcov_remote_find(handle); + if (!remote) { + kcov_debug("no remote found"); + spin_unlock(&kcov_remote_lock); + return; + } + /* Put in kcov_remote_stop(). */ + kcov_get(remote->kcov); + t->kcov = remote->kcov; + /* + * Read kcov fields before unlock to prevent races with + * KCOV_DISABLE / kcov_remote_reset(). + */ + size = remote->kcov->remote_size; + mode = remote->kcov->mode; + sequence = remote->kcov->sequence; + area = kcov_remote_area_get(size); + spin_unlock(&kcov_remote_lock); + + if (!area) { + area = vmalloc(size * sizeof(unsigned long)); + if (!area) { + t->kcov = NULL; + kcov_put(remote->kcov); + return; + } + } + /* Reset coverage size. */ + *(u64 *)area = 0; + + kcov_debug("area = %px, size = %u", area, size); + + kcov_start(t, size, area, mode, sequence); + +} +EXPORT_SYMBOL(kcov_remote_start); + +static void kcov_move_area(enum kcov_mode mode, void *dst_area, + unsigned int dst_area_size, void *src_area) +{ + u64 word_size = sizeof(unsigned long); + u64 count_size, entry_size_log; + u64 dst_len, src_len; + void *dst_entries, *src_entries; + u64 dst_occupied, dst_free, bytes_to_move, entries_moved; + + kcov_debug("%px %u <= %px %lu\n", + dst_area, dst_area_size, src_area, *(unsigned long *)src_area); + + switch (mode) { + case KCOV_MODE_TRACE_PC: + dst_len = READ_ONCE(*(unsigned long *)dst_area); + src_len = *(unsigned long *)src_area; + count_size = sizeof(unsigned long); + entry_size_log = __ilog2_u64(sizeof(unsigned long)); + break; + case KCOV_MODE_TRACE_CMP: + dst_len = READ_ONCE(*(u64 *)dst_area); + src_len = *(u64 *)src_area; + count_size = sizeof(u64); + BUILD_BUG_ON(!is_power_of_2(KCOV_WORDS_PER_CMP)); + entry_size_log = __ilog2_u64(sizeof(u64) * KCOV_WORDS_PER_CMP); + break; + default: + WARN_ON(1); + return; + } + + /* As arm can't divide u64 integers use log of entry size. */ + if (dst_len > ((dst_area_size * word_size - count_size) >> + entry_size_log)) + return; + dst_occupied = count_size + (dst_len << entry_size_log); + dst_free = dst_area_size * word_size - dst_occupied; + bytes_to_move = min(dst_free, src_len << entry_size_log); + dst_entries = dst_area + dst_occupied; + src_entries = src_area + count_size; + memcpy(dst_entries, src_entries, bytes_to_move); + entries_moved = bytes_to_move >> entry_size_log; + + switch (mode) { + case KCOV_MODE_TRACE_PC: + WRITE_ONCE(*(unsigned long *)dst_area, dst_len + entries_moved); + break; + case KCOV_MODE_TRACE_CMP: + WRITE_ONCE(*(u64 *)dst_area, dst_len + entries_moved); + break; + default: + break; + } +} + +/* See the comment before kcov_remote_start() for usage details. */ +void kcov_remote_stop(void) +{ + struct task_struct *t = current; + struct kcov *kcov = t->kcov; + void *area = t->kcov_area; + unsigned int size = t->kcov_size; + int sequence = t->kcov_sequence; + + if (!kcov) { + kcov_debug("no kcov found\n"); + return; + } + + kcov_stop(t); + t->kcov = NULL; + + spin_lock(&kcov->lock); + /* + * KCOV_DISABLE could have been called between kcov_remote_start() + * and kcov_remote_stop(), hence the check. + */ + kcov_debug("move if: %d == %d && %d\n", + sequence, kcov->sequence, (int)kcov->remote); + if (sequence == kcov->sequence && kcov->remote) + kcov_move_area(kcov->mode, kcov->area, kcov->size, area); + spin_unlock(&kcov->lock); + + spin_lock(&kcov_remote_lock); + kcov_remote_area_put(area, size); + spin_unlock(&kcov_remote_lock); + + kcov_put(kcov); +} +EXPORT_SYMBOL(kcov_remote_stop); + +/* See the comment before kcov_remote_start() for usage details. */ +u64 kcov_common_handle(void) +{ + return current->kcov_handle; +} +EXPORT_SYMBOL(kcov_common_handle); + static int __init kcov_init(void) { /* -- GitLab From 00ce9d07b9a6daa5e1190263ab85f55f1a522f27 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Wed, 4 Dec 2019 16:52:47 -0800 Subject: [PATCH 0097/1055] UPSTREAM: usb, kcov: collect coverage from hub_event (Upstream commit 95d23dc27bde0ab4b25f7ade5e2fddc08dd97d9b.) Add kcov_remote_start()/kcov_remote_stop() annotations to the hub_event() function, which is responsible for processing events on USB buses, in particular events that happen during USB device enumeration. Since hub_event() is run in a global background kernel thread (see Documentation/dev-tools/kcov.rst for details), each USB bus gets a unique global handle from the USB subsystem kcov handle range. As the result kcov can now be used to collect coverage from events that happen on a particular USB bus. [akpm@linux-foundation.org: avoid patch conflicts to make life easier for Andrew] Link: http://lkml.kernel.org/r/de4fe1c219db2d002d905dc1736e2a3bfa1db997.1572366574.git.andreyknvl@google.com Signed-off-by: Andrey Konovalov Reviewed-by: Greg Kroah-Hartman Cc: Alan Stern Cc: Alexander Potapenko Cc: Anders Roxell Cc: Arnd Bergmann Cc: David Windsor Cc: Dmitry Vyukov Cc: Elena Reshetova Cc: Jason Wang Cc: Marco Elver Cc: "Michael S. Tsirkin" Cc: Steven Rostedt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: I4ef39331fe5b789459938e998b1f557406627ba6 --- drivers/usb/core/hub.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 4efccf8bf99f..294b9e48d3b3 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -5183,6 +5184,8 @@ static void hub_event(struct work_struct *work) hub_dev = hub->intfdev; intf = to_usb_interface(hub_dev); + kcov_remote_start_usb((u64)hdev->bus->busnum); + dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n", hdev->state, hdev->maxchild, /* NOTE: expects max 15 ports... */ @@ -5289,6 +5292,8 @@ static void hub_event(struct work_struct *work) /* Balance the stuff in kick_hub_wq() and allow autosuspend */ usb_autopm_put_interface(intf); kref_put(&hub->kref, hub_release); + + kcov_remote_stop(); } static const struct usb_device_id hub_id_table[] = { -- GitLab From 47ba92a2552b60441f0dc69b94a731b9c1d7bfb9 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Wed, 4 Dec 2019 16:52:50 -0800 Subject: [PATCH 0098/1055] UPSTREAM: vhost, kcov: collect coverage from vhost_worker (Upstream commit 8f6a7f96dc29cefe16ab60f06f9c3a43510b96fd.) Add kcov_remote_start()/kcov_remote_stop() annotations to the vhost_worker() function, which is responsible for processing vhost works. Since vhost_worker() threads are spawned per vhost device instance the common kcov handle is used for kcov_remote_start()/stop() annotations (see Documentation/dev-tools/kcov.rst for details). As the result kcov can now be used to collect coverage from vhost worker threads. Link: http://lkml.kernel.org/r/e49d5d154e5da6c9ada521d2b7ce10a49ce9f98b.1572366574.git.andreyknvl@google.com Signed-off-by: Andrey Konovalov Cc: Alan Stern Cc: Alexander Potapenko Cc: Anders Roxell Cc: Arnd Bergmann Cc: David Windsor Cc: Dmitry Vyukov Cc: Elena Reshetova Cc: Greg Kroah-Hartman Cc: Jason Wang Cc: Marco Elver Cc: "Michael S. Tsirkin" Cc: Steven Rostedt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: Ie99a67ede00a839a28472877e5c3263db69d1c58 --- drivers/vhost/vhost.c | 6 ++++++ drivers/vhost/vhost.h | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 3d7bea15c57b..85edacc0be47 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "vhost.h" @@ -361,7 +362,9 @@ static int vhost_worker(void *data) llist_for_each_entry_safe(work, work_next, node, node) { clear_bit(VHOST_WORK_QUEUED, &work->flags); __set_current_state(TASK_RUNNING); + kcov_remote_start_common(dev->kcov_handle); work->fn(work); + kcov_remote_stop(); if (need_resched()) schedule(); } @@ -521,6 +524,7 @@ long vhost_dev_set_owner(struct vhost_dev *dev) /* No owner, become one */ dev->mm = get_task_mm(current); + dev->kcov_handle = kcov_common_handle(); worker = kthread_create(vhost_worker, dev, "vhost-%d", current->pid); if (IS_ERR(worker)) { err = PTR_ERR(worker); @@ -546,6 +550,7 @@ long vhost_dev_set_owner(struct vhost_dev *dev) if (dev->mm) mmput(dev->mm); dev->mm = NULL; + dev->kcov_handle = 0; err_mm: return err; } @@ -665,6 +670,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked) if (dev->worker) { kthread_stop(dev->worker); dev->worker = NULL; + dev->kcov_handle = 0; } if (dev->mm) mmput(dev->mm); diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 950c5c4e4ee3..6e8f67ff1e1c 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -175,6 +175,7 @@ struct vhost_dev { wait_queue_head_t wait; int weight; int byte_weight; + u64 kcov_handle; }; bool vhost_exceeds_weight(struct vhost_virtqueue *vq, int pkts, int total_len); -- GitLab From 3852ef1983e37088e8ef7f21c80bfbbb8287e493 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Sat, 4 Jan 2020 12:59:39 -0800 Subject: [PATCH 0099/1055] UPSTREAM: kcov: fix struct layout for kcov_remote_arg (Upstream commit a69b83e1ae7f6c5ff2cc310870c1708405d86be2.) Make the layout of kcov_remote_arg the same for 32-bit and 64-bit code. This makes it more convenient to write userspace apps that can be compiled into 32-bit or 64-bit binaries and still work with the same 64-bit kernel. Also use proper __u32 types in uapi headers instead of unsigned ints. Link: http://lkml.kernel.org/r/9e91020876029cfefc9211ff747685eba9536426.1575638983.git.andreyknvl@google.com Fixes: eec028c9386ed1a ("kcov: remote coverage support") Signed-off-by: Andrey Konovalov Acked-by: Marco Elver Cc: Greg Kroah-Hartman Cc: Alan Stern Cc: Felipe Balbi Cc: Chunfeng Yun Cc: "Jacky . Cao @ sony . com" Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Marco Elver Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Andrey Konovalov Bug: 147413187 Change-Id: I25a7107841048b3735db94c89199f9de73615333 --- Documentation/dev-tools/kcov.rst | 10 +++++----- include/uapi/linux/kcov.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/dev-tools/kcov.rst b/Documentation/dev-tools/kcov.rst index b37e8e743af1..f254173b180f 100644 --- a/Documentation/dev-tools/kcov.rst +++ b/Documentation/dev-tools/kcov.rst @@ -251,11 +251,11 @@ selectively from different subsystems. .. code-block:: c struct kcov_remote_arg { - unsigned trace_mode; - unsigned area_size; - unsigned num_handles; - uint64_t common_handle; - uint64_t handles[0]; + __u32 trace_mode; + __u32 area_size; + __u32 num_handles; + __aligned_u64 common_handle; + __aligned_u64 handles[0]; }; #define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) diff --git a/include/uapi/linux/kcov.h b/include/uapi/linux/kcov.h index 409d3ad1e6e2..1d0350e44ae3 100644 --- a/include/uapi/linux/kcov.h +++ b/include/uapi/linux/kcov.h @@ -9,11 +9,11 @@ * and the comment before kcov_remote_start() for usage details. */ struct kcov_remote_arg { - unsigned int trace_mode; /* KCOV_TRACE_PC or KCOV_TRACE_CMP */ - unsigned int area_size; /* Length of coverage buffer in words */ - unsigned int num_handles; /* Size of handles array */ - __u64 common_handle; - __u64 handles[0]; + __u32 trace_mode; /* KCOV_TRACE_PC or KCOV_TRACE_CMP */ + __u32 area_size; /* Length of coverage buffer in words */ + __u32 num_handles; /* Size of handles array */ + __aligned_u64 common_handle; + __aligned_u64 handles[0]; }; #define KCOV_REMOTE_MAX_HANDLES 0x100 -- GitLab From c807f43500e14ed24599106745bb6005665f74d6 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 19 Dec 2019 12:02:03 +0000 Subject: [PATCH 0100/1055] chardev: Avoid potential use-after-free in 'chrdev_open()' commit 68faa679b8be1a74e6663c21c3a9d25d32f1c079 upstream. 'chrdev_open()' calls 'cdev_get()' to obtain a reference to the 'struct cdev *' stashed in the 'i_cdev' field of the target inode structure. If the pointer is NULL, then it is initialised lazily by looking up the kobject in the 'cdev_map' and so the whole procedure is protected by the 'cdev_lock' spinlock to serialise initialisation of the shared pointer. Unfortunately, it is possible for the initialising thread to fail *after* installing the new pointer, for example if the subsequent '->open()' call on the file fails. In this case, 'cdev_put()' is called, the reference count on the kobject is dropped and, if nobody else has taken a reference, the release function is called which finally clears 'inode->i_cdev' from 'cdev_purge()' before potentially freeing the object. The problem here is that a racing thread can happily take the 'cdev_lock' and see the non-NULL pointer in the inode, which can result in a refcount increment from zero and a warning: | ------------[ cut here ]------------ | refcount_t: addition on 0; use-after-free. | WARNING: CPU: 2 PID: 6385 at lib/refcount.c:25 refcount_warn_saturate+0x6d/0xf0 | Modules linked in: | CPU: 2 PID: 6385 Comm: repro Not tainted 5.5.0-rc2+ #22 | Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 | RIP: 0010:refcount_warn_saturate+0x6d/0xf0 | Code: 05 55 9a 15 01 01 e8 9d aa c8 ff 0f 0b c3 80 3d 45 9a 15 01 00 75 ce 48 c7 c7 00 9c 62 b3 c6 08 | RSP: 0018:ffffb524c1b9bc70 EFLAGS: 00010282 | RAX: 0000000000000000 RBX: ffff9e9da1f71390 RCX: 0000000000000000 | RDX: ffff9e9dbbd27618 RSI: ffff9e9dbbd18798 RDI: ffff9e9dbbd18798 | RBP: 0000000000000000 R08: 000000000000095f R09: 0000000000000039 | R10: 0000000000000000 R11: ffffb524c1b9bb20 R12: ffff9e9da1e8c700 | R13: ffffffffb25ee8b0 R14: 0000000000000000 R15: ffff9e9da1e8c700 | FS: 00007f3b87d26700(0000) GS:ffff9e9dbbd00000(0000) knlGS:0000000000000000 | CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 | CR2: 00007fc16909c000 CR3: 000000012df9c000 CR4: 00000000000006e0 | DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 | DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 | Call Trace: | kobject_get+0x5c/0x60 | cdev_get+0x2b/0x60 | chrdev_open+0x55/0x220 | ? cdev_put.part.3+0x20/0x20 | do_dentry_open+0x13a/0x390 | path_openat+0x2c8/0x1470 | do_filp_open+0x93/0x100 | ? selinux_file_ioctl+0x17f/0x220 | do_sys_open+0x186/0x220 | do_syscall_64+0x48/0x150 | entry_SYSCALL_64_after_hwframe+0x44/0xa9 | RIP: 0033:0x7f3b87efcd0e | Code: 89 54 24 08 e8 a3 f4 ff ff 8b 74 24 0c 48 8b 3c 24 41 89 c0 44 8b 54 24 08 b8 01 01 00 00 89 f4 | RSP: 002b:00007f3b87d259f0 EFLAGS: 00000293 ORIG_RAX: 0000000000000101 | RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f3b87efcd0e | RDX: 0000000000000000 RSI: 00007f3b87d25a80 RDI: 00000000ffffff9c | RBP: 00007f3b87d25e90 R08: 0000000000000000 R09: 0000000000000000 | R10: 0000000000000000 R11: 0000000000000293 R12: 00007ffe188f504e | R13: 00007ffe188f504f R14: 00007f3b87d26700 R15: 0000000000000000 | ---[ end trace 24f53ca58db8180a ]--- Since 'cdev_get()' can already fail to obtain a reference, simply move it over to use 'kobject_get_unless_zero()' instead of 'kobject_get()', which will cause the racing thread to return -ENXIO if the initialising thread fails unexpectedly. Cc: Hillf Danton Cc: Andrew Morton Cc: Al Viro Reported-by: syzbot+82defefbbd8527e1c2cb@syzkaller.appspotmail.com Signed-off-by: Will Deacon Cc: stable Link: https://lore.kernel.org/r/20191219120203.32691-1-will@kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/char_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/char_dev.c b/fs/char_dev.c index 20ce45c7c57c..715d76b00108 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -361,7 +361,7 @@ static struct kobject *cdev_get(struct cdev *p) if (owner && !try_module_get(owner)) return NULL; - kobj = kobject_get(&p->kobj); + kobj = kobject_get_unless_zero(&p->kobj); if (!kobj) module_put(owner); return kobj; -- GitLab From c07d275dd30f95d063ba27a83e8793bcf1afb8d7 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 26 Dec 2019 07:57:54 -0800 Subject: [PATCH 0101/1055] usb: chipidea: host: Disable port power only if previously enabled commit c1ffba305dbcf3fb9ca969c20a97acbddc38f8e9 upstream. On shutdown, ehci_power_off() is called unconditionally to power off each port, even if it was never called to power on the port. For chipidea, this results in a call to ehci_ci_portpower() with a request to power off ports even if the port was never powered on. This results in the following warning from the regulator code. WARNING: CPU: 0 PID: 182 at drivers/regulator/core.c:2596 _regulator_disable+0x1a8/0x210 unbalanced disables for usb_otg2_vbus Modules linked in: CPU: 0 PID: 182 Comm: init Not tainted 5.4.6 #1 Hardware name: Freescale i.MX7 Dual (Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0xe0/0x10c) [] (dump_stack) from [] (__warn+0xf4/0x10c) [] (__warn) from [] (warn_slowpath_fmt+0x78/0xbc) [] (warn_slowpath_fmt) from [] (_regulator_disable+0x1a8/0x210) [] (_regulator_disable) from [] (regulator_disable+0x38/0xe8) [] (regulator_disable) from [] (ehci_ci_portpower+0x38/0xdc) [] (ehci_ci_portpower) from [] (ehci_port_power+0x50/0xa4) [] (ehci_port_power) from [] (ehci_silence_controller+0x5c/0xc4) [] (ehci_silence_controller) from [] (ehci_stop+0x3c/0xcc) [] (ehci_stop) from [] (usb_remove_hcd+0xe0/0x19c) [] (usb_remove_hcd) from [] (host_stop+0x38/0xa8) [] (host_stop) from [] (ci_hdrc_remove+0x44/0xe4) ... Keeping track of the power enable state avoids the warning and traceback. Fixes: c8679a2fb8dec ("usb: chipidea: host: add portpower override") Cc: Michael Grzeschik Cc: Peter Chen Cc: stable@vger.kernel.org Signed-off-by: Guenter Roeck Acked-by: Peter Chen Link: https://lore.kernel.org/r/20191226155754.25451-1-linux@roeck-us.net Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/host.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 18cb8e46262d..83683a5627f3 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -37,6 +37,7 @@ static int (*orig_bus_suspend)(struct usb_hcd *hcd); struct ehci_ci_priv { struct regulator *reg_vbus; + bool enabled; }; static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) @@ -48,7 +49,7 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) int ret = 0; int port = HCS_N_PORTS(ehci->hcs_params); - if (priv->reg_vbus) { + if (priv->reg_vbus && enable != priv->enabled) { if (port > 1) { dev_warn(dev, "Not support multi-port regulator control\n"); @@ -64,6 +65,7 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) enable ? "enable" : "disable", ret); return ret; } + priv->enabled = enable; } if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) { -- GitLab From c33be6e4898f646b6ac9f6adb65c1c7670f70444 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 4 Jan 2020 12:09:36 +0100 Subject: [PATCH 0102/1055] ALSA: usb-audio: Apply the sample rate quirk for Bose Companion 5 commit 51d4efab7865e6ea6a4ebcd25b3f03c019515c4c upstream. Bose Companion 5 (with USB ID 05a7:1020) doesn't seem supporting reading back the sample rate, so the existing quirk is needed. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=206063 Cc: Link: https://lore.kernel.org/r/20200104110936.14288-1-tiwai@suse.de Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index ad14d6b78bdc..51ee7910e98c 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1143,6 +1143,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */ case USB_ID(0x05A3, 0x9420): /* ELP HD USB Camera */ + case USB_ID(0x05a7, 0x1020): /* Bose Companion 5 */ case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */ case USB_ID(0x1395, 0x740a): /* Sennheiser DECT */ case USB_ID(0x1901, 0x0191): /* GE B850V3 CP2114 audio interface */ -- GitLab From bbfcd088dec42f9b1b019dca6e67cc574bd7b967 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Fri, 3 Jan 2020 16:24:06 +0800 Subject: [PATCH 0103/1055] ALSA: hda/realtek - Add new codec supported for ALCS1200A commit 6d9ffcff646bbd0ede6c2a59f4cd28414ecec6e0 upstream. Add ALCS1200A supported. It was similar as ALC900. Signed-off-by: Kailang Yang Cc: Link: https://lore.kernel.org/r/a9bd3cdaa02d4fa197623448d5c51e50@realtek.com Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- 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 41e3c77d5fb7..69877ee47740 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -396,6 +396,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) break; case 0x10ec0899: case 0x10ec0900: + case 0x10ec0b00: case 0x10ec1168: case 0x10ec1220: alc_update_coef_idx(codec, 0x7, 1<<1, 0); @@ -2389,6 +2390,7 @@ static int patch_alc882(struct hda_codec *codec) case 0x10ec0882: case 0x10ec0885: case 0x10ec0900: + case 0x10ec0b00: case 0x10ec1220: break; default: @@ -8398,6 +8400,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662), HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882), HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882), + HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882), HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882), HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882), {} /* terminator */ -- GitLab From b2d1f611a7c46d2ae13fc9b54128eddc4bd04e8a Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Tue, 7 Jan 2020 17:22:19 +0800 Subject: [PATCH 0104/1055] ALSA: hda/realtek - Set EAPD control to default for ALC222 commit 9194a1ebbc56d7006835e2b4cacad301201fb832 upstream. Set EAPD control to verb control. Signed-off-by: Kailang Yang Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 69877ee47740..5a7afbeb612d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -378,6 +378,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0672: alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */ break; + case 0x10ec0222: case 0x10ec0623: alc_update_coef_idx(codec, 0x19, 1<<13, 0); break; -- GitLab From d51eac9941a45be04f97c886656dc853db69e160 Mon Sep 17 00:00:00 2001 From: Kaitao Cheng Date: Tue, 31 Dec 2019 05:35:30 -0800 Subject: [PATCH 0105/1055] kernel/trace: Fix do not unregister tracepoints when register sched_migrate_task fail commit 50f9ad607ea891a9308e67b81f774c71736d1098 upstream. In the function, if register_trace_sched_migrate_task() returns error, sched_switch/sched_wakeup_new/sched_wakeup won't unregister. That is why fail_deprobe_sched_switch was added. Link: http://lkml.kernel.org/r/20191231133530.2794-1-pilgrimtao@gmail.com Cc: stable@vger.kernel.org Fixes: 478142c39c8c2 ("tracing: do not grab lock in wakeup latency function tracing") Signed-off-by: Kaitao Cheng Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_sched_wakeup.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c index 0fa9dadf3f4f..a5a4b5663163 100644 --- a/kernel/trace/trace_sched_wakeup.c +++ b/kernel/trace/trace_sched_wakeup.c @@ -640,7 +640,7 @@ static void start_wakeup_tracer(struct trace_array *tr) if (ret) { pr_info("wakeup trace: Couldn't activate tracepoint" " probe to kernel_sched_migrate_task\n"); - return; + goto fail_deprobe_sched_switch; } wakeup_reset(tr); @@ -658,6 +658,8 @@ static void start_wakeup_tracer(struct trace_array *tr) printk(KERN_ERR "failed to start wakeup tracer\n"); return; +fail_deprobe_sched_switch: + unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL); fail_deprobe_wake_new: unregister_trace_sched_wakeup_new(probe_wakeup, NULL); fail_deprobe: -- GitLab From f12e2598a5a2871dbba539ec4e943246594b4256 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Thu, 2 Jan 2020 22:02:41 -0500 Subject: [PATCH 0106/1055] tracing: Have stack tracer compile when MCOUNT_INSN_SIZE is not defined commit b8299d362d0837ae39e87e9019ebe6b736e0f035 upstream. On some archs with some configurations, MCOUNT_INSN_SIZE is not defined, and this makes the stack tracer fail to compile. Just define it to zero in this case. Link: https://lore.kernel.org/r/202001020219.zvE3vsty%lkp@intel.com Cc: stable@vger.kernel.org Fixes: 4df297129f622 ("tracing: Remove most or all of stack tracer stack size from stack_max_size") Reported-by: kbuild test robot Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_stack.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 719a52a4064a..6f9091f874a9 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c @@ -196,6 +196,11 @@ check_stack(unsigned long ip, unsigned long *stack) local_irq_restore(flags); } +/* Some archs may not define MCOUNT_INSN_SIZE */ +#ifndef MCOUNT_INSN_SIZE +# define MCOUNT_INSN_SIZE 0 +#endif + static void stack_trace_call(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *pt_regs) -- GitLab From c54db442f5b2bb3de2cafb49dcc45d029e519cc6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 10 Dec 2019 16:26:11 -0500 Subject: [PATCH 0107/1055] HID: Fix slab-out-of-bounds read in hid_field_extract commit 8ec321e96e056de84022c032ffea253431a83c3c upstream. The syzbot fuzzer found a slab-out-of-bounds bug in the HID report handler. The bug was caused by a report descriptor which included a field with size 12 bits and count 4899, for a total size of 7349 bytes. The usbhid driver uses at most a single-page 4-KB buffer for reports. In the test there wasn't any problem about overflowing the buffer, since only one byte was received from the device. Rather, the bug occurred when the HID core tried to extract the data from the report fields, which caused it to try reading data beyond the end of the allocated buffer. This patch fixes the problem by rejecting any report whose total length exceeds the HID_MAX_BUFFER_SIZE limit (minus one byte to allow for a possible report index). In theory a device could have a report longer than that, but if there was such a thing we wouldn't handle it correctly anyway. Reported-and-tested-by: syzbot+09ef48aa58261464b621@syzkaller.appspotmail.com Signed-off-by: Alan Stern CC: Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 6a04b56d161b..2d089d3954e3 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -268,6 +268,12 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign offset = report->size; report->size += parser->global.report_size * parser->global.report_count; + /* Total size check: Allow for possible report index byte */ + if (report->size > (HID_MAX_BUFFER_SIZE - 1) << 3) { + hid_err(parser->device, "report is too long\n"); + return -1; + } + if (!parser->local.usage_index) /* Ignore padding fields */ return 0; -- GitLab From 90a26bdc2f73c1d2a1d764d3d00e75228fc6b48e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 4 Dec 2019 03:43:55 +0100 Subject: [PATCH 0108/1055] HID: uhid: Fix returning EPOLLOUT from uhid_char_poll commit be54e7461ffdc5809b67d2aeefc1ddc9a91470c7 upstream. Always return EPOLLOUT from uhid_char_poll to allow polling /dev/uhid for writable state. Fixes: 1f9dec1e0164 ("HID: uhid: allow poll()'ing on uhid devices") Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/uhid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 6f67d73b184e..e63b761f600a 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -25,6 +25,7 @@ #include #include #include +#include #define UHID_NAME "uhid" #define UHID_BUFSIZE 32 @@ -774,7 +775,7 @@ static unsigned int uhid_char_poll(struct file *file, poll_table *wait) if (uhid->head != uhid->tail) return POLLIN | POLLRDNORM; - return 0; + return EPOLLOUT | EPOLLWRNORM; } static const struct file_operations uhid_fops = { -- GitLab From 1df54fdd3f989a140ab3fa6c9f1c485288421a96 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 10 Dec 2019 12:32:31 +0100 Subject: [PATCH 0109/1055] can: gs_usb: gs_usb_probe(): use descriptors of current altsetting commit 2f361cd9474ab2c4ab9ac8db20faf81e66c6279b upstream. Make sure to always use the descriptors of the current alternate setting to avoid future issues when accessing fields that may differ between settings. Signed-off-by: Johan Hovold Fixes: d08e973a77d1 ("can: gs_usb: Added support for the GS_USB CAN devices") Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/usb/gs_usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index bfbf80949600..aed8ab6d6c5b 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -926,7 +926,7 @@ static int gs_usb_probe(struct usb_interface *intf, GS_USB_BREQ_HOST_FORMAT, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 1, - intf->altsetting[0].desc.bInterfaceNumber, + intf->cur_altsetting->desc.bInterfaceNumber, hconf, sizeof(*hconf), 1000); @@ -949,7 +949,7 @@ static int gs_usb_probe(struct usb_interface *intf, GS_USB_BREQ_DEVICE_CONFIG, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 1, - intf->altsetting[0].desc.bInterfaceNumber, + intf->cur_altsetting->desc.bInterfaceNumber, dconf, sizeof(*dconf), 1000); -- GitLab From e08e3dda248f115c77fc59016d26fdc1fd19cf58 Mon Sep 17 00:00:00 2001 From: Florian Faber Date: Thu, 26 Dec 2019 19:51:24 +0100 Subject: [PATCH 0110/1055] can: mscan: mscan_rx_poll(): fix rx path lockup when returning from polling to irq mode commit 2d77bd61a2927be8f4e00d9478fe6996c47e8d45 upstream. Under load, the RX side of the mscan driver can get stuck while TX still works. Restarting the interface locks up the system. This behaviour could be reproduced reliably on a MPC5121e based system. The patch fixes the return value of the NAPI polling function (should be the number of processed packets, not constant 1) and the condition under which IRQs are enabled again after polling is finished. With this patch, no more lockups were observed over a test period of ten days. Fixes: afa17a500a36 ("net/can: add driver for mscan family & mpc52xx_mscan") Signed-off-by: Florian Faber Cc: linux-stable Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/mscan/mscan.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index acb708fc1463..0a7d818a06f3 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -392,13 +392,12 @@ static int mscan_rx_poll(struct napi_struct *napi, int quota) struct net_device *dev = napi->dev; struct mscan_regs __iomem *regs = priv->reg_base; struct net_device_stats *stats = &dev->stats; - int npackets = 0; - int ret = 1; + int work_done = 0; struct sk_buff *skb; struct can_frame *frame; u8 canrflg; - while (npackets < quota) { + while (work_done < quota) { canrflg = in_8(®s->canrflg); if (!(canrflg & (MSCAN_RXF | MSCAN_ERR_IF))) break; @@ -419,18 +418,18 @@ static int mscan_rx_poll(struct napi_struct *napi, int quota) stats->rx_packets++; stats->rx_bytes += frame->can_dlc; - npackets++; + work_done++; netif_receive_skb(skb); } - if (!(in_8(®s->canrflg) & (MSCAN_RXF | MSCAN_ERR_IF))) { - napi_complete(&priv->napi); - clear_bit(F_RX_PROGRESS, &priv->flags); - if (priv->can.state < CAN_STATE_BUS_OFF) - out_8(®s->canrier, priv->shadow_canrier); - ret = 0; + if (work_done < quota) { + if (likely(napi_complete_done(&priv->napi, work_done))) { + clear_bit(F_RX_PROGRESS, &priv->flags); + if (priv->can.state < CAN_STATE_BUS_OFF) + out_8(®s->canrier, priv->shadow_canrier); + } } - return ret; + return work_done; } static irqreturn_t mscan_isr(int irq, void *dev_id) -- GitLab From 54a5ba5136c188c9d349236cc0a0abc5dc0a899d Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Sat, 7 Dec 2019 19:34:18 +0100 Subject: [PATCH 0111/1055] can: can_dropped_invalid_skb(): ensure an initialized headroom in outgoing CAN sk_buffs commit e7153bf70c3496bac00e7e4f395bb8d8394ac0ea upstream. KMSAN sysbot detected a read access to an untinitialized value in the headroom of an outgoing CAN related sk_buff. When using CAN sockets this area is filled appropriately - but when using a packet socket this initialization is missing. The problematic read access occurs in the CAN receive path which can only be triggered when the sk_buff is sent through a (virtual) CAN interface. So we check in the sending path whether we need to perform the missing initializations. Fixes: d3b58c47d330d ("can: replace timestamp as unique skb attribute") Reported-by: syzbot+b02ff0707a97e4e79ebb@syzkaller.appspotmail.com Signed-off-by: Oliver Hartkopp Tested-by: Oliver Hartkopp Cc: linux-stable # >= v4.1 Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- include/linux/can/dev.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index c0c0b992210e..995903c7055b 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h @@ -18,6 +18,7 @@ #include #include #include +#include #include /* @@ -90,6 +91,36 @@ struct can_priv { #define get_can_dlc(i) (min_t(__u8, (i), CAN_MAX_DLC)) #define get_canfd_dlc(i) (min_t(__u8, (i), CANFD_MAX_DLC)) +/* Check for outgoing skbs that have not been created by the CAN subsystem */ +static inline bool can_skb_headroom_valid(struct net_device *dev, + struct sk_buff *skb) +{ + /* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */ + if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv))) + return false; + + /* af_packet does not apply CAN skb specific settings */ + if (skb->ip_summed == CHECKSUM_NONE) { + /* init headroom */ + can_skb_prv(skb)->ifindex = dev->ifindex; + can_skb_prv(skb)->skbcnt = 0; + + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* preform proper loopback on capable devices */ + if (dev->flags & IFF_ECHO) + skb->pkt_type = PACKET_LOOPBACK; + else + skb->pkt_type = PACKET_HOST; + + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); + } + + return true; +} + /* Drop a given socketbuffer if it does not contain a valid CAN frame. */ static inline bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb) @@ -107,6 +138,9 @@ static inline bool can_dropped_invalid_skb(struct net_device *dev, } else goto inval_skb; + if (!can_skb_headroom_valid(dev, skb)) + goto inval_skb; + return false; inval_skb: -- GitLab From dfeb44f281b14c56a99203b119e4c6f4386390d6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 5 Jan 2020 17:03:56 +0100 Subject: [PATCH 0112/1055] gpiolib: acpi: Turn dmi_system_id table into a generic quirk table commit 1ad1b54099c231aed8f6f257065c1b322583f264 upstream. Turn the existing run_edge_events_on_boot_blacklist dmi_system_id table into a generic quirk table, storing the quirks in the driver_data ptr. This is a preparation patch for adding other types of (DMI based) quirks. Cc: stable@vger.kernel.org Reviewed-by: Andy Shevchenko Acked-by: Mika Westerberg Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20200105160357.97154-2-hdegoede@redhat.com Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpiolib-acpi.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 3aa7fe6baf2a..e2f933682182 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -24,6 +24,8 @@ #include "gpiolib.h" +#define QUIRK_NO_EDGE_EVENTS_ON_BOOT 0x01l + static int run_edge_events_on_boot = -1; module_param(run_edge_events_on_boot, int, 0444); MODULE_PARM_DESC(run_edge_events_on_boot, @@ -1312,7 +1314,7 @@ static int acpi_gpio_handle_deferred_request_irqs(void) /* We must use _sync so that this runs after the first deferred_probe run */ late_initcall_sync(acpi_gpio_handle_deferred_request_irqs); -static const struct dmi_system_id run_edge_events_on_boot_blacklist[] = { +static const struct dmi_system_id gpiolib_acpi_quirks[] = { { /* * The Minix Neo Z83-4 has a micro-USB-B id-pin handler for @@ -1322,7 +1324,8 @@ static const struct dmi_system_id run_edge_events_on_boot_blacklist[] = { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "MINIX"), DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"), - } + }, + .driver_data = (void *)QUIRK_NO_EDGE_EVENTS_ON_BOOT, }, { /* @@ -1334,15 +1337,23 @@ static const struct dmi_system_id run_edge_events_on_boot_blacklist[] = { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Wortmann_AG"), DMI_MATCH(DMI_PRODUCT_NAME, "TERRA_PAD_1061"), - } + }, + .driver_data = (void *)QUIRK_NO_EDGE_EVENTS_ON_BOOT, }, {} /* Terminating entry */ }; static int acpi_gpio_setup_params(void) { + const struct dmi_system_id *id; + long quirks = 0; + + id = dmi_first_match(gpiolib_acpi_quirks); + if (id) + quirks = (long)id->driver_data; + if (run_edge_events_on_boot < 0) { - if (dmi_check_system(run_edge_events_on_boot_blacklist)) + if (quirks & QUIRK_NO_EDGE_EVENTS_ON_BOOT) run_edge_events_on_boot = 0; else run_edge_events_on_boot = 1; -- GitLab From fbfb42b7268ec0459785d335a6fefee24c8a94b6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 5 Jan 2020 17:03:57 +0100 Subject: [PATCH 0113/1055] gpiolib: acpi: Add honor_wakeup module-option + quirk mechanism commit aa23ca3d98f756d5b1e503fb140665fb24a41a38 upstream. On some laptops enabling wakeup on the GPIO interrupts used for ACPI _AEI event handling causes spurious wakeups. This commit adds a new honor_wakeup option, defaulting to true (our current behavior), which can be used to disable wakeup on troublesome hardware to avoid these spurious wakeups. This is a workaround for an architectural problem with s2idle under Linux where we do not have any mechanism to immediately go back to sleep after wakeup events, other then for embedded-controller events using the standard ACPI EC interface, for details see: https://lore.kernel.org/linux-acpi/61450f9b-cbc6-0c09-8b3a-aff6bf9a0b3c@redhat.com/ One series of laptops which is not able to suspend without this workaround is the HP x2 10 Cherry Trail models, this commit adds a DMI based quirk which makes sets honor_wakeup to false on these models. Cc: stable@vger.kernel.org Reviewed-by: Andy Shevchenko Acked-by: Mika Westerberg Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20200105160357.97154-3-hdegoede@redhat.com Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpiolib-acpi.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index e2f933682182..c7b9125c8ec2 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -25,12 +25,18 @@ #include "gpiolib.h" #define QUIRK_NO_EDGE_EVENTS_ON_BOOT 0x01l +#define QUIRK_NO_WAKEUP 0x02l static int run_edge_events_on_boot = -1; module_param(run_edge_events_on_boot, int, 0444); MODULE_PARM_DESC(run_edge_events_on_boot, "Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto"); +static int honor_wakeup = -1; +module_param(honor_wakeup, int, 0444); +MODULE_PARM_DESC(honor_wakeup, + "Honor the ACPI wake-capable flag: 0=no, 1=yes, -1=auto"); + /** * struct acpi_gpio_event - ACPI GPIO event handler data * @@ -341,7 +347,7 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares, event->handle = evt_handle; event->handler = handler; event->irq = irq; - event->irq_is_wake = agpio->wake_capable == ACPI_WAKE_CAPABLE; + event->irq_is_wake = honor_wakeup && agpio->wake_capable == ACPI_WAKE_CAPABLE; event->pin = pin; event->desc = desc; @@ -1340,6 +1346,23 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = { }, .driver_data = (void *)QUIRK_NO_EDGE_EVENTS_ON_BOOT, }, + { + /* + * Various HP X2 10 Cherry Trail models use an external + * embedded-controller connected via I2C + an ACPI GPIO + * event handler. The embedded controller generates various + * spurious wakeup events when suspended. So disable wakeup + * for its handler (it uses the only ACPI GPIO event handler). + * This breaks wakeup when opening the lid, the user needs + * to press the power-button to wakeup the system. The + * alternative is suspend simply not working, which is worse. + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP x2 Detachable 10-p0XX"), + }, + .driver_data = (void *)QUIRK_NO_WAKEUP, + }, {} /* Terminating entry */ }; @@ -1359,6 +1382,13 @@ static int acpi_gpio_setup_params(void) run_edge_events_on_boot = 1; } + if (honor_wakeup < 0) { + if (quirks & QUIRK_NO_WAKEUP) + honor_wakeup = 0; + else + honor_wakeup = 1; + } + return 0; } -- GitLab From e77914f232115b4967491b5fb48a0dc8330e2d4a Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Fri, 20 Dec 2019 21:15:59 +0000 Subject: [PATCH 0114/1055] staging: vt6656: set usb_set_intfdata on driver fail. commit c0bcf9f3f5b661d4ace2a64a79ef661edd2a4dc8 upstream. intfdata will contain stale pointer when the device is detached after failed initialization when referenced in vt6656_disconnect Provide driver access to it here and NULL it. Cc: stable Signed-off-by: Malcolm Priestley Link: https://lore.kernel.org/r/6de448d7-d833-ef2e-dd7b-3ef9992fee0e@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/device.h | 1 + drivers/staging/vt6656/main_usb.c | 1 + drivers/staging/vt6656/wcmd.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h index 74715c854856..705fffa59da9 100644 --- a/drivers/staging/vt6656/device.h +++ b/drivers/staging/vt6656/device.h @@ -269,6 +269,7 @@ struct vnt_private { u8 mac_hw; /* netdev */ struct usb_device *usb; + struct usb_interface *intf; u64 tsf_time; u8 rx_rate; diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index cc6d8778fe5b..645ea16b53d5 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -954,6 +954,7 @@ vt6656_probe(struct usb_interface *intf, const struct usb_device_id *id) priv = hw->priv; priv->hw = hw; priv->usb = udev; + priv->intf = intf; vnt_set_options(priv); diff --git a/drivers/staging/vt6656/wcmd.c b/drivers/staging/vt6656/wcmd.c index b2fc17f1381b..3f6ccdeb6dec 100644 --- a/drivers/staging/vt6656/wcmd.c +++ b/drivers/staging/vt6656/wcmd.c @@ -109,6 +109,7 @@ void vnt_run_command(struct work_struct *work) if (vnt_init(priv)) { /* If fail all ends TODO retry */ dev_err(&priv->usb->dev, "failed to start\n"); + usb_set_intfdata(priv->intf, NULL); ieee80211_free_hw(priv->hw); return; } -- GitLab From 3a56fda03237994891658d420c35b07d053d3a3d Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Thu, 19 Dec 2019 11:07:07 +0100 Subject: [PATCH 0115/1055] USB: serial: option: add ZLP support for 0x1bc7/0x9010 commit 2438c3a19dec5e98905fd3ffcc2f24716aceda6b upstream. Telit FN980 flashing device 0x1bc7/0x9010 requires zero packet to be sent if out data size is is equal to the endpoint max size. Signed-off-by: Daniele Palmas [ johan: switch operands in conditional ] Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 8 ++++++++ drivers/usb/serial/usb-wwan.h | 1 + drivers/usb/serial/usb_wwan.c | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index dc9a1139e7e1..e69e31539914 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -570,6 +570,9 @@ static void option_instat_callback(struct urb *urb); /* Interface must have two endpoints */ #define NUMEP2 BIT(16) +/* Device needs ZLP */ +#define ZLP BIT(17) + static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, @@ -1201,6 +1204,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(1) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1901, 0xff), /* Telit LN940 (MBIM) */ .driver_info = NCTRL(0) }, + { USB_DEVICE(TELIT_VENDOR_ID, 0x9010), /* Telit SBL FN980 flashing device */ + .driver_info = NCTRL(0) | ZLP }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff), .driver_info = RSVD(1) }, @@ -2109,6 +2114,9 @@ static int option_attach(struct usb_serial *serial) if (!(device_flags & NCTRL(iface_desc->bInterfaceNumber))) data->use_send_setup = 1; + if (device_flags & ZLP) + data->use_zlp = 1; + spin_lock_init(&data->susp_lock); usb_set_serial_data(serial, data); diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h index d28dab4b9eff..9879773fb39e 100644 --- a/drivers/usb/serial/usb-wwan.h +++ b/drivers/usb/serial/usb-wwan.h @@ -36,6 +36,7 @@ struct usb_wwan_intf_private { spinlock_t susp_lock; unsigned int suspended:1; unsigned int use_send_setup:1; + unsigned int use_zlp:1; int in_flight; unsigned int open_ports; void *private; diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 59bfcb3da116..95e9576c2fe6 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -492,6 +492,7 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port, void (*callback) (struct urb *)) { struct usb_serial *serial = port->serial; + struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); struct urb *urb; urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ @@ -502,6 +503,9 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port, usb_sndbulkpipe(serial->dev, endpoint) | dir, buf, len, callback, ctx); + if (intfdata->use_zlp && dir == USB_DIR_OUT) + urb->transfer_flags |= URB_ZERO_PACKET; + return urb; } -- GitLab From b095f9e2e8ea53c4830ba81183a3ce8721aea0ce Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 7 Jan 2020 09:26:24 -0600 Subject: [PATCH 0116/1055] usb: musb: fix idling for suspend after disconnect interrupt commit 5fbf7a2534703fd71159d3d71504b0ad01b43394 upstream. When disconnected as USB B-device, suspend interrupt should come before diconnect interrupt, because the DP/DM pins are shorter than the VBUS/GND pins on the USB connectors. But we sometimes get a suspend interrupt after disconnect interrupt. In that case we have devctl set to 99 with VBUS still valid and musb_pm_runtime_check_session() wrongly thinks we have an active session. We have no other interrupts after disconnect coming in this case at least with the omap2430 glue. Let's fix the issue by checking the interrupt status again with delayed work for the devctl 99 case. In the suspend after disconnect case the devctl session bit has cleared by then and musb can idle. For a typical USB B-device connect case we just continue with normal interrupts. Fixes: 467d5c980709 ("usb: musb: Implement session bit based runtime PM for musb-core") Cc: Merlijn Wajer Cc: Pavel Machek Cc: Sebastian Reichel Cc: stable@vger.kernel.org Signed-off-by: Tony Lindgren Signed-off-by: Bin Liu Link: https://lore.kernel.org/r/20200107152625.857-2-b-liu@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index ff17e94ef465..cc8cdeb4b7fe 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1838,6 +1838,9 @@ static const struct attribute_group musb_attr_group = { #define MUSB_QUIRK_B_INVALID_VBUS_91 (MUSB_DEVCTL_BDEVICE | \ (2 << MUSB_DEVCTL_VBUS_SHIFT) | \ MUSB_DEVCTL_SESSION) +#define MUSB_QUIRK_B_DISCONNECT_99 (MUSB_DEVCTL_BDEVICE | \ + (3 << MUSB_DEVCTL_VBUS_SHIFT) | \ + MUSB_DEVCTL_SESSION) #define MUSB_QUIRK_A_DISCONNECT_19 ((3 << MUSB_DEVCTL_VBUS_SHIFT) | \ MUSB_DEVCTL_SESSION) @@ -1860,6 +1863,11 @@ static void musb_pm_runtime_check_session(struct musb *musb) s = MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV | MUSB_DEVCTL_HR; switch (devctl & ~s) { + case MUSB_QUIRK_B_DISCONNECT_99: + musb_dbg(musb, "Poll devctl in case of suspend after disconnect\n"); + schedule_delayed_work(&musb->irq_work, + msecs_to_jiffies(1000)); + break; case MUSB_QUIRK_B_INVALID_VBUS_91: if (musb->quirk_retries && !musb->flush_irq_work) { musb_dbg(musb, -- GitLab From b40e1f6761536f54e83e1ee99148ad354c43daa2 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Tue, 7 Jan 2020 09:26:25 -0600 Subject: [PATCH 0117/1055] usb: musb: Disable pullup at init commit 96a0c12843109e5c4d5eb1e09d915fdd0ce31d25 upstream. The pullup may be already enabled before the driver is initialized. This happens for instance on JZ4740. It has to be disabled at init time, as we cannot guarantee that a gadget driver will be bound to the UDC. Signed-off-by: Paul Cercueil Suggested-by: Bin Liu Cc: stable@vger.kernel.org Signed-off-by: Bin Liu Link: https://lore.kernel.org/r/20200107152625.857-3-b-liu@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index cc8cdeb4b7fe..dca39c9a13b0 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2328,6 +2328,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) musb_disable_interrupts(musb); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); + /* MUSB_POWER_SOFTCONN might be already set, JZ4740 does this. */ + musb_writeb(musb->mregs, MUSB_POWER, 0); + /* Init IRQ workqueue before request_irq */ INIT_DELAYED_WORK(&musb->irq_work, musb_irq_work); INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); -- GitLab From ba21819f1cdc3914bd76ff577d499424e9244c7f Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 16 Dec 2019 10:18:43 -0600 Subject: [PATCH 0118/1055] usb: musb: dma: Correct parameter passed to IRQ handler commit c80d0f4426c7fdc7efd6ae8d8b021dcfc89b4254 upstream. The IRQ handler was passed a pointer to a struct dma_controller, but the argument was then casted to a pointer to a struct musb_dma_controller. Fixes: 427c4f333474 ("usb: struct device - replace bus_id with dev_name(), dev_set_name()") Signed-off-by: Paul Cercueil Tested-by: Artur Rojek Cc: stable@vger.kernel.org Signed-off-by: Bin Liu Link: https://lore.kernel.org/r/20191216161844.772-2-b-liu@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musbhsdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 512108e22d2b..1dc35ab31275 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -399,7 +399,7 @@ struct dma_controller *musbhs_dma_controller_create(struct musb *musb, controller->controller.channel_abort = dma_channel_abort; if (request_irq(irq, dma_controller_irq, 0, - dev_name(musb->controller), &controller->controller)) { + dev_name(musb->controller), controller)) { dev_err(dev, "request_irq %d failed!\n", irq); musb_dma_controller_destroy(&controller->controller); -- GitLab From 912cb3eac58deadf051138c2021cbb3b0acb14b4 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 27 Dec 2019 17:00:54 +0000 Subject: [PATCH 0119/1055] staging: comedi: adv_pci1710: fix AI channels 16-31 for PCI-1713 commit a9d3a9cedc1330c720e0ddde1978a8e7771da5ab upstream. The Advantech PCI-1713 has 32 analog input channels, but an incorrect bit-mask in the definition of the `PCI171X_MUX_CHANH(x)` and PCI171X_MUX_CHANL(x)` macros is causing channels 16 to 31 to be aliases of channels 0 to 15. Change the bit-mask value from 0xf to 0xff to fix it. Note that the channel numbers will have been range checked already, so the bit-mask isn't really needed. Fixes: 92c65e5553ed ("staging: comedi: adv_pci1710: define the mux control register bits") Reported-by: Dmytro Fil Cc: # v4.5+ Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20191227170054.32051-1-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/adv_pci1710.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index 2c1b6de30da8..385e14269870 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -45,8 +45,8 @@ #define PCI171X_RANGE_UNI BIT(4) #define PCI171X_RANGE_GAIN(x) (((x) & 0x7) << 0) #define PCI171X_MUX_REG 0x04 /* W: A/D multiplexor control */ -#define PCI171X_MUX_CHANH(x) (((x) & 0xf) << 8) -#define PCI171X_MUX_CHANL(x) (((x) & 0xf) << 0) +#define PCI171X_MUX_CHANH(x) (((x) & 0xff) << 8) +#define PCI171X_MUX_CHANL(x) (((x) & 0xff) << 0) #define PCI171X_MUX_CHAN(x) (PCI171X_MUX_CHANH(x) | PCI171X_MUX_CHANL(x)) #define PCI171X_STATUS_REG 0x06 /* R: status register */ #define PCI171X_STATUS_IRQ BIT(11) /* 1=IRQ occurred */ -- GitLab From cb0a3edf8d00740303e5b42e9c0e72d924fc23d2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 7 Dec 2019 13:05:18 -0800 Subject: [PATCH 0120/1055] HID: hid-input: clear unmapped usages commit 4f3882177240a1f55e45a3d241d3121341bead78 upstream. We should not be leaving half-mapped usages with potentially invalid keycodes, as that may confuse hidinput_find_key() when the key is located by index, which may end up feeding way too large keycode into the VT keyboard handler and cause OOB write there: BUG: KASAN: global-out-of-bounds in clear_bit include/asm-generic/bitops-instrumented.h:56 [inline] BUG: KASAN: global-out-of-bounds in kbd_keycode drivers/tty/vt/keyboard.c:1411 [inline] BUG: KASAN: global-out-of-bounds in kbd_event+0xe6b/0x3790 drivers/tty/vt/keyboard.c:1495 Write of size 8 at addr ffffffff89a1b2d8 by task syz-executor108/1722 ... kbd_keycode drivers/tty/vt/keyboard.c:1411 [inline] kbd_event+0xe6b/0x3790 drivers/tty/vt/keyboard.c:1495 input_to_handler+0x3b6/0x4c0 drivers/input/input.c:118 input_pass_values.part.0+0x2e3/0x720 drivers/input/input.c:145 input_pass_values drivers/input/input.c:949 [inline] input_set_keycode+0x290/0x320 drivers/input/input.c:954 evdev_handle_set_keycode_v2+0xc4/0x120 drivers/input/evdev.c:882 evdev_do_ioctl drivers/input/evdev.c:1150 [inline] Cc: stable@vger.kernel.org Reported-by: syzbot+19340dff067c2d3835c0@syzkaller.appspotmail.com Signed-off-by: Dmitry Torokhov Tested-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-input.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 9d24fb0715ba..14e4003fde4d 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1116,9 +1116,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel } mapped: - if (device->driver->input_mapped && device->driver->input_mapped(device, - hidinput, field, usage, &bit, &max) < 0) - goto ignore; + if (device->driver->input_mapped && + device->driver->input_mapped(device, hidinput, field, usage, + &bit, &max) < 0) { + /* + * The driver indicated that no further generic handling + * of the usage is desired. + */ + return; + } set_bit(usage->type, input->evbit); @@ -1176,9 +1182,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel set_bit(MSC_SCAN, input->mscbit); } -ignore: return; +ignore: + usage->type = 0; + usage->code = 0; } void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) -- GitLab From af62c38b0f86539504dc5c0e5dcfc7613b1150a5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 13 Dec 2019 14:56:16 -0800 Subject: [PATCH 0121/1055] Input: add safety guards to input_set_keycode() commit cb222aed03d798fc074be55e59d9a112338ee784 upstream. If we happen to have a garbage in input device's keycode table with values too big we'll end up doing clear_bit() with offset way outside of our bitmaps, damaging other objects within an input device or even outside of it. Let's add sanity checks to the returned old keycodes. Reported-by: syzbot+c769968809f9359b07aa@syzkaller.appspotmail.com Reported-by: syzbot+76f3a30e88d256644c78@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/20191207212757.GA245964@dtor-ws Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/input.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/input/input.c b/drivers/input/input.c index 50d425fe6706..cadb368be8ef 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -858,16 +858,18 @@ static int input_default_setkeycode(struct input_dev *dev, } } - __clear_bit(*old_keycode, dev->keybit); - __set_bit(ke->keycode, dev->keybit); - - for (i = 0; i < dev->keycodemax; i++) { - if (input_fetch_keycode(dev, i) == *old_keycode) { - __set_bit(*old_keycode, dev->keybit); - break; /* Setting the bit twice is useless, so break */ + if (*old_keycode <= KEY_MAX) { + __clear_bit(*old_keycode, dev->keybit); + for (i = 0; i < dev->keycodemax; i++) { + if (input_fetch_keycode(dev, i) == *old_keycode) { + __set_bit(*old_keycode, dev->keybit); + /* Setting the bit twice is useless, so break */ + break; + } } } + __set_bit(ke->keycode, dev->keybit); return 0; } @@ -923,9 +925,13 @@ int input_set_keycode(struct input_dev *dev, * Simulate keyup event if keycode is not present * in the keymap anymore */ - if (test_bit(EV_KEY, dev->evbit) && - !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && - __test_and_clear_bit(old_keycode, dev->key)) { + if (old_keycode > KEY_MAX) { + dev_warn(dev->dev.parent ?: &dev->dev, + "%s: got too big old keycode %#x\n", + __func__, old_keycode); + } else if (test_bit(EV_KEY, dev->evbit) && + !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && + __test_and_clear_bit(old_keycode, dev->key)) { struct input_value vals[] = { { EV_KEY, old_keycode, 0 }, input_value_sync -- GitLab From 733463fdf7b0080e8092238a2c1f817f6aa81e4c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 30 Dec 2019 14:27:34 +0100 Subject: [PATCH 0122/1055] drm/fb-helper: Round up bits_per_pixel if possible commit f30e27779d3031a092c2a177b7fb76adccc45241 upstream. When userspace requests a video mode parameter value that is not supported, frame buffer device drivers should round it up to a supported value, if possible, instead of just rejecting it. This allows applications to quickly scan for supported video modes. Currently this rule is not followed for the number of bits per pixel, causing e.g. "fbset -depth N" to fail, if N is smaller than the current number of bits per pixel. Fix this by returning an error only if bits per pixel is too large, and setting it to the current value otherwise. See also Documentation/fb/framebuffer.rst, Section 2 (Programmer's View of /dev/fb*"). Fixes: 865afb11949e5bf4 ("drm/fb-helper: reject any changes to the fbdev") Cc: stable@vger.kernel.org Signed-off-by: Geert Uytterhoeven Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20191230132734.4538-1-geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_fb_helper.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index f1259a0c2883..eb6bf881c465 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1590,7 +1590,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, * Changes struct fb_var_screeninfo are currently not pushed back * to KMS, hence fail if different settings are requested. */ - if (var->bits_per_pixel != fb->format->cpp[0] * 8 || + if (var->bits_per_pixel > fb->format->cpp[0] * 8 || var->xres > fb->width || var->yres > fb->height || var->xres_virtual > fb->width || var->yres_virtual > fb->height) { DRM_DEBUG("fb requested width/height/bpp can't fit in current fb " @@ -1615,6 +1615,11 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, drm_fb_helper_fill_pixel_fmt(var, fb->format->depth); } + /* + * Likewise, bits_per_pixel should be rounded up to a supported value. + */ + var->bits_per_pixel = fb->format->cpp[0] * 8; + /* * drm fbdev emulation doesn't support changing the pixel format at all, * so reject all pixel format changing requests. -- GitLab From 0c703639c11a17db7e479e71fea8778d098c95c2 Mon Sep 17 00:00:00 2001 From: Wayne Lin Date: Fri, 3 Jan 2020 13:50:01 +0800 Subject: [PATCH 0123/1055] drm/dp_mst: correct the shifting in DP_REMOTE_I2C_READ commit c4e4fccc5d52d881afaac11d3353265ef4eccb8b upstream. [Why] According to DP spec, it should shift left 4 digits for NO_STOP_BIT in REMOTE_I2C_READ message. Not 5 digits. In current code, NO_STOP_BIT is always set to zero which means I2C master is always generating a I2C stop at the end of each I2C write transaction while handling REMOTE_I2C_READ sideband message. This issue might have the generated I2C signal not meeting the requirement. Take random read in I2C for instance, I2C master should generate a repeat start to start to read data after writing the read address. This issue will cause the I2C master to generate a stop-start rather than a re-start which is not expected in I2C random read. [How] Correct the shifting value of NO_STOP_BIT for DP_REMOTE_I2C_READ case in drm_dp_encode_sideband_req(). Changes since v1:(https://patchwork.kernel.org/patch/11312667/) * Add more descriptions in commit and cc to stable Fixes: ad7f8a1f9ced ("drm/helper: add Displayport multi-stream helper (v0.6)") Reviewed-by: Harry Wentland Signed-off-by: Wayne Lin Cc: stable@vger.kernel.org Signed-off-by: Lyude Paul Link: https://patchwork.freedesktop.org/patch/msgid/20200103055001.10287-1-Wayne.Lin@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_dp_mst_topology.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index ef86721c06f3..c8c83f84aced 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -274,7 +274,7 @@ static void drm_dp_encode_sideband_req(struct drm_dp_sideband_msg_req_body *req, memcpy(&buf[idx], req->u.i2c_read.transactions[i].bytes, req->u.i2c_read.transactions[i].num_bytes); idx += req->u.i2c_read.transactions[i].num_bytes; - buf[idx] = (req->u.i2c_read.transactions[i].no_stop_bit & 0x1) << 5; + buf[idx] = (req->u.i2c_read.transactions[i].no_stop_bit & 0x1) << 4; buf[idx] |= (req->u.i2c_read.transactions[i].i2c_transaction_delay & 0xf); idx++; } -- GitLab From a188bd5c9eb5294daff27cc2d8247074fee2eae2 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 28 Dec 2019 15:37:25 +0100 Subject: [PATCH 0124/1055] staging: rtl8188eu: Add device code for TP-Link TL-WN727N v5.21 commit 58dcc5bf4030cab548d5c98cd4cd3632a5444d5a upstream. This device was added to the stand-alone driver on github. Add it to the staging driver as well. Link: https://github.com/lwfinger/rtl8188eu/commit/b9b537aa25a8 Signed-off-by: Michael Straube Cc: stable Link: https://lore.kernel.org/r/20191228143725.24455-1-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 3733b73863b6..536453358568 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -45,6 +45,7 @@ static const struct usb_device_id rtw_usb_id_tbl[] = { {USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */ {USB_DEVICE(0x2001, 0x331B)}, /* D-Link DWA-121 rev B1 */ {USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */ + {USB_DEVICE(0x2357, 0x0111)}, /* TP-Link TL-WN727N v5.21 */ {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xffef)}, /* Rosewill RNX-N150NUB */ {} /* Terminating entry */ -- GitLab From 3d7cbd45ae237bcc958b79cf6bb70d0e1052ca41 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 12 Dec 2019 13:16:02 +0000 Subject: [PATCH 0125/1055] tty: link tty and port before configuring it as console commit fb2b90014d782d80d7ebf663e50f96d8c507a73c upstream. There seems to be a race condition in tty drivers and I could see on many boot cycles a NULL pointer dereference as tty_init_dev() tries to do 'tty->port->itty = tty' even though tty->port is NULL. 'tty->port' will be set by the driver and if the driver has not yet done it before we open the tty device we can get to this situation. By adding some extra debug prints, I noticed that: 6.650130: uart_add_one_port 6.663849: register_console 6.664846: tty_open 6.674391: tty_init_dev 6.675456: tty_port_link_device uart_add_one_port() registers the console, as soon as it registers, the userspace tries to use it and that leads to tty_open() but uart_add_one_port() has not yet done tty_port_link_device() and so tty->port is not yet configured when control reaches tty_init_dev(). Further look into the code and tty_port_link_device() is done by uart_add_one_port(). After registering the console uart_add_one_port() will call tty_port_register_device_attr_serdev() and tty_port_link_device() is called from this. Call add tty_port_link_device() before uart_configure_port() is done and add a check in tty_port_link_device() so that it only links the port if it has not been done yet. Suggested-by: Jiri Slaby Signed-off-by: Sudip Mukherjee Cc: stable Link: https://lore.kernel.org/r/20191212131602.29504-1-sudipm.mukherjee@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 1 + drivers/tty/tty_port.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 38bb8f85e88d..0ff8de7725cf 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2810,6 +2810,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) if (uport->cons && uport->dev) of_console_check(uport->dev->of_node, uport->cons->name, uport->line); + tty_port_link_device(port, drv->tty_driver, uport->line); uart_configure_port(drv, state, uport); port->console = uart_console(uport); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index c93a33701d32..d5b598137211 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -88,7 +88,8 @@ void tty_port_link_device(struct tty_port *port, { if (WARN_ON(index >= driver->num)) return; - driver->ports[index] = port; + if (!driver->ports[index]) + driver->ports[index] = port; } EXPORT_SYMBOL_GPL(tty_port_link_device); -- GitLab From 292c7f12b2b986f84a612d9f623334e48aacce8f Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 27 Dec 2019 17:44:34 +0000 Subject: [PATCH 0126/1055] tty: always relink the port commit 273f632912f1b24b642ba5b7eb5022e43a72f3b5 upstream. If the serial device is disconnected and reconnected, it re-enumerates properly but does not link it. fwiw, linking means just saving the port index, so allow it always as there is no harm in saving the same value again even if it tries to relink with the same port. Fixes: fb2b90014d78 ("tty: link tty and port before configuring it as console") Reported-by: Kenneth R. Crudup Signed-off-by: Sudip Mukherjee Cc: stable Link: https://lore.kernel.org/r/20191227174434.12057-1-sudipm.mukherjee@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_port.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index d5b598137211..c93a33701d32 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -88,8 +88,7 @@ void tty_port_link_device(struct tty_port *port, { if (WARN_ON(index >= driver->num)) return; - if (!driver->ports[index]) - driver->ports[index] = port; + driver->ports[index] = port; } EXPORT_SYMBOL_GPL(tty_port_link_device); -- GitLab From c2544fb30080aecc3fff99f2e97999ce8e625f45 Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Thu, 21 Nov 2019 21:34:38 +0530 Subject: [PATCH 0127/1055] mwifiex: fix possible heap overflow in mwifiex_process_country_ie() commit 3d94a4a8373bf5f45cf5f939e88b8354dbf2311b upstream. mwifiex_process_country_ie() function parse elements of bss descriptor in beacon packet. When processing WLAN_EID_COUNTRY element, there is no upper limit check for country_ie_len before calling memcpy. The destination buffer domain_info->triplet is an array of length MWIFIEX_MAX_TRIPLET_802_11D(83). The remote attacker can build a fake AP with the same ssid as real AP, and send malicous beacon packet with long WLAN_EID_COUNTRY elemen (country_ie_len > 83). Attacker can force STA connect to fake AP on a different channel. When the victim STA connects to fake AP, will trigger the heap buffer overflow. Fix this by checking for length and if found invalid, don not connect to the AP. This fix addresses CVE-2019-14895. Reported-by: huangwen Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/marvell/mwifiex/sta_ioctl.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index a8043d76152a..f88a953b3cd5 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -271,6 +271,14 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv, "11D: skip setting domain info in FW\n"); return 0; } + + if (country_ie_len > + (IEEE80211_COUNTRY_STRING_LEN + MWIFIEX_MAX_TRIPLET_802_11D)) { + mwifiex_dbg(priv->adapter, ERROR, + "11D: country_ie_len overflow!, deauth AP\n"); + return -EINVAL; + } + memcpy(priv->adapter->country_code, &country_ie[2], 2); domain_info->country_code[0] = country_ie[2]; @@ -314,8 +322,9 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, priv->scan_block = false; if (bss) { - if (adapter->region_code == 0x00) - mwifiex_process_country_ie(priv, bss); + if (adapter->region_code == 0x00 && + mwifiex_process_country_ie(priv, bss)) + return -EINVAL; /* Allocate and fill new bss descriptor */ bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), -- GitLab From 6ddbe82681d911534f460e6afd297fcf7f388049 Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Fri, 4 Oct 2019 15:08:52 -0500 Subject: [PATCH 0128/1055] mwifiex: pcie: Fix memory leak in mwifiex_pcie_alloc_cmdrsp_buf commit db8fd2cde93227e566a412cf53173ffa227998bc upstream. In mwifiex_pcie_alloc_cmdrsp_buf, a new skb is allocated which should be released if mwifiex_map_pci_memory() fails. The release is added. Fixes: fc3314609047 ("mwifiex: use pci_alloc/free_consistent APIs for PCIe") Signed-off-by: Navid Emamdoost Acked-by: Ganapathi Bhat Signed-off-by: Kalle Valo Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/marvell/mwifiex/pcie.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 9d0d790a1319..8ee9609ef974 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1022,8 +1022,10 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter) } skb_put(skb, MWIFIEX_UPLD_SIZE); if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, - PCI_DMA_FROMDEVICE)) + PCI_DMA_FROMDEVICE)) { + kfree_skb(skb); return -1; + } card->cmdrsp_buf = skb; -- GitLab From f4e8c78fad1294c785de5e92562862dbef1e9c1e Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Tue, 10 Sep 2019 18:44:15 -0500 Subject: [PATCH 0129/1055] scsi: bfa: release allocated memory in case of error commit 0e62395da2bd5166d7c9e14cbc7503b256a34cb0 upstream. In bfad_im_get_stats if bfa_port_get_stats fails, allocated memory needs to be released. Link: https://lore.kernel.org/r/20190910234417.22151-1-navid.emamdoost@gmail.com Signed-off-by: Navid Emamdoost Signed-off-by: Martin K. Petersen Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/bfa/bfad_attr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c index d0a504af5b4f..0a70d54a4df6 100644 --- a/drivers/scsi/bfa/bfad_attr.c +++ b/drivers/scsi/bfa/bfad_attr.c @@ -283,8 +283,10 @@ bfad_im_get_stats(struct Scsi_Host *shost) rc = bfa_port_get_stats(BFA_FCPORT(&bfad->bfa), fcstats, bfad_hcb_comp, &fcomp); spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (rc != BFA_STATUS_OK) + if (rc != BFA_STATUS_OK) { + kfree(fcstats); return NULL; + } wait_for_completion(&fcomp.comp); -- GitLab From 32079b0c59f4620fdf7a5576af7502b0d05fcb01 Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Thu, 19 Sep 2019 22:00:41 -0500 Subject: [PATCH 0130/1055] rtl8xxxu: prevent leaking urb commit a2cdd07488e666aa93a49a3fc9c9b1299e27ef3c upstream. In rtl8xxxu_submit_int_urb if usb_submit_urb fails the allocated urb should be released. Signed-off-by: Navid Emamdoost Reviewed-by: Chris Chiu Signed-off-by: Kalle Valo Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index b58bf8e2cad2..73fc5952fd37 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5453,6 +5453,7 @@ static int rtl8xxxu_submit_int_urb(struct ieee80211_hw *hw) ret = usb_submit_urb(urb, GFP_KERNEL); if (ret) { usb_unanchor_urb(urb); + usb_free_urb(urb); goto error; } -- GitLab From 4af2276845448609264360e95973246f222a7d86 Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Thu, 19 Sep 2019 20:36:26 -0500 Subject: [PATCH 0131/1055] ath10k: fix memory leak commit b8d17e7d93d2beb89e4f34c59996376b8b544792 upstream. In ath10k_usb_hif_tx_sg the allocated urb should be released if usb_submit_urb fails. Signed-off-by: Navid Emamdoost Signed-off-by: Kalle Valo Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath10k/usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c index f9c79e21ab22..c64a03f164c0 100644 --- a/drivers/net/wireless/ath/ath10k/usb.c +++ b/drivers/net/wireless/ath/ath10k/usb.c @@ -454,6 +454,7 @@ static int ath10k_usb_hif_tx_sg(struct ath10k *ar, u8 pipe_id, ath10k_dbg(ar, ATH10K_DBG_USB_BULK, "usb bulk transmit failed: %d\n", ret); usb_unanchor_urb(urb); + usb_free_urb(urb); ret = -EINVAL; goto err_free_urb_to_pipe; } -- GitLab From 66552949c83a903779830561cb9c23eabd9866ae Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 27 Mar 2018 11:51:12 +0100 Subject: [PATCH 0132/1055] arm64: cpufeature: Avoid warnings due to unused symbols commit 12eb369125abe92bfc55e9ce198200f5807b63ff upstream. An allnoconfig build complains about unused symbols due to functions that are called via conditional cpufeature and cpu_errata table entries. Annotate these as __maybe_unused if they are likely to be generic, or predicate their compilation on the same option as the table entry if they are specific to a given alternative. Signed-off-by: Will Deacon [Just a portion of the original patch] Signed-off-by: Jisheng Zhang Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpufeature.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 15ce2c8b9ee2..60066315d669 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -799,11 +799,6 @@ static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry, int _ MIDR_CPU_VAR_REV(1, MIDR_REVISION_MASK)); } -static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused) -{ - return is_kernel_in_hyp_mode(); -} - static bool hyp_offset_low(const struct arm64_cpu_capabilities *entry, int __unused) { @@ -937,6 +932,12 @@ static int __init parse_kpti(char *str) } early_param("kpti", parse_kpti); +#ifdef CONFIG_ARM64_VHE +static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused) +{ + return is_kernel_in_hyp_mode(); +} + static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused) { /* @@ -950,6 +951,7 @@ static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused) if (!alternatives_applied) write_sysreg(read_sysreg(tpidr_el1), tpidr_el2); } +#endif #ifdef CONFIG_ARM64_SSBD static int ssbs_emulation_handler(struct pt_regs *regs, u32 instr) -- GitLab From ac3a29ac803b5ce052f201ec7ce497bc3f30bd37 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 17 Dec 2019 14:50:21 -0800 Subject: [PATCH 0133/1055] HID: hiddev: fix mess in hiddev_open() commit 18a1b06e5b91d47dc86c0a66a762646ea7c5d141 upstream. The open method of hiddev handler fails to bring the device out of autosuspend state as was promised in 0361a28d3f9a, as it actually has 2 blocks that try to start the transport (call hid_hw_open()) with both being guarded by the "open" counter, so the 2nd block is never executed as the first block increments the counter so it is never at 0 when we check it for the second block. Additionally hiddev_open() was leaving counter incremented on errors, causing the device to never be reopened properly if there was ever an error. Let's fix all of this by factoring out code that creates client structure and powers up the device into a separate function that is being called from usbhid_open() with the "existancelock" being held. Fixes: 0361a28d3f9a ("HID: autosuspend support for USB HID") Signed-off-by: Dmitry Torokhov Signed-off-by: Benjamin Tissoires Signed-off-by: Greg Kroah-Hartman --- drivers/hid/usbhid/hiddev.c | 97 ++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 55 deletions(-) diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index ce342fd0457e..bccd97cdc53f 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -254,12 +254,51 @@ static int hiddev_release(struct inode * inode, struct file * file) return 0; } +static int __hiddev_open(struct hiddev *hiddev, struct file *file) +{ + struct hiddev_list *list; + int error; + + lockdep_assert_held(&hiddev->existancelock); + + list = vzalloc(sizeof(*list)); + if (!list) + return -ENOMEM; + + mutex_init(&list->thread_lock); + list->hiddev = hiddev; + + if (!hiddev->open++) { + error = hid_hw_power(hiddev->hid, PM_HINT_FULLON); + if (error < 0) + goto err_drop_count; + + error = hid_hw_open(hiddev->hid); + if (error < 0) + goto err_normal_power; + } + + spin_lock_irq(&hiddev->list_lock); + list_add_tail(&list->node, &hiddev->list); + spin_unlock_irq(&hiddev->list_lock); + + file->private_data = list; + + return 0; + +err_normal_power: + hid_hw_power(hiddev->hid, PM_HINT_NORMAL); +err_drop_count: + hiddev->open--; + vfree(list); + return error; +} + /* * open file op */ static int hiddev_open(struct inode *inode, struct file *file) { - struct hiddev_list *list; struct usb_interface *intf; struct hid_device *hid; struct hiddev *hiddev; @@ -268,66 +307,14 @@ static int hiddev_open(struct inode *inode, struct file *file) intf = usbhid_find_interface(iminor(inode)); if (!intf) return -ENODEV; + hid = usb_get_intfdata(intf); hiddev = hid->hiddev; - if (!(list = vzalloc(sizeof(struct hiddev_list)))) - return -ENOMEM; - mutex_init(&list->thread_lock); - list->hiddev = hiddev; - file->private_data = list; - - /* - * no need for locking because the USB major number - * is shared which usbcore guards against disconnect - */ - if (list->hiddev->exist) { - if (!list->hiddev->open++) { - res = hid_hw_open(hiddev->hid); - if (res < 0) - goto bail; - } - } else { - res = -ENODEV; - goto bail; - } - - spin_lock_irq(&list->hiddev->list_lock); - list_add_tail(&list->node, &hiddev->list); - spin_unlock_irq(&list->hiddev->list_lock); - mutex_lock(&hiddev->existancelock); - /* - * recheck exist with existance lock held to - * avoid opening a disconnected device - */ - if (!list->hiddev->exist) { - res = -ENODEV; - goto bail_unlock; - } - if (!list->hiddev->open++) - if (list->hiddev->exist) { - struct hid_device *hid = hiddev->hid; - res = hid_hw_power(hid, PM_HINT_FULLON); - if (res < 0) - goto bail_unlock; - res = hid_hw_open(hid); - if (res < 0) - goto bail_normal_power; - } - mutex_unlock(&hiddev->existancelock); - return 0; -bail_normal_power: - hid_hw_power(hid, PM_HINT_NORMAL); -bail_unlock: + res = hiddev->exist ? __hiddev_open(hiddev, file) : -ENODEV; mutex_unlock(&hiddev->existancelock); - spin_lock_irq(&list->hiddev->list_lock); - list_del(&list->node); - spin_unlock_irq(&list->hiddev->list_lock); -bail: - file->private_data = NULL; - vfree(list); return res; } -- GitLab From c51a3c85eb8c9a499e7efe51157ad21e1d83034d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 6 Jan 2020 10:43:42 -0500 Subject: [PATCH 0134/1055] USB: Fix: Don't skip endpoint descriptors with maxpacket=0 commit 2548288b4fb059b2da9ceada172ef763077e8a59 upstream. It turns out that even though endpoints with a maxpacket length of 0 aren't useful for data transfer, the descriptors do serve other purposes. In particular, skipping them will also skip over other class-specific descriptors for classes such as UVC. This unexpected side effect has caused some UVC cameras to stop working. In addition, the USB spec requires that when isochronous endpoint descriptors are present in an interface's altsetting 0 (which is true on some devices), the maxpacket size _must_ be set to 0. Warning about such things seems like a bad idea. This patch updates an earlier commit which would log a warning and skip these endpoint descriptors. Now we only log a warning, and we don't even do that for isochronous endpoints in altsetting 0. We don't need to worry about preventing endpoints with maxpacket = 0 from ever being used for data transfers; usb_submit_urb() already checks for this. Reported-and-tested-by: Roger Whittaker Fixes: d482c7bb0541 ("USB: Skip endpoints with 0 maxpacket length") Signed-off-by: Alan Stern CC: Laurent Pinchart Link: https://marc.info/?l=linux-usb&m=157790377329882&w=2 Link: https://lore.kernel.org/r/Pine.LNX.4.44L0.2001061040270.1514-100000@iolanthe.rowland.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/config.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 1f525d5f6d2d..7df7faa3eed5 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -392,12 +392,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, endpoint->desc.wMaxPacketSize = cpu_to_le16(8); } - /* Validate the wMaxPacketSize field */ + /* + * Validate the wMaxPacketSize field. + * Some devices have isochronous endpoints in altsetting 0; + * the USB-2 spec requires such endpoints to have wMaxPacketSize = 0 + * (see the end of section 5.6.3), so don't warn about them. + */ maxp = usb_endpoint_maxp(&endpoint->desc); - if (maxp == 0) { - dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has wMaxPacketSize 0, skipping\n", + if (maxp == 0 && !(usb_endpoint_xfer_isoc(d) && asnum == 0)) { + dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n", cfgno, inum, asnum, d->bEndpointAddress); - goto skip_to_next_endpoint_or_interface_descriptor; } /* Find the highest legal maxpacket size for this endpoint */ -- GitLab From 1adecb749b826d4956a2691b470d806715619f90 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 20 Dec 2019 16:21:40 +0530 Subject: [PATCH 0135/1055] phy: cpcap-usb: Fix error path when no host driver is loaded commit 4acb0200ab2b07843e3ef5599add3454c7440f03 upstream. If musb_mailbox() returns an error, we must still continue to finish configuring the phy. Otherwise the phy state may end up only half initialized, and this can cause the debug serial console to stop working. And this will happen if the usb driver musb controller is not loaded. Let's fix the issue by adding helper for cpcap_usb_try_musb_mailbox(). Fixes: 6d6ce40f63af ("phy: cpcap-usb: Add CPCAP PMIC USB support") Cc: Merlijn Wajer Cc: Pavel Machek Cc: Sebastian Reichel Signed-off-by: Tony Lindgren Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Greg Kroah-Hartman --- drivers/phy/motorola/phy-cpcap-usb.c | 33 +++++++++++++++------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c index 6601ad0dfb3a..6beaf8e0449c 100644 --- a/drivers/phy/motorola/phy-cpcap-usb.c +++ b/drivers/phy/motorola/phy-cpcap-usb.c @@ -207,6 +207,19 @@ static int cpcap_phy_get_ints_state(struct cpcap_phy_ddata *ddata, static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata); static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata); +static void cpcap_usb_try_musb_mailbox(struct cpcap_phy_ddata *ddata, + enum musb_vbus_id_status status) +{ + int error; + + error = musb_mailbox(status); + if (!error) + return; + + dev_dbg(ddata->dev, "%s: musb_mailbox failed: %i\n", + __func__, error); +} + static void cpcap_usb_detect(struct work_struct *work) { struct cpcap_phy_ddata *ddata; @@ -226,9 +239,7 @@ static void cpcap_usb_detect(struct work_struct *work) if (error) goto out_err; - error = musb_mailbox(MUSB_ID_GROUND); - if (error) - goto out_err; + cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND); error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, CPCAP_BIT_VBUSSTBY_EN, @@ -255,9 +266,7 @@ static void cpcap_usb_detect(struct work_struct *work) error = cpcap_usb_set_usb_mode(ddata); if (error) goto out_err; - error = musb_mailbox(MUSB_ID_GROUND); - if (error) - goto out_err; + cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND); return; } @@ -267,9 +276,7 @@ static void cpcap_usb_detect(struct work_struct *work) error = cpcap_usb_set_usb_mode(ddata); if (error) goto out_err; - error = musb_mailbox(MUSB_VBUS_VALID); - if (error) - goto out_err; + cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_VALID); return; } @@ -279,9 +286,7 @@ static void cpcap_usb_detect(struct work_struct *work) if (error) goto out_err; - error = musb_mailbox(MUSB_VBUS_OFF); - if (error) - goto out_err; + cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF); dev_dbg(ddata->dev, "set UART mode\n"); @@ -647,9 +652,7 @@ static int cpcap_usb_phy_remove(struct platform_device *pdev) if (error) dev_err(ddata->dev, "could not set UART mode\n"); - error = musb_mailbox(MUSB_VBUS_OFF); - if (error) - dev_err(ddata->dev, "could not set mailbox\n"); + cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF); usb_remove_phy(&ddata->phy); cancel_delayed_work_sync(&ddata->detect_work); -- GitLab From f71f56ad53546fed4b22b783d7aecdf7dee4c71d Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sun, 22 Dec 2019 10:00:19 -0800 Subject: [PATCH 0136/1055] phy: cpcap-usb: Fix flakey host idling and enumerating of devices commit 049226b9fd7442149dcbcf55f15408f5973cceda upstream. We must let the USB host idle things properly before we switch to debug UART mode. Otherwise the USB host may never idle after disconnecting devices, and that causes the next enumeration to be flakey. Cc: Jacopo Mondi Cc: Marcel Partap Cc: Merlijn Wajer Cc: Michael Scott Cc: NeKit Cc: Pavel Machek Cc: Sebastian Reichel Acked-by: Pavel Machek Fixes: 6d6ce40f63af ("phy: cpcap-usb: Add CPCAP PMIC USB support") Signed-off-by: Tony Lindgren Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Greg Kroah-Hartman --- drivers/phy/motorola/phy-cpcap-usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c index 6beaf8e0449c..4ba3634009af 100644 --- a/drivers/phy/motorola/phy-cpcap-usb.c +++ b/drivers/phy/motorola/phy-cpcap-usb.c @@ -281,13 +281,13 @@ static void cpcap_usb_detect(struct work_struct *work) return; } + cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF); + /* Default to debug UART mode */ error = cpcap_usb_set_uart_mode(ddata); if (error) goto out_err; - cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF); - dev_dbg(ddata->dev, "set UART mode\n"); return; -- GitLab From c28aabbd643e2201a09d39e45240b661bfb61b50 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 27 Dec 2019 01:33:10 +0100 Subject: [PATCH 0137/1055] netfilter: arp_tables: init netns pointer in xt_tgchk_param struct commit 1b789577f655060d98d20ed0c6f9fbd469d6ba63 upstream. We get crash when the targets checkentry function tries to make use of the network namespace pointer for arptables. When the net pointer got added back in 2010, only ip/ip6/ebtables were changed to initialize it, so arptables has this set to NULL. This isn't a problem for normal arptables because no existing arptables target has a checkentry function that makes use of par->net. However, direct users of the setsockopt interface can provide any target they want as long as its registered for ARP or UNPSEC protocols. syzkaller managed to send a semi-valid arptables rule for RATEEST target which is enough to trigger NULL deref: kasan: GPF could be caused by NULL-ptr deref or user memory access general protection fault: 0000 [#1] PREEMPT SMP KASAN RIP: xt_rateest_tg_checkentry+0x11d/0xb40 net/netfilter/xt_RATEEST.c:109 [..] xt_check_target+0x283/0x690 net/netfilter/x_tables.c:1019 check_target net/ipv4/netfilter/arp_tables.c:399 [inline] find_check_entry net/ipv4/netfilter/arp_tables.c:422 [inline] translate_table+0x1005/0x1d70 net/ipv4/netfilter/arp_tables.c:572 do_replace net/ipv4/netfilter/arp_tables.c:977 [inline] do_arpt_set_ctl+0x310/0x640 net/ipv4/netfilter/arp_tables.c:1456 Fixes: add67461240c1d ("netfilter: add struct net * to target parameters") Reported-by: syzbot+d7358a458d8a81aee898@syzkaller.appspotmail.com Signed-off-by: Florian Westphal Acked-by: Cong Wang Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/ipv4/netfilter/arp_tables.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 356ae7da4f16..e288489ae3d5 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -394,10 +394,11 @@ next: ; return 1; } -static inline int check_target(struct arpt_entry *e, const char *name) +static int check_target(struct arpt_entry *e, struct net *net, const char *name) { struct xt_entry_target *t = arpt_get_target(e); struct xt_tgchk_param par = { + .net = net, .table = name, .entryinfo = e, .target = t->u.kernel.target, @@ -409,8 +410,9 @@ static inline int check_target(struct arpt_entry *e, const char *name) return xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false); } -static inline int -find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, +static int +find_check_entry(struct arpt_entry *e, struct net *net, const char *name, + unsigned int size, struct xt_percpu_counter_alloc_state *alloc_state) { struct xt_entry_target *t; @@ -429,7 +431,7 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, } t->u.kernel.target = target; - ret = check_target(e, name); + ret = check_target(e, net, name); if (ret) goto err; return 0; @@ -522,7 +524,9 @@ static inline void cleanup_entry(struct arpt_entry *e) /* Checks and translates the user-supplied table segment (held in * newinfo). */ -static int translate_table(struct xt_table_info *newinfo, void *entry0, +static int translate_table(struct net *net, + struct xt_table_info *newinfo, + void *entry0, const struct arpt_replace *repl) { struct xt_percpu_counter_alloc_state alloc_state = { 0 }; @@ -586,7 +590,7 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, /* Finally, each sanity check must pass */ i = 0; xt_entry_foreach(iter, entry0, newinfo->size) { - ret = find_check_entry(iter, repl->name, repl->size, + ret = find_check_entry(iter, net, repl->name, repl->size, &alloc_state); if (ret != 0) break; @@ -974,7 +978,7 @@ static int do_replace(struct net *net, const void __user *user, goto free_newinfo; } - ret = translate_table(newinfo, loc_cpu_entry, &tmp); + ret = translate_table(net, newinfo, loc_cpu_entry, &tmp); if (ret != 0) goto free_newinfo; @@ -1149,7 +1153,8 @@ compat_copy_entry_from_user(struct compat_arpt_entry *e, void **dstptr, } } -static int translate_compat_table(struct xt_table_info **pinfo, +static int translate_compat_table(struct net *net, + struct xt_table_info **pinfo, void **pentry0, const struct compat_arpt_replace *compatr) { @@ -1217,7 +1222,7 @@ static int translate_compat_table(struct xt_table_info **pinfo, repl.num_counters = 0; repl.counters = NULL; repl.size = newinfo->size; - ret = translate_table(newinfo, entry1, &repl); + ret = translate_table(net, newinfo, entry1, &repl); if (ret) goto free_newinfo; @@ -1270,7 +1275,7 @@ static int compat_do_replace(struct net *net, void __user *user, goto free_newinfo; } - ret = translate_compat_table(&newinfo, &loc_cpu_entry, &tmp); + ret = translate_compat_table(net, &newinfo, &loc_cpu_entry, &tmp); if (ret != 0) goto free_newinfo; @@ -1546,7 +1551,7 @@ int arpt_register_table(struct net *net, loc_cpu_entry = newinfo->entries; memcpy(loc_cpu_entry, repl->entries, repl->size); - ret = translate_table(newinfo, loc_cpu_entry, repl); + ret = translate_table(net, newinfo, loc_cpu_entry, repl); if (ret != 0) goto out_free; -- GitLab From bd6d13a15aaab4967bedd46f216dd63c428252aa Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 8 Jan 2020 10:59:38 +0100 Subject: [PATCH 0138/1055] netfilter: ipset: avoid null deref when IPSET_ATTR_LINENO is present commit 22dad713b8a5ff488e07b821195270672f486eb2 upstream. The set uadt functions assume lineno is never NULL, but it is in case of ip_set_utest(). syzkaller managed to generate a netlink message that calls this with LINENO attr present: general protection fault: 0000 [#1] PREEMPT SMP KASAN RIP: 0010:hash_mac4_uadt+0x1bc/0x470 net/netfilter/ipset/ip_set_hash_mac.c:104 Call Trace: ip_set_utest+0x55b/0x890 net/netfilter/ipset/ip_set_core.c:1867 nfnetlink_rcv_msg+0xcf2/0xfb0 net/netfilter/nfnetlink.c:229 netlink_rcv_skb+0x177/0x450 net/netlink/af_netlink.c:2477 nfnetlink_rcv+0x1ba/0x460 net/netfilter/nfnetlink.c:563 pass a dummy lineno storage, its easier than patching all set implementations. This seems to be a day-0 bug. Cc: Jozsef Kadlecsik Reported-by: syzbot+34bd2369d38707f3f4a7@syzkaller.appspotmail.com Fixes: a7b4f989a6294 ("netfilter: ipset: IP set core support") Signed-off-by: Florian Westphal Acked-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/ipset/ip_set_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 94d74ec61f42..c2b21c9c1229 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -1639,6 +1639,7 @@ static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb, struct ip_set *set; struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {}; int ret = 0; + u32 lineno; if (unlikely(protocol_failed(attr) || !attr[IPSET_ATTR_SETNAME] || @@ -1655,7 +1656,7 @@ static int ip_set_utest(struct net *net, struct sock *ctnl, struct sk_buff *skb, return -IPSET_ERR_PROTOCOL; rcu_read_lock_bh(); - ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0, 0); + ret = set->variant->uadt(set, tb, IPSET_TEST, &lineno, 0, 0); rcu_read_unlock_bh(); /* Userspace can't trigger element to be re-added */ if (ret == -EAGAIN) -- GitLab From 39465647eda707db7c7561006da3a8450ca634b9 Mon Sep 17 00:00:00 2001 From: Akeem G Abodunrin Date: Wed, 8 Jan 2020 12:37:25 -0800 Subject: [PATCH 0139/1055] drm/i915/gen9: Clear residual context state on context switch commit bc8a76a152c5f9ef3b48104154a65a68a8b76946 upstream. Intel ID: PSIRT-TA-201910-001 CVEID: CVE-2019-14615 Intel GPU Hardware prior to Gen11 does not clear EU state during a context switch. This can result in information leakage between contexts. For Gen8 and Gen9, hardware provides a mechanism for fast cleardown of the EU state, by issuing a PIPE_CONTROL with bit 27 set. We can use this in a context batch buffer to explicitly cleardown the state on every context switch. As this workaround is already in place for gen8, we can borrow the code verbatim for Gen9. Signed-off-by: Mika Kuoppala Signed-off-by: Akeem G Abodunrin Cc: Kumar Valsan Prathap Cc: Chris Wilson Cc: Balestrieri Francesco Cc: Bloomfield Jon Cc: Dutt Sudeep Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_lrc.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index e0483c068d23..baff1f01bfc7 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1101,17 +1101,14 @@ static u32 *gen9_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch) *batch++ = MI_NOOP; - /* WaClearSlmSpaceAtContextSwitch:kbl */ - /* Actual scratch location is at 128 bytes offset */ - if (IS_KBL_REVID(engine->i915, 0, KBL_REVID_A0)) { - batch = gen8_emit_pipe_control(batch, - PIPE_CONTROL_FLUSH_L3 | - PIPE_CONTROL_GLOBAL_GTT_IVB | - PIPE_CONTROL_CS_STALL | - PIPE_CONTROL_QW_WRITE, - i915_ggtt_offset(engine->scratch) - + 2 * CACHELINE_BYTES); - } + /* WaClearSlmSpaceAtContextSwitch:skl,bxt,kbl,glk,cfl */ + batch = gen8_emit_pipe_control(batch, + PIPE_CONTROL_FLUSH_L3 | + PIPE_CONTROL_GLOBAL_GTT_IVB | + PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_QW_WRITE, + i915_ggtt_offset(engine->scratch) + + 2 * CACHELINE_BYTES); /* WaMediaPoolStateCmdInWABB:bxt,glk */ if (HAS_POOLED_EU(engine->i915)) { -- GitLab From c04fc6fa5c96ec57316527b2228fa31f26494abe Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 14 Jan 2020 20:05:49 +0100 Subject: [PATCH 0140/1055] Linux 4.14.165 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f2aa55cea457..166e18aa9ca9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 164 +SUBLEVEL = 165 EXTRAVERSION = NAME = Petit Gorille -- GitLab From 642db7c730a4f8468d5148f500735a0912f6edd6 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 8 Jan 2020 18:19:25 -0800 Subject: [PATCH 0141/1055] ANDROID: Enable HID_STEAM as y These configs will now be required in aosp/1204022. Change-Id: Ib2961a9abf545f483cd5691f04b93cffd011ec82 Signed-off-by: Siarhei Vishniakou Bug: 136263708 Test: none --- 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 71fc12c51973..e718b8a1860b 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -368,6 +368,7 @@ CONFIG_HID_SAITEK=y CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SPEEDLINK=y +CONFIG_HID_STEAM=y CONFIG_HID_SUNPLUS=y CONFIG_HID_GREENASIA=y CONFIG_GREENASIA_FF=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 11e1f466ddd8..5314fe11470e 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -389,6 +389,7 @@ CONFIG_HID_SAITEK=y CONFIG_HID_SAMSUNG=y CONFIG_HID_SONY=y CONFIG_HID_SPEEDLINK=y +CONFIG_HID_STEAM=y CONFIG_HID_SUNPLUS=y CONFIG_HID_GREENASIA=y CONFIG_GREENASIA_FF=y -- GitLab From d3b701efacbc0d39d1da593ab3e0ec336e6d3d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 13 Jan 2020 23:52:14 -0800 Subject: [PATCH 0142/1055] cuttlefish - enable CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quota logging is needed to enable data metering. Bug: 147203196 Signed-off-by: Maciej Żenczykowski Change-Id: I7219a3abd922b31249a3bccb94bc0dcff197788e --- 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 e718b8a1860b..d22e5b86216c 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -150,6 +150,7 @@ CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 5314fe11470e..9e92a37c20b1 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -159,6 +159,7 @@ CONFIG_NETFILTER_XT_MATCH_POLICY=y CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y -- GitLab From 37d5c0dbbb882c9913fe9ed2ab1a4088e6cff27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 16 Jan 2020 01:52:49 -0800 Subject: [PATCH 0143/1055] cuttlefish: enable CONFIG_DUMMY=y MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dummy network interface required for upcoming self-tests. Bug: 147203196 Signed-off-by: Maciej Żenczykowski Change-Id: I1989ece6cb95a8fa0c8b03ed756f9962476e0577 --- 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 d22e5b86216c..c2700608d034 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -230,6 +230,7 @@ CONFIG_DM_VERITY_FEC=y CONFIG_DM_VERITY_AVB=y CONFIG_DM_BOW=y CONFIG_NETDEVICES=y +CONFIG_DUMMY=y CONFIG_NETCONSOLE=y CONFIG_NETCONSOLE_DYNAMIC=y CONFIG_TUN=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 9e92a37c20b1..0cee03ee5f2c 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -246,6 +246,7 @@ CONFIG_DM_VERITY_FEC=y CONFIG_DM_ANDROID_VERITY=y CONFIG_DM_BOW=y CONFIG_NETDEVICES=y +CONFIG_DUMMY=y CONFIG_NETCONSOLE=y CONFIG_NETCONSOLE_DYNAMIC=y CONFIG_TUN=y -- GitLab From 4f9ec9a986ca8f359d9128caa9d1085bac9d84da Mon Sep 17 00:00:00 2001 From: Fabian Henneke Date: Tue, 9 Jul 2019 13:03:37 +0200 Subject: [PATCH 0144/1055] hidraw: Return EPOLLOUT from hidraw_poll [ Upstream commit 378b80370aa1fe50f9c48a3ac8af3e416e73b89f ] Always return EPOLLOUT from hidraw_poll when a device is connected. This is safe since writes are always possible (but will always block). hidraw does not support non-blocking writes and instead always calls blocking backend functions on write requests. Hence, so far, a call to poll never returned EPOLLOUT, which confuses tools like socat. Signed-off-by: Fabian Henneke In-reply-to: Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin --- 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 5652bd0ffb4d..1ac82e194818 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -260,7 +260,7 @@ static unsigned int hidraw_poll(struct file *file, poll_table *wait) poll_wait(file, &list->hidraw->wait, wait); if (list->head != list->tail) - return POLLIN | POLLRDNORM; + return POLLIN | POLLRDNORM | POLLOUT; if (!list->hidraw->exist) return POLLERR | POLLHUP; return 0; -- GitLab From fa8b1126ca127c50f47553971af7b4febe220ecc Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 4 Dec 2019 03:37:13 +0100 Subject: [PATCH 0145/1055] HID: hidraw: Fix returning EPOLLOUT from hidraw_poll [ Upstream commit 9f3b61dc1dd7b81e99e7ed23776bb64a35f39e1a ] When polling a connected /dev/hidrawX device, it is useful to get the EPOLLOUT when writing is possible. Since writing is possible as soon as the device is connected, always return it. Right now EPOLLOUT is only returned when there are also input reports are available. This works if devices start sending reports when connected, but some HID devices might need an output report first before sending any input reports. This change will allow using EPOLLOUT here as well. Fixes: 378b80370aa1 ("hidraw: Return EPOLLOUT from hidraw_poll") Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin --- drivers/hid/hidraw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 1ac82e194818..1abf5008def0 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -260,10 +260,10 @@ static unsigned int hidraw_poll(struct file *file, poll_table *wait) poll_wait(file, &list->hidraw->wait, wait); if (list->head != list->tail) - return POLLIN | POLLRDNORM | POLLOUT; + return POLLIN | POLLRDNORM; if (!list->hidraw->exist) return POLLERR | POLLHUP; - return 0; + return POLLOUT | POLLWRNORM; } static int hidraw_open(struct inode *inode, struct file *file) -- GitLab From 2aaed8c188341c22e0b6f39f238d800936c77c01 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 10 Jan 2020 15:32:51 +0100 Subject: [PATCH 0146/1055] HID: hidraw, uhid: Always report EPOLLOUT [ Upstream commit 9e635c2851df6caee651e589fbf937b637973c91 ] hidraw and uhid device nodes are always available for writing so we should always report EPOLLOUT and EPOLLWRNORM bits, not only in the cases when there is nothing to read. Reported-by: Linus Torvalds Fixes: be54e7461ffdc ("HID: uhid: Fix returning EPOLLOUT from uhid_char_poll") Fixes: 9f3b61dc1dd7b ("HID: hidraw: Fix returning EPOLLOUT from hidraw_poll") Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin --- drivers/hid/hidraw.c | 7 ++++--- drivers/hid/uhid.c | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 1abf5008def0..5243c4120819 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -257,13 +257,14 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t static unsigned int hidraw_poll(struct file *file, poll_table *wait) { struct hidraw_list *list = file->private_data; + unsigned int mask = POLLOUT | POLLWRNORM; /* hidraw is always writable */ poll_wait(file, &list->hidraw->wait, wait); if (list->head != list->tail) - return POLLIN | POLLRDNORM; + mask |= POLLIN | POLLRDNORM; if (!list->hidraw->exist) - return POLLERR | POLLHUP; - return POLLOUT | POLLWRNORM; + mask |= POLLERR | POLLHUP; + return mask; } static int hidraw_open(struct inode *inode, struct file *file) diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index e63b761f600a..c749f449c7cb 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -769,13 +769,14 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer, static unsigned int uhid_char_poll(struct file *file, poll_table *wait) { struct uhid_device *uhid = file->private_data; + unsigned int mask = POLLOUT | POLLWRNORM; /* uhid is always writable */ poll_wait(file, &uhid->waitq, wait); if (uhid->head != uhid->tail) - return POLLIN | POLLRDNORM; + mask |= POLLIN | POLLRDNORM; - return EPOLLOUT | EPOLLWRNORM; + return mask; } static const struct file_operations uhid_fops = { -- GitLab From 10dbcf14b89929100d36e529e0d22de4b97d9a68 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 7 Mar 2019 16:58:35 +0100 Subject: [PATCH 0147/1055] ethtool: reduce stack usage with clang commit 3499e87ea0413ee5b2cc028f4c8ed4d424bc7f98 upstream. clang inlines the dev_ethtool() more aggressively than gcc does, leading to a larger amount of used stack space: net/core/ethtool.c:2536:24: error: stack frame size of 1216 bytes in function 'dev_ethtool' [-Werror,-Wframe-larger-than=] Marking the sub-functions that require the most stack space as noinline_for_stack gives us reasonable behavior on all compilers. Signed-off-by: Arnd Bergmann Reviewed-by: Michal Kubecek Signed-off-by: David S. Miller Signed-off-by: Miles Chen Signed-off-by: Greg Kroah-Hartman --- net/core/ethtool.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 7822defa5a5d..749d48393d06 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -2343,9 +2343,10 @@ static int ethtool_set_tunable(struct net_device *dev, void __user *useraddr) return ret; } -static int ethtool_get_per_queue_coalesce(struct net_device *dev, - void __user *useraddr, - struct ethtool_per_queue_op *per_queue_opt) +static noinline_for_stack int +ethtool_get_per_queue_coalesce(struct net_device *dev, + void __user *useraddr, + struct ethtool_per_queue_op *per_queue_opt) { u32 bit; int ret; @@ -2375,9 +2376,10 @@ static int ethtool_get_per_queue_coalesce(struct net_device *dev, return 0; } -static int ethtool_set_per_queue_coalesce(struct net_device *dev, - void __user *useraddr, - struct ethtool_per_queue_op *per_queue_opt) +static noinline_for_stack int +ethtool_set_per_queue_coalesce(struct net_device *dev, + void __user *useraddr, + struct ethtool_per_queue_op *per_queue_opt) { u32 bit; int i, ret = 0; @@ -2434,7 +2436,7 @@ static int ethtool_set_per_queue_coalesce(struct net_device *dev, return ret; } -static int ethtool_set_per_queue(struct net_device *dev, +static int noinline_for_stack ethtool_set_per_queue(struct net_device *dev, void __user *useraddr, u32 sub_cmd) { struct ethtool_per_queue_op per_queue_opt; -- GitLab From f3848952e00578330e427e3008f9a099ba43985c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 14 May 2019 15:41:42 -0700 Subject: [PATCH 0148/1055] fs/select: avoid clang stack usage warning commit ad312f95d41c9de19313c51e388c4984451c010f upstream. The select() implementation is carefully tuned to put a sensible amount of data on the stack for holding a copy of the user space fd_set, but not too large to risk overflowing the kernel stack. When building a 32-bit kernel with clang, we need a little more space than with gcc, which often triggers a warning: fs/select.c:619:5: error: stack frame size of 1048 bytes in function 'core_sys_select' [-Werror,-Wframe-larger-than=] int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, I experimentally found that for 32-bit ARM, reducing the maximum stack usage by 64 bytes keeps us reliably under the warning limit again. Link: http://lkml.kernel.org/r/20190307090146.1874906-1-arnd@arndb.de Signed-off-by: Arnd Bergmann Reviewed-by: Andi Kleen Cc: Nick Desaulniers Cc: Alexander Viro Cc: Christoph Hellwig Cc: Eric Dumazet Cc: "Darrick J. Wong" Cc: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Miles Chen Signed-off-by: Greg Kroah-Hartman --- include/linux/poll.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/poll.h b/include/linux/poll.h index d384f12abdd5..c7acd7c09747 100644 --- a/include/linux/poll.h +++ b/include/linux/poll.h @@ -15,7 +15,11 @@ extern struct ctl_table epoll_table[]; /* for sysctl */ /* ~832 bytes of stack space used max in sys_select/sys_poll before allocating additional memory. */ +#ifdef __clang__ +#define MAX_STACK_ALLOC 768 +#else #define MAX_STACK_ALLOC 832 +#endif #define FRONTEND_STACK_ALLOC 256 #define SELECT_STACK_ALLOC FRONTEND_STACK_ALLOC #define POLL_STACK_ALLOC FRONTEND_STACK_ALLOC -- GitLab From ba8bbddaa188235df007411fdead5832f9e0cb59 Mon Sep 17 00:00:00 2001 From: Sanjay Konduri Date: Tue, 15 May 2018 14:34:30 +0530 Subject: [PATCH 0149/1055] rsi: add fix for crash during assertions commit abd39c6ded9db53aa44c2540092bdd5fb6590fa8 upstream. Observed crash in some scenarios when assertion has occurred, this is because hw structure is freed and is tried to get accessed in some functions where null check is already present. So, avoided the crash by making the hw to NULL after freeing. Signed-off-by: Sanjay Konduri Signed-off-by: Sushant Kumar Mishra Signed-off-by: Kalle Valo Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index fa12c05d9e23..233b2239311d 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -218,6 +218,7 @@ void rsi_mac80211_detach(struct rsi_hw *adapter) ieee80211_stop_queues(hw); ieee80211_unregister_hw(hw); ieee80211_free_hw(hw); + adapter->hw = NULL; } for (band = 0; band < NUM_NL80211_BANDS; band++) { -- GitLab From 8cf89b9506ebffce80d280991da845e41b9781b0 Mon Sep 17 00:00:00 2001 From: Kristina Martsenko Date: Wed, 13 Dec 2017 17:07:20 +0000 Subject: [PATCH 0150/1055] arm64: don't open code page table entry creation commit 193383043f14a398393dc18bae8380f7fe665ec3 upstream. Instead of open coding the generation of page table entries, use the macros/functions that exist for this - pfn_p*d and p*d_populate. Most code in the kernel already uses these macros, this patch tries to fix up the few places that don't. This is useful for the next patch in this series, which needs to change the page table entry logic, and it's better to have that logic in one place. The KVM extended ID map is special, since we're creating a level above CONFIG_PGTABLE_LEVELS and the required function isn't available. Leave it as is and add a comment to explain it. (The normal kernel ID map code doesn't need this change because its page tables are created in assembly (__create_page_tables)). Tested-by: Suzuki K Poulose Reviewed-by: Suzuki K Poulose Reviewed-by: Marc Zyngier Tested-by: Bob Picco Reviewed-by: Bob Picco Signed-off-by: Kristina Martsenko Signed-off-by: Catalin Marinas Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/kvm_mmu.h | 5 +++++ arch/arm64/include/asm/pgtable.h | 1 + arch/arm64/kernel/hibernate.c | 3 +-- arch/arm64/mm/mmu.c | 14 +++++++++----- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index e42c1f0ae6cf..47ba6a57dc45 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -296,6 +296,11 @@ static inline bool __kvm_cpu_uses_extended_idmap(void) return __cpu_uses_extended_idmap(); } +/* + * Can't use pgd_populate here, because the extended idmap adds an extra level + * above CONFIG_PGTABLE_LEVELS (which is 2 or 3 if we're using the extended + * idmap), and pgd_populate is only available if CONFIG_PGTABLE_LEVELS = 4. + */ static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd, pgd_t *hyp_pgd, pgd_t *merged_hyp_pgd, diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 9b676c3dd3ce..324db23b37de 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -343,6 +343,7 @@ static inline int pmd_protnone(pmd_t pmd) #define pud_write(pud) pte_write(pud_pte(pud)) #define pud_pfn(pud) (((pud_val(pud) & PUD_MASK) & PHYS_MASK) >> PAGE_SHIFT) +#define pfn_pud(pfn,prot) (__pud(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))) #define set_pmd_at(mm, addr, pmdp, pmd) set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd)) diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c index bb444c693796..49f543ebd6cb 100644 --- a/arch/arm64/kernel/hibernate.c +++ b/arch/arm64/kernel/hibernate.c @@ -246,8 +246,7 @@ static int create_safe_exec_page(void *src_start, size_t length, } pte = pte_offset_kernel(pmd, dst_addr); - set_pte(pte, __pte(virt_to_phys((void *)dst) | - pgprot_val(PAGE_KERNEL_EXEC))); + set_pte(pte, pfn_pte(virt_to_pfn(dst), PAGE_KERNEL_EXEC)); /* * Load our new page tables. A strict BBM approach requires that we diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index abb9d2ecc675..045017e7148c 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -605,8 +605,8 @@ static void __init map_kernel(pgd_t *pgd) * entry instead. */ BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES)); - set_pud(pud_set_fixmap_offset(pgd, FIXADDR_START), - __pud(__pa_symbol(bm_pmd) | PUD_TYPE_TABLE)); + pud_populate(&init_mm, pud_set_fixmap_offset(pgd, FIXADDR_START), + lm_alias(bm_pmd)); pud_clear_fixmap(); } else { BUG(); @@ -721,7 +721,7 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node) if (!p) return -ENOMEM; - set_pmd(pmd, __pmd(__pa(p) | PROT_SECT_NORMAL)); + pmd_set_huge(pmd, __pa(p), __pgprot(PROT_SECT_NORMAL)); } else vmemmap_verify((pte_t *)pmd, node, addr, next); } while (addr = next, addr != end); @@ -915,15 +915,19 @@ int __init arch_ioremap_pmd_supported(void) int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot) { + pgprot_t sect_prot = __pgprot(PUD_TYPE_SECT | + pgprot_val(mk_sect_prot(prot))); BUG_ON(phys & ~PUD_MASK); - set_pud(pud, __pud(phys | PUD_TYPE_SECT | pgprot_val(mk_sect_prot(prot)))); + set_pud(pud, pfn_pud(__phys_to_pfn(phys), sect_prot)); return 1; } int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot) { + pgprot_t sect_prot = __pgprot(PMD_TYPE_SECT | + pgprot_val(mk_sect_prot(prot))); BUG_ON(phys & ~PMD_MASK); - set_pmd(pmd, __pmd(phys | PMD_TYPE_SECT | pgprot_val(mk_sect_prot(prot)))); + set_pmd(pmd, pfn_pmd(__phys_to_pfn(phys), sect_prot)); return 1; } -- GitLab From 9a6baa402ee47d9e3bb20e08bbae437685652eb6 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 14 Jan 2020 15:44:11 +0000 Subject: [PATCH 0151/1055] arm64: mm: Change page table pointer name in p[md]_set_huge() This is preparation for the following backported fixes. It was done upstream as part of commit 20a004e7b017 "arm64: mm: Use READ_ONCE/WRITE_ONCE when accessing page tables", the rest of which does not seem suitable for stable. Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/arm64/mm/mmu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 045017e7148c..7ea6acce6fce 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -913,21 +913,21 @@ int __init arch_ioremap_pmd_supported(void) return !IS_ENABLED(CONFIG_ARM64_PTDUMP_DEBUGFS); } -int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot) +int pud_set_huge(pud_t *pudp, phys_addr_t phys, pgprot_t prot) { pgprot_t sect_prot = __pgprot(PUD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))); BUG_ON(phys & ~PUD_MASK); - set_pud(pud, pfn_pud(__phys_to_pfn(phys), sect_prot)); + set_pud(pudp, pfn_pud(__phys_to_pfn(phys), sect_prot)); return 1; } -int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot) +int pmd_set_huge(pmd_t *pmdp, phys_addr_t phys, pgprot_t prot) { pgprot_t sect_prot = __pgprot(PMD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))); BUG_ON(phys & ~PMD_MASK); - set_pmd(pmd, pfn_pmd(__phys_to_pfn(phys), sect_prot)); + set_pmd(pmdp, pfn_pmd(__phys_to_pfn(phys), sect_prot)); return 1; } -- GitLab From 68a066f6ff13e7029d54da9d322ad686694c7039 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 21 Feb 2018 12:59:27 +0000 Subject: [PATCH 0152/1055] arm64: Enforce BBM for huge IO/VMAP mappings commit 15122ee2c515a253b0c66a3e618bc7ebe35105eb upstream. ioremap_page_range doesn't honour break-before-make and attempts to put down huge mappings (using p*d_set_huge) over the top of pre-existing table entries. This leads to us leaking page table memory and also gives rise to TLB conflicts and spurious aborts, which have been seen in practice on Cortex-A75. Until this has been resolved, refuse to put block mappings when the existing entry is found to be present. Fixes: 324420bf91f60 ("arm64: add support for ioremap() block mappings") Reported-by: Hanjun Guo Reported-by: Lei Li Acked-by: Ard Biesheuvel Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/arm64/mm/mmu.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 7ea6acce6fce..2c037a123c79 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -917,6 +917,11 @@ int pud_set_huge(pud_t *pudp, phys_addr_t phys, pgprot_t prot) { pgprot_t sect_prot = __pgprot(PUD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))); + + /* ioremap_page_range doesn't honour BBM */ + if (pud_present(READ_ONCE(*pudp))) + return 0; + BUG_ON(phys & ~PUD_MASK); set_pud(pudp, pfn_pud(__phys_to_pfn(phys), sect_prot)); return 1; @@ -926,6 +931,11 @@ int pmd_set_huge(pmd_t *pmdp, phys_addr_t phys, pgprot_t prot) { pgprot_t sect_prot = __pgprot(PMD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))); + + /* ioremap_page_range doesn't honour BBM */ + if (pmd_present(READ_ONCE(*pmdp))) + return 0; + BUG_ON(phys & ~PMD_MASK); set_pmd(pmdp, pfn_pmd(__phys_to_pfn(phys), sect_prot)); return 1; -- GitLab From 4ded4a2cf506a1aa621901d1289e89a8587963bc Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Wed, 23 May 2018 11:43:46 -0700 Subject: [PATCH 0153/1055] arm64: Make sure permission updates happen for pmd/pud commit 82034c23fcbc2389c73d97737f61fa2dd6526413 upstream. Commit 15122ee2c515 ("arm64: Enforce BBM for huge IO/VMAP mappings") disallowed block mappings for ioremap since that code does not honor break-before-make. The same APIs are also used for permission updating though and the extra checks prevent the permission updates from happening, even though this should be permitted. This results in read-only permissions not being fully applied. Visibly, this can occasionaly be seen as a failure on the built in rodata test when the test data ends up in a section or as an odd RW gap on the page table dump. Fix this by using pgattr_change_is_safe instead of p*d_present for determining if the change is permitted. Reviewed-by: Kees Cook Tested-by: Peter Robinson Reported-by: Peter Robinson Fixes: 15122ee2c515 ("arm64: Enforce BBM for huge IO/VMAP mappings") Signed-off-by: Laura Abbott Signed-off-by: Will Deacon Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/arm64/mm/mmu.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 2c037a123c79..e02a6326c800 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -917,13 +917,15 @@ int pud_set_huge(pud_t *pudp, phys_addr_t phys, pgprot_t prot) { pgprot_t sect_prot = __pgprot(PUD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))); + pud_t new_pud = pfn_pud(__phys_to_pfn(phys), sect_prot); - /* ioremap_page_range doesn't honour BBM */ - if (pud_present(READ_ONCE(*pudp))) + /* Only allow permission changes for now */ + if (!pgattr_change_is_safe(READ_ONCE(pud_val(*pudp)), + pud_val(new_pud))) return 0; BUG_ON(phys & ~PUD_MASK); - set_pud(pudp, pfn_pud(__phys_to_pfn(phys), sect_prot)); + set_pud(pudp, new_pud); return 1; } @@ -931,13 +933,15 @@ int pmd_set_huge(pmd_t *pmdp, phys_addr_t phys, pgprot_t prot) { pgprot_t sect_prot = __pgprot(PMD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))); + pmd_t new_pmd = pfn_pmd(__phys_to_pfn(phys), sect_prot); - /* ioremap_page_range doesn't honour BBM */ - if (pmd_present(READ_ONCE(*pmdp))) + /* Only allow permission changes for now */ + if (!pgattr_change_is_safe(READ_ONCE(pmd_val(*pmdp)), + pmd_val(new_pmd))) return 0; BUG_ON(phys & ~PMD_MASK); - set_pmd(pmdp, pfn_pmd(__phys_to_pfn(phys), sect_prot)); + set_pmd(pmdp, new_pmd); return 1; } -- GitLab From b06e6e5c3705d14a90f30955bce7befd24adecc4 Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Sun, 29 Jul 2018 14:59:16 +0300 Subject: [PATCH 0154/1055] cfg80211/mac80211: make ieee80211_send_layer2_update a public function commit 30ca1aa536211f5ac3de0173513a7a99a98a97f3 upstream. Make ieee80211_send_layer2_update() a common function so other drivers can re-use it. Signed-off-by: Dedy Lansky Signed-off-by: Johannes Berg [bwh: Backported to 4.14 as dependency of commit 3e493173b784 "mac80211: Do not send Layer 2 Update frame before authorization"] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- include/net/cfg80211.h | 11 ++++++++++ net/mac80211/cfg.c | 48 ++---------------------------------------- net/wireless/util.c | 45 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 46 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ea0ed58db97e..a4c8e9d7dd06 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4479,6 +4479,17 @@ static inline const u8 *cfg80211_find_ext_ie(u8 ext_eid, const u8 *ies, int len) const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type, const u8 *ies, int len); +/** + * cfg80211_send_layer2_update - send layer 2 update frame + * + * @dev: network device + * @addr: STA MAC address + * + * Wireless drivers can use this function to update forwarding tables in bridge + * devices upon STA association. + */ +void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr); + /** * DOC: Regulatory enforcement infrastructure * diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8168c667d91d..f236a990638f 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1089,50 +1089,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) return 0; } -/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ -struct iapp_layer2_update { - u8 da[ETH_ALEN]; /* broadcast */ - u8 sa[ETH_ALEN]; /* STA addr */ - __be16 len; /* 6 */ - u8 dsap; /* 0 */ - u8 ssap; /* 0 */ - u8 control; - u8 xid_info[3]; -} __packed; - -static void ieee80211_send_layer2_update(struct sta_info *sta) -{ - struct iapp_layer2_update *msg; - struct sk_buff *skb; - - /* Send Level 2 Update Frame to update forwarding tables in layer 2 - * bridge devices */ - - skb = dev_alloc_skb(sizeof(*msg)); - if (!skb) - return; - msg = skb_put(skb, sizeof(*msg)); - - /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) - * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ - - eth_broadcast_addr(msg->da); - memcpy(msg->sa, sta->sta.addr, ETH_ALEN); - msg->len = htons(6); - msg->dsap = 0; - msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */ - msg->control = 0xaf; /* XID response lsb.1111F101. - * F=0 (no poll command; unsolicited frame) */ - msg->xid_info[0] = 0x81; /* XID format identifier */ - msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ - msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ - - skb->dev = sta->sdata->dev; - skb->protocol = eth_type_trans(skb, sta->sdata->dev); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx_ni(skb); -} - static int sta_apply_auth_flags(struct ieee80211_local *local, struct sta_info *sta, u32 mask, u32 set) @@ -1496,7 +1452,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, } if (layer2_update) - ieee80211_send_layer2_update(sta); + cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr); rcu_read_unlock(); @@ -1598,7 +1554,7 @@ static int ieee80211_change_station(struct wiphy *wiphy, if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) ieee80211_vif_inc_num_mcast(sta->sdata); - ieee80211_send_layer2_update(sta); + cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr); } err = sta_apply_parameters(local, sta, params); diff --git a/net/wireless/util.c b/net/wireless/util.c index 0f6c34ff9b55..2234817f5dbb 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1873,3 +1873,48 @@ EXPORT_SYMBOL(rfc1042_header); const unsigned char bridge_tunnel_header[] __aligned(2) = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; EXPORT_SYMBOL(bridge_tunnel_header); + +/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ +struct iapp_layer2_update { + u8 da[ETH_ALEN]; /* broadcast */ + u8 sa[ETH_ALEN]; /* STA addr */ + __be16 len; /* 6 */ + u8 dsap; /* 0 */ + u8 ssap; /* 0 */ + u8 control; + u8 xid_info[3]; +} __packed; + +void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr) +{ + struct iapp_layer2_update *msg; + struct sk_buff *skb; + + /* Send Level 2 Update Frame to update forwarding tables in layer 2 + * bridge devices */ + + skb = dev_alloc_skb(sizeof(*msg)); + if (!skb) + return; + msg = skb_put(skb, sizeof(*msg)); + + /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) + * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ + + eth_broadcast_addr(msg->da); + ether_addr_copy(msg->sa, addr); + msg->len = htons(6); + msg->dsap = 0; + msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */ + msg->control = 0xaf; /* XID response lsb.1111F101. + * F=0 (no poll command; unsolicited frame) */ + msg->xid_info[0] = 0x81; /* XID format identifier */ + msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ + msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx_ni(skb); +} +EXPORT_SYMBOL(cfg80211_send_layer2_update); -- GitLab From 57e1b5f6b55acb655358bd62c7e2f14d8af90e0a Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Wed, 11 Sep 2019 16:03:05 +0300 Subject: [PATCH 0155/1055] mac80211: Do not send Layer 2 Update frame before authorization commit 3e493173b7841259a08c5c8e5cbe90adb349da7e upstream. The Layer 2 Update frame is used to update bridges when a station roams to another AP even if that STA does not transmit any frames after the reassociation. This behavior was described in IEEE Std 802.11F-2003 as something that would happen based on MLME-ASSOCIATE.indication, i.e., before completing 4-way handshake. However, this IEEE trial-use recommended practice document was published before RSN (IEEE Std 802.11i-2004) and as such, did not consider RSN use cases. Furthermore, IEEE Std 802.11F-2003 was withdrawn in 2006 and as such, has not been maintained amd should not be used anymore. Sending out the Layer 2 Update frame immediately after association is fine for open networks (and also when using SAE, FT protocol, or FILS authentication when the station is actually authenticated by the time association completes). However, it is not appropriate for cases where RSN is used with PSK or EAP authentication since the station is actually fully authenticated only once the 4-way handshake completes after authentication and attackers might be able to use the unauthenticated triggering of Layer 2 Update frame transmission to disrupt bridge behavior. Fix this by postponing transmission of the Layer 2 Update frame from station entry addition to the point when the station entry is marked authorized. Similarly, send out the VLAN binding update only if the STA entry has already been authorized. Signed-off-by: Jouni Malinen Reviewed-by: Johannes Berg Signed-off-by: David S. Miller Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- net/mac80211/cfg.c | 14 ++++---------- net/mac80211/sta_info.c | 4 ++++ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index f236a990638f..d437007b15bb 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1398,7 +1398,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, struct sta_info *sta; struct ieee80211_sub_if_data *sdata; int err; - int layer2_update; if (params->vlan) { sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); @@ -1442,18 +1441,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, test_sta_flag(sta, WLAN_STA_ASSOC)) rate_control_rate_init(sta); - layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || - sdata->vif.type == NL80211_IFTYPE_AP; - err = sta_info_insert_rcu(sta); if (err) { rcu_read_unlock(); return err; } - if (layer2_update) - cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr); - rcu_read_unlock(); return 0; @@ -1551,10 +1544,11 @@ static int ieee80211_change_station(struct wiphy *wiphy, sta->sdata = vlansdata; ieee80211_check_fast_xmit(sta); - if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) + if (test_sta_flag(sta, WLAN_STA_AUTHORIZED)) { ieee80211_vif_inc_num_mcast(sta->sdata); - - cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr); + cfg80211_send_layer2_update(sta->sdata->dev, + sta->sta.addr); + } } err = sta_apply_parameters(local, sta, params); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 1a86974b02e3..627dc642f894 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1899,6 +1899,10 @@ int sta_info_move_state(struct sta_info *sta, ieee80211_check_fast_xmit(sta); ieee80211_check_fast_rx(sta); } + if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN || + sta->sdata->vif.type == NL80211_IFTYPE_AP) + cfg80211_send_layer2_update(sta->sdata->dev, + sta->sta.addr); break; default: break; -- GitLab From ffe76c896fbc91af8859aaea15b75b0b887960f3 Mon Sep 17 00:00:00 2001 From: Vandana BN Date: Wed, 22 May 2019 04:34:15 -0400 Subject: [PATCH 0156/1055] media: usb:zr364xx:Fix KASAN:null-ptr-deref Read in zr364xx_vidioc_querycap commit 5d2e73a5f80a5b5aff3caf1ec6d39b5b3f54b26e upstream. SyzKaller hit the null pointer deref while reading from uninitialized udev->product in zr364xx_vidioc_querycap(). ================================================================== BUG: KASAN: null-ptr-deref in read_word_at_a_time+0xe/0x20 include/linux/compiler.h:274 Read of size 1 at addr 0000000000000000 by task v4l_id/5287 CPU: 1 PID: 5287 Comm: v4l_id Not tainted 5.1.0-rc3-319004-g43151d6 #6 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+0xe8/0x16e lib/dump_stack.c:113 kasan_report.cold+0x5/0x3c mm/kasan/report.c:321 read_word_at_a_time+0xe/0x20 include/linux/compiler.h:274 strscpy+0x8a/0x280 lib/string.c:207 zr364xx_vidioc_querycap+0xb5/0x210 drivers/media/usb/zr364xx/zr364xx.c:706 v4l_querycap+0x12b/0x340 drivers/media/v4l2-core/v4l2-ioctl.c:1062 __video_do_ioctl+0x5bb/0xb40 drivers/media/v4l2-core/v4l2-ioctl.c:2874 video_usercopy+0x44e/0xf00 drivers/media/v4l2-core/v4l2-ioctl.c:3056 v4l2_ioctl+0x14e/0x1a0 drivers/media/v4l2-core/v4l2-dev.c:364 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:509 [inline] do_vfs_ioctl+0xced/0x12f0 fs/ioctl.c:696 ksys_ioctl+0xa0/0xc0 fs/ioctl.c:713 __do_sys_ioctl fs/ioctl.c:720 [inline] __se_sys_ioctl fs/ioctl.c:718 [inline] __x64_sys_ioctl+0x74/0xb0 fs/ioctl.c:718 do_syscall_64+0xcf/0x4f0 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x7f3b56d8b347 Code: 90 90 90 48 8b 05 f1 fa 2a 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 90 90 90 90 90 90 90 90 90 90 b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d c1 fa 2a 00 31 d2 48 29 c2 64 RSP: 002b:00007ffe005d5d68 EFLAGS: 00000202 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007f3b56d8b347 RDX: 00007ffe005d5d70 RSI: 0000000080685600 RDI: 0000000000000003 RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000400884 R13: 00007ffe005d5ec0 R14: 0000000000000000 R15: 0000000000000000 ================================================================== For this device udev->product is not initialized and accessing it causes a NULL pointer deref. The fix is to check for NULL before strscpy() and copy empty string, if product is NULL Reported-by: syzbot+66010012fd4c531a1a96@syzkaller.appspotmail.com Signed-off-by: Vandana BN Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab [bwh: Backported to 4.14: This function uses strlcpy() instead of strscpy()] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/zr364xx/zr364xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 4ff8d0aed015..d30f129a9db7 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -706,7 +706,8 @@ static int zr364xx_vidioc_querycap(struct file *file, void *priv, struct zr364xx_camera *cam = video_drvdata(file); strlcpy(cap->driver, DRIVER_DESC, sizeof(cap->driver)); - strlcpy(cap->card, cam->udev->product, sizeof(cap->card)); + if (cam->udev->product) + strlcpy(cap->card, cam->udev->product, sizeof(cap->card)); strlcpy(cap->bus_info, dev_name(&cam->udev->dev), sizeof(cap->bus_info)); cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | -- GitLab From 1059b758b6fb0fb6949b8c0474d5db27ea269b01 Mon Sep 17 00:00:00 2001 From: ZhangXiaoxu Date: Sat, 6 Apr 2019 15:30:38 +0800 Subject: [PATCH 0157/1055] cifs: Fix lease buffer length error commit b57a55e2200ede754e4dc9cce4ba9402544b9365 upstream. There is a KASAN slab-out-of-bounds: BUG: KASAN: slab-out-of-bounds in _copy_from_iter_full+0x783/0xaa0 Read of size 80 at addr ffff88810c35e180 by task mount.cifs/539 CPU: 1 PID: 539 Comm: mount.cifs Not tainted 4.19 #10 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-0-ga698c8995f-prebuilt.qemu.org 04/01/2014 Call Trace: dump_stack+0xdd/0x12a print_address_description+0xa7/0x540 kasan_report+0x1ff/0x550 check_memory_region+0x2f1/0x310 memcpy+0x2f/0x80 _copy_from_iter_full+0x783/0xaa0 tcp_sendmsg_locked+0x1840/0x4140 tcp_sendmsg+0x37/0x60 inet_sendmsg+0x18c/0x490 sock_sendmsg+0xae/0x130 smb_send_kvec+0x29c/0x520 __smb_send_rqst+0x3ef/0xc60 smb_send_rqst+0x25a/0x2e0 compound_send_recv+0x9e8/0x2af0 cifs_send_recv+0x24/0x30 SMB2_open+0x35e/0x1620 open_shroot+0x27b/0x490 smb2_open_op_close+0x4e1/0x590 smb2_query_path_info+0x2ac/0x650 cifs_get_inode_info+0x1058/0x28f0 cifs_root_iget+0x3bb/0xf80 cifs_smb3_do_mount+0xe00/0x14c0 cifs_do_mount+0x15/0x20 mount_fs+0x5e/0x290 vfs_kern_mount+0x88/0x460 do_mount+0x398/0x31e0 ksys_mount+0xc6/0x150 __x64_sys_mount+0xea/0x190 do_syscall_64+0x122/0x590 entry_SYSCALL_64_after_hwframe+0x44/0xa9 It can be reproduced by the following step: 1. samba configured with: server max protocol = SMB2_10 2. mount -o vers=default When parse the mount version parameter, the 'ops' and 'vals' was setted to smb30, if negotiate result is smb21, just update the 'ops' to smb21, but the 'vals' is still smb30. When add lease context, the iov_base is allocated with smb21 ops, but the iov_len is initiallited with the smb30. Because the iov_len is longer than iov_base, when send the message, copy array out of bounds. we need to keep the 'ops' and 'vals' consistent. Fixes: 9764c02fcbad ("SMB3: Add support for multidialect negotiate (SMB2.1 and later)") Fixes: d5c7076b772a ("smb3: add smb3.1.1 to default dialect list") Signed-off-by: ZhangXiaoxu Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky [bwh: Backported to 4.14: We never switch to SMB3.1.1 here] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- fs/cifs/smb2pdu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 0e1c36c92f60..4eb0a9e7194b 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -575,6 +575,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) } else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) { /* ops set to 3.0 by default for default so update */ ses->server->ops = &smb21_operations; + ses->server->vals = &smb21_values; } } else if (le16_to_cpu(rsp->DialectRevision) != ses->server->vals->protocol_id) { -- GitLab From cae904fa00de645b6de57c698e5e00c0ba7e97e8 Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Tue, 10 Sep 2019 18:01:40 -0500 Subject: [PATCH 0158/1055] wimax: i2400: fix memory leak commit 2507e6ab7a9a440773be476141a255934468c5ef upstream. In i2400m_op_rfkill_sw_toggle cmd buffer should be released along with skb response. Signed-off-by: Navid Emamdoost Signed-off-by: David S. Miller Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/wimax/i2400m/op-rfkill.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c index b0dba35a8ad2..7c92e8ace9c2 100644 --- a/drivers/net/wimax/i2400m/op-rfkill.c +++ b/drivers/net/wimax/i2400m/op-rfkill.c @@ -142,6 +142,7 @@ int i2400m_op_rfkill_sw_toggle(struct wimax_dev *wimax_dev, "%d\n", result); result = 0; error_cmd: + kfree(cmd); kfree_skb(ack_skb); error_msg_to_dev: error_alloc: -- GitLab From 67a8c1b6bc85dfe2d2ae5d86d1ea8d00b1b29493 Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Fri, 25 Oct 2019 23:53:30 -0500 Subject: [PATCH 0159/1055] wimax: i2400: Fix memory leak in i2400m_op_rfkill_sw_toggle commit 6f3ef5c25cc762687a7341c18cbea5af54461407 upstream. In the implementation of i2400m_op_rfkill_sw_toggle() the allocated buffer for cmd should be released before returning. The documentation for i2400m_msg_to_dev() says when it returns the buffer can be reused. Meaning cmd should be released in either case. Move kfree(cmd) before return to be reached by all execution paths. Fixes: 2507e6ab7a9a ("wimax: i2400: fix memory leak") Signed-off-by: Navid Emamdoost Signed-off-by: David S. Miller Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/wimax/i2400m/op-rfkill.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c index 7c92e8ace9c2..dc6fe93ce71f 100644 --- a/drivers/net/wimax/i2400m/op-rfkill.c +++ b/drivers/net/wimax/i2400m/op-rfkill.c @@ -142,12 +142,12 @@ int i2400m_op_rfkill_sw_toggle(struct wimax_dev *wimax_dev, "%d\n", result); result = 0; error_cmd: - kfree(cmd); kfree_skb(ack_skb); error_msg_to_dev: error_alloc: d_fnend(4, dev, "(wimax_dev %p state %d) = %d\n", wimax_dev, state, result); + kfree(cmd); return result; } -- GitLab From db1fb5a39747a680a4cc182c8bb4648b845a841f Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Thu, 12 Sep 2019 23:23:27 -0500 Subject: [PATCH 0160/1055] iwlwifi: dbg_ini: fix memory leak in alloc_sgtable commit b4b814fec1a5a849383f7b3886b654a13abbda7d upstream. In alloc_sgtable if alloc_page fails, the alocated table should be released. Signed-off-by: Navid Emamdoost Signed-off-by: Luca Coelho Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 4650b9e5da2b..ba9e7bfeca2c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -532,6 +532,7 @@ static struct scatterlist *alloc_sgtable(int size) if (new_page) __free_page(new_page); } + kfree(table); return NULL; } alloc_size = min_t(int, size, PAGE_SIZE); -- GitLab From d0c15c1e8f9223552818fe5340b0427483b34f22 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 1 Apr 2019 09:35:54 +0800 Subject: [PATCH 0161/1055] dccp: Fix memleak in __feat_register_sp commit 1d3ff0950e2b40dc861b1739029649d03f591820 upstream. If dccp_feat_push_change fails, we forget free the mem which is alloced by kmemdup in dccp_feat_clone_sp_val. Reported-by: Hulk Robot Fixes: e8ef967a54f4 ("dccp: Registration routines for changing feature values") Reviewed-by: Mukesh Ojha Signed-off-by: YueHaibing Signed-off-by: David S. Miller Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- net/dccp/feat.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/dccp/feat.c b/net/dccp/feat.c index f227f002c73d..db87d9f58019 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c @@ -738,7 +738,12 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local, if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len)) return -ENOMEM; - return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval); + if (dccp_feat_push_change(fn, feat, is_local, mandatory, &fval)) { + kfree(fval.sp.vec); + return -ENOMEM; + } + + return 0; } /** -- GitLab From 573e1fe003c1e2016bc40cc4f2b231e3b8c990f8 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Tue, 14 Jan 2020 18:39:37 +0000 Subject: [PATCH 0162/1055] drm/i915: Fix use-after-free when destroying GEM context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch is a simplified fix to address a use-after-free in 4.14.x and 4.19.x stable kernels. The flaw is already fixed upstream, starting in 5.2, by commit 7dc40713618c ("drm/i915: Introduce a mutex for file_priv->context_idr") as part of a more complex patch series that isn't appropriate for backporting to stable kernels. Expand mutex coverage, while destroying the GEM context, to include the GEM context lookup step. This fixes a use-after-free detected by KASAN: ================================================================== BUG: KASAN: use-after-free in i915_ppgtt_close+0x2ca/0x2f0 Write of size 1 at addr ffff8881368a8368 by task i915-poc/3124 CPU: 0 PID: 3124 Comm: i915-poc Not tainted 4.14.164 #1 Hardware name: HP HP Elite x2 1012 G1 /80FC, BIOS N85 Ver. 01.20 04/05/2017 Call Trace: dump_stack+0xcd/0x12e ? _atomic_dec_and_lock+0x1b2/0x1b2 ? i915_ppgtt_close+0x2ca/0x2f0 ? printk+0x8f/0xab ? show_regs_print_info+0x53/0x53 ? i915_ppgtt_close+0x2ca/0x2f0 print_address_description+0x65/0x270 ? i915_ppgtt_close+0x2ca/0x2f0 kasan_report+0x251/0x340 i915_ppgtt_close+0x2ca/0x2f0 ? __radix_tree_insert+0x3f0/0x3f0 ? i915_ppgtt_init_hw+0x7c0/0x7c0 context_close+0x42e/0x680 ? i915_gem_context_release+0x230/0x230 ? kasan_kmalloc+0xa0/0xd0 ? radix_tree_delete_item+0x1d4/0x250 ? radix_tree_lookup+0x10/0x10 ? inet_recvmsg+0x4b0/0x4b0 ? kasan_slab_free+0x88/0xc0 i915_gem_context_destroy_ioctl+0x236/0x300 ? i915_gem_context_create_ioctl+0x360/0x360 ? drm_dev_printk+0x1d0/0x1d0 ? memcpy+0x34/0x50 ? i915_gem_context_create_ioctl+0x360/0x360 drm_ioctl_kernel+0x1b0/0x2b0 ? drm_ioctl_permit+0x2a0/0x2a0 ? avc_ss_reset+0xd0/0xd0 drm_ioctl+0x6fe/0xa20 ? i915_gem_context_create_ioctl+0x360/0x360 ? drm_getstats+0x20/0x20 ? put_unused_fd+0x260/0x260 do_vfs_ioctl+0x189/0x12d0 ? ioctl_preallocate+0x280/0x280 ? selinux_file_ioctl+0x3a7/0x680 ? selinux_bprm_set_creds+0xe30/0xe30 ? security_file_ioctl+0x69/0xa0 ? selinux_bprm_set_creds+0xe30/0xe30 SyS_ioctl+0x6f/0x80 ? __sys_sendmmsg+0x4a0/0x4a0 ? do_vfs_ioctl+0x12d0/0x12d0 do_syscall_64+0x214/0x5f0 ? __switch_to_asm+0x31/0x60 ? __switch_to_asm+0x25/0x60 ? __switch_to_asm+0x31/0x60 ? syscall_return_slowpath+0x2c0/0x2c0 ? copy_overflow+0x20/0x20 ? __switch_to_asm+0x25/0x60 ? syscall_return_via_sysret+0x2a/0x7a ? prepare_exit_to_usermode+0x200/0x200 ? __switch_to_asm+0x31/0x60 ? __switch_to_asm+0x31/0x60 ? __switch_to_asm+0x25/0x60 ? __switch_to_asm+0x25/0x60 ? __switch_to_asm+0x31/0x60 ? __switch_to_asm+0x25/0x60 ? __switch_to_asm+0x31/0x60 ? __switch_to_asm+0x31/0x60 ? __switch_to_asm+0x25/0x60 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x7f7fda5115d7 RSP: 002b:00007f7eec317ec8 EFLAGS: 00000286 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f7fda5115d7 RDX: 000055b306db9188 RSI: 000000004008646e RDI: 0000000000000003 RBP: 00007f7eec317ef0 R08: 00007f7eec318700 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000286 R12: 00007f7eec317fc0 R13: 0000000000000000 R14: 0000000000000000 R15: 00007ffd8007ade0 Allocated by task 2898: save_stack+0x32/0xb0 kasan_kmalloc+0xa0/0xd0 kmem_cache_alloc_trace+0x5e/0x180 i915_ppgtt_create+0xab/0x2510 i915_gem_create_context+0x981/0xf90 i915_gem_context_create_ioctl+0x1d7/0x360 drm_ioctl_kernel+0x1b0/0x2b0 drm_ioctl+0x6fe/0xa20 do_vfs_ioctl+0x189/0x12d0 SyS_ioctl+0x6f/0x80 do_syscall_64+0x214/0x5f0 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Freed by task 104: save_stack+0x32/0xb0 kasan_slab_free+0x72/0xc0 kfree+0x88/0x190 i915_ppgtt_release+0x24e/0x460 i915_gem_context_free+0x90/0x480 contexts_free_worker+0x54/0x80 process_one_work+0x876/0x14e0 worker_thread+0x1b8/0xfd0 kthread+0x2f8/0x3c0 ret_from_fork+0x35/0x40 The buggy address belongs to the object at ffff8881368a8000 which belongs to the cache kmalloc-8192 of size 8192 The buggy address is located 872 bytes inside of 8192-byte region [ffff8881368a8000, ffff8881368aa000) The buggy address belongs to the page: page:ffffea0004da2a00 count:1 mapcount:0 mapping: (null) index:0x0 compound_mapcount: 0 flags: 0x200000000008100(slab|head) raw: 0200000000008100 0000000000000000 0000000000000000 0000000100030003 raw: dead000000000100 dead000000000200 ffff88822a002280 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff8881368a8200: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff8881368a8280: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb >ffff8881368a8300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ^ ffff8881368a8380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff8881368a8400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ================================================================== Fixes: 1acfc104cdf8 ("drm/i915: Enable rcu-only context lookups") Reported-by: 罗权 Cc: Chris Wilson Cc: Jon Bloomfield Cc: stable@vger.kernel.org # 4.14.x Cc: stable@vger.kernel.org # 4.19.x Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_gem_context.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 3925a63c1661..cdb67889817c 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -993,18 +993,19 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, if (args->ctx_id == DEFAULT_CONTEXT_HANDLE) return -ENOENT; + ret = i915_mutex_lock_interruptible(dev); + if (ret) + return ret; + ctx = i915_gem_context_lookup(file_priv, args->ctx_id); - if (!ctx) + if (!ctx) { + mutex_unlock(&dev->struct_mutex); return -ENOENT; - - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - goto out; + } __destroy_hw_context(ctx, file_priv); mutex_unlock(&dev->struct_mutex); -out: i915_gem_context_put(ctx); return 0; } -- GitLab From f1545409a5e179e4bc94a0fc28eebb61b2e1ff33 Mon Sep 17 00:00:00 2001 From: Ran Bi Date: Wed, 11 Dec 2019 17:43:54 +0800 Subject: [PATCH 0163/1055] rtc: mt6397: fix alarm register overwrite commit 653997eeecef95c3ead4fba1b2d27e6a5854d6cd upstream. Alarm registers high byte was reserved for other functions. This add mask in alarm registers operation functions. This also fix error condition in interrupt handler. Fixes: fc2979118f3f ("rtc: mediatek: Add MT6397 RTC driver") Signed-off-by: Ran Bi Signed-off-by: Hsin-Hsiung Wang Link: https://lore.kernel.org/r/1576057435-3561-6-git-send-email-hsin-hsiung.wang@mediatek.com Signed-off-by: Alexandre Belloni Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-mt6397.c | 47 ++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index e82df43e5ca2..c696d9186451 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -55,6 +55,14 @@ #define RTC_AL_SEC 0x0018 +#define RTC_AL_SEC_MASK 0x003f +#define RTC_AL_MIN_MASK 0x003f +#define RTC_AL_HOU_MASK 0x001f +#define RTC_AL_DOM_MASK 0x001f +#define RTC_AL_DOW_MASK 0x0007 +#define RTC_AL_MTH_MASK 0x000f +#define RTC_AL_YEA_MASK 0x007f + #define RTC_PDN2 0x002e #define RTC_PDN2_PWRON_ALARM BIT(4) @@ -111,7 +119,7 @@ static irqreturn_t mtk_rtc_irq_handler_thread(int irq, void *data) irqen = irqsta & ~RTC_IRQ_EN_AL; mutex_lock(&rtc->lock); if (regmap_write(rtc->regmap, rtc->addr_base + RTC_IRQ_EN, - irqen) < 0) + irqen) == 0) mtk_rtc_write_trigger(rtc); mutex_unlock(&rtc->lock); @@ -233,12 +241,12 @@ static int mtk_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) alm->pending = !!(pdn2 & RTC_PDN2_PWRON_ALARM); mutex_unlock(&rtc->lock); - tm->tm_sec = data[RTC_OFFSET_SEC]; - tm->tm_min = data[RTC_OFFSET_MIN]; - tm->tm_hour = data[RTC_OFFSET_HOUR]; - tm->tm_mday = data[RTC_OFFSET_DOM]; - tm->tm_mon = data[RTC_OFFSET_MTH]; - tm->tm_year = data[RTC_OFFSET_YEAR]; + tm->tm_sec = data[RTC_OFFSET_SEC] & RTC_AL_SEC_MASK; + tm->tm_min = data[RTC_OFFSET_MIN] & RTC_AL_MIN_MASK; + tm->tm_hour = data[RTC_OFFSET_HOUR] & RTC_AL_HOU_MASK; + tm->tm_mday = data[RTC_OFFSET_DOM] & RTC_AL_DOM_MASK; + tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_AL_MTH_MASK; + tm->tm_year = data[RTC_OFFSET_YEAR] & RTC_AL_YEA_MASK; tm->tm_year += RTC_MIN_YEAR_OFFSET; tm->tm_mon--; @@ -259,14 +267,25 @@ static int mtk_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) tm->tm_year -= RTC_MIN_YEAR_OFFSET; tm->tm_mon++; - data[RTC_OFFSET_SEC] = tm->tm_sec; - data[RTC_OFFSET_MIN] = tm->tm_min; - data[RTC_OFFSET_HOUR] = tm->tm_hour; - data[RTC_OFFSET_DOM] = tm->tm_mday; - data[RTC_OFFSET_MTH] = tm->tm_mon; - data[RTC_OFFSET_YEAR] = tm->tm_year; - mutex_lock(&rtc->lock); + ret = regmap_bulk_read(rtc->regmap, rtc->addr_base + RTC_AL_SEC, + data, RTC_OFFSET_COUNT); + if (ret < 0) + goto exit; + + data[RTC_OFFSET_SEC] = ((data[RTC_OFFSET_SEC] & ~(RTC_AL_SEC_MASK)) | + (tm->tm_sec & RTC_AL_SEC_MASK)); + data[RTC_OFFSET_MIN] = ((data[RTC_OFFSET_MIN] & ~(RTC_AL_MIN_MASK)) | + (tm->tm_min & RTC_AL_MIN_MASK)); + data[RTC_OFFSET_HOUR] = ((data[RTC_OFFSET_HOUR] & ~(RTC_AL_HOU_MASK)) | + (tm->tm_hour & RTC_AL_HOU_MASK)); + data[RTC_OFFSET_DOM] = ((data[RTC_OFFSET_DOM] & ~(RTC_AL_DOM_MASK)) | + (tm->tm_mday & RTC_AL_DOM_MASK)); + data[RTC_OFFSET_MTH] = ((data[RTC_OFFSET_MTH] & ~(RTC_AL_MTH_MASK)) | + (tm->tm_mon & RTC_AL_MTH_MASK)); + data[RTC_OFFSET_YEAR] = ((data[RTC_OFFSET_YEAR] & ~(RTC_AL_YEA_MASK)) | + (tm->tm_year & RTC_AL_YEA_MASK)); + if (alm->enabled) { ret = regmap_bulk_write(rtc->regmap, rtc->addr_base + RTC_AL_SEC, -- GitLab From d070b8d5701e91dee87603c784cfb2484e5db4e1 Mon Sep 17 00:00:00 2001 From: Selvin Xavier Date: Mon, 25 Nov 2019 00:39:30 -0800 Subject: [PATCH 0164/1055] RDMA/bnxt_re: Fix Send Work Entry state check while polling completions commit c5275723580922e5f3264f96751337661a153c7d upstream. Some adapters need a fence Work Entry to handle retransmission. Currently the driver checks for this condition, only if the Send queue entry is signalled. Implement the condition check, irrespective of the signalled state of the Work queue entries Failure to add the fence can result in access to memory that is already marked as completed, triggering data corruption, transmission failure, IOMMU failures, etc. Fixes: 9152e0b722b2 ("RDMA/bnxt_re: HW workarounds for handling specific conditions") Link: https://lore.kernel.org/r/1574671174-5064-3-git-send-email-selvin.xavier@broadcom.com Signed-off-by: Selvin Xavier Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index e8afc47f8949..908803fe8276 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -2024,13 +2024,13 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq, bnxt_qplib_mark_qp_error(qp); bnxt_qplib_unlock_buddy_cq(qp, cq); } else { + /* Before we complete, do WA 9060 */ + if (do_wa9060(qp, cq, cq_cons, sw_sq_cons, + cqe_sq_cons)) { + *lib_qp = qp; + goto out; + } if (swq->flags & SQ_SEND_FLAGS_SIGNAL_COMP) { - /* Before we complete, do WA 9060 */ - if (do_wa9060(qp, cq, cq_cons, sw_sq_cons, - cqe_sq_cons)) { - *lib_qp = qp; - goto out; - } cqe->status = CQ_REQ_STATUS_OK; cqe++; (*budget)--; -- GitLab From 42182bcccd7f534d462240f2d341ecba60567ecd Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Wed, 4 Dec 2019 16:43:31 +0100 Subject: [PATCH 0165/1055] ASoC: stm32: spdifrx: fix inconsistent lock state commit 2859b1784031b5709446af8f6039c467f136e67d upstream. In current spdifrx driver locks may be requested as follows: - request lock on iec capture control, when starting synchronization. - request lock in interrupt context, when spdifrx stop is called from IRQ handler. Take lock with IRQs disabled, to avoid the possible deadlock. Lockdep report: [ 74.278059] ================================ [ 74.282306] WARNING: inconsistent lock state [ 74.290120] -------------------------------- ... [ 74.314373] CPU0 [ 74.314377] ---- [ 74.314381] lock(&(&spdifrx->lock)->rlock); [ 74.314396] [ 74.314400] lock(&(&spdifrx->lock)->rlock); Fixes: 03e4d5d56fa5 ("ASoC: stm32: Add SPDIFRX support") Signed-off-by: Olivier Moysan Link: https://lore.kernel.org/r/20191204154333.7152-2-olivier.moysan@st.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/stm/stm32_spdifrx.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index 84cc5678beba..60d7980104e0 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -313,6 +313,7 @@ static void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx) static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) { int cr, cr_mask, imr, ret; + unsigned long flags; /* Enable IRQs */ imr = SPDIFRX_IMR_IFEIE | SPDIFRX_IMR_SYNCDIE | SPDIFRX_IMR_PERRIE; @@ -320,7 +321,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) if (ret) return ret; - spin_lock(&spdifrx->lock); + spin_lock_irqsave(&spdifrx->lock, flags); spdifrx->refcount++; @@ -353,7 +354,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) "Failed to start synchronization\n"); } - spin_unlock(&spdifrx->lock); + spin_unlock_irqrestore(&spdifrx->lock, flags); return ret; } @@ -361,11 +362,12 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) { int cr, cr_mask, reg; + unsigned long flags; - spin_lock(&spdifrx->lock); + spin_lock_irqsave(&spdifrx->lock, flags); if (--spdifrx->refcount) { - spin_unlock(&spdifrx->lock); + spin_unlock_irqrestore(&spdifrx->lock, flags); return; } @@ -384,7 +386,7 @@ static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) regmap_read(spdifrx->regmap, STM32_SPDIFRX_DR, ®); regmap_read(spdifrx->regmap, STM32_SPDIFRX_CSR, ®); - spin_unlock(&spdifrx->lock); + spin_unlock_irqrestore(&spdifrx->lock, flags); } static int stm32_spdifrx_dma_ctrl_register(struct device *dev, -- GitLab From 3b3c9bfa0640ab023221248460dc578dad5b356b Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Wed, 4 Dec 2019 16:43:32 +0100 Subject: [PATCH 0166/1055] ASoC: stm32: spdifrx: fix race condition in irq handler commit 86e1956af4c863d653136fd6e5694adf2054dbaa upstream. When snd_pcm_stop() is called in interrupt routine, substream context may have already been released. Add protection on substream context. Fixes: 03e4d5d56fa5 ("ASoC: stm32: Add SPDIFRX support") Signed-off-by: Olivier Moysan Link: https://lore.kernel.org/r/20191204154333.7152-3-olivier.moysan@st.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/stm/stm32_spdifrx.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index 60d7980104e0..7bc57651e186 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -213,6 +213,7 @@ * @slave_config: dma slave channel runtime config pointer * @phys_addr: SPDIFRX registers physical base address * @lock: synchronization enabling lock + * @irq_lock: prevent race condition with IRQ on stream state * @cs: channel status buffer * @ub: user data buffer * @irq: SPDIFRX interrupt line @@ -233,6 +234,7 @@ struct stm32_spdifrx_data { struct dma_slave_config slave_config; dma_addr_t phys_addr; spinlock_t lock; /* Sync enabling lock */ + spinlock_t irq_lock; /* Prevent race condition on stream state */ unsigned char cs[SPDIFRX_CS_BYTES_NB]; unsigned char ub[SPDIFRX_UB_BYTES_NB]; int irq; @@ -646,7 +648,6 @@ static const struct regmap_config stm32_h7_spdifrx_regmap_conf = { static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) { struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)devid; - struct snd_pcm_substream *substream = spdifrx->substream; struct platform_device *pdev = spdifrx->pdev; unsigned int cr, mask, sr, imr; unsigned int flags; @@ -714,14 +715,19 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, SPDIFRX_CR_SPDIFEN_MASK, cr); - if (substream) - snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); + spin_lock(&spdifrx->irq_lock); + if (spdifrx->substream) + snd_pcm_stop(spdifrx->substream, + SNDRV_PCM_STATE_DISCONNECTED); + spin_unlock(&spdifrx->irq_lock); return IRQ_HANDLED; } - if (err_xrun && substream) - snd_pcm_stop_xrun(substream); + spin_lock(&spdifrx->irq_lock); + if (err_xrun && spdifrx->substream) + snd_pcm_stop_xrun(spdifrx->substream); + spin_unlock(&spdifrx->irq_lock); return IRQ_HANDLED; } @@ -730,9 +736,12 @@ static int stm32_spdifrx_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; int ret; + spin_lock_irqsave(&spdifrx->irq_lock, flags); spdifrx->substream = substream; + spin_unlock_irqrestore(&spdifrx->irq_lock, flags); ret = clk_prepare_enable(spdifrx->kclk); if (ret) @@ -804,8 +813,12 @@ static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; + spin_lock_irqsave(&spdifrx->irq_lock, flags); spdifrx->substream = NULL; + spin_unlock_irqrestore(&spdifrx->irq_lock, flags); + clk_disable_unprepare(spdifrx->kclk); } @@ -910,6 +923,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) spdifrx->pdev = pdev; init_completion(&spdifrx->cs_completion); spin_lock_init(&spdifrx->lock); + spin_lock_init(&spdifrx->irq_lock); platform_set_drvdata(pdev, spdifrx); -- GitLab From a5eedf4e6bba2d4f87af4bebb0c74be90f82b54e Mon Sep 17 00:00:00 2001 From: Swapna Manupati Date: Thu, 26 Dec 2019 17:42:11 +0530 Subject: [PATCH 0167/1055] gpio: zynq: Fix for bug in zynq_gpio_restore_context API commit 36f2e7207f21a83ca0054116191f119ac64583ab upstream. This patch writes the inverse value of Interrupt Mask Status register into the Interrupt Enable register in zynq_gpio_restore_context API to fix the bug. Fixes: e11de4de28c0 ("gpio: zynq: Add support for suspend resume") Signed-off-by: Swapna Manupati Signed-off-by: Michal Simek Signed-off-by: Srinivas Neeli Link: https://lore.kernel.org/r/1577362338-28744-2-git-send-email-srinivas.neeli@xilinx.com Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-zynq.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index b3cc948a2d8b..f1d7066b6637 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -639,6 +639,8 @@ static void zynq_gpio_restore_context(struct zynq_gpio *gpio) unsigned int bank_num; for (bank_num = 0; bank_num < gpio->p_data->max_bank; bank_num++) { + writel_relaxed(ZYNQ_GPIO_IXR_DISABLE_ALL, gpio->base_addr + + ZYNQ_GPIO_INTDIS_OFFSET(bank_num)); writel_relaxed(gpio->context.datalsw[bank_num], gpio->base_addr + ZYNQ_GPIO_DATA_LSW_OFFSET(bank_num)); @@ -648,9 +650,6 @@ static void zynq_gpio_restore_context(struct zynq_gpio *gpio) writel_relaxed(gpio->context.dirm[bank_num], gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); - writel_relaxed(gpio->context.int_en[bank_num], - gpio->base_addr + - ZYNQ_GPIO_INTEN_OFFSET(bank_num)); writel_relaxed(gpio->context.int_type[bank_num], gpio->base_addr + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); @@ -660,6 +659,9 @@ static void zynq_gpio_restore_context(struct zynq_gpio *gpio) writel_relaxed(gpio->context.int_any[bank_num], gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); + writel_relaxed(~(gpio->context.int_en[bank_num]), + gpio->base_addr + + ZYNQ_GPIO_INTEN_OFFSET(bank_num)); } } -- GitLab From 1ef9c81097d0aef4ffc45aa76b9a9f25a10609a3 Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Tue, 31 Dec 2019 13:24:19 -0700 Subject: [PATCH 0168/1055] iommu: Remove device link to group on failure commit 7d4e6ccd1fb09dbfbc49746ca82bd5c25ad4bfe4 upstream. This adds the missing teardown step that removes the device link from the group when the device addition fails. Signed-off-by: Jon Derrick Fixes: 797a8b4d768c5 ("iommu: Handle default domain attach failure") Reviewed-by: Lu Baolu Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/iommu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 1620a6f49989..4b761678a18b 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -613,6 +613,7 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev) mutex_unlock(&group->mutex); dev->iommu_group = NULL; kobject_put(group->devices_kobj); + sysfs_remove_link(group->devices_kobj, device->name); err_free_name: kfree(device->name); err_remove_link: -- GitLab From 5371360dd2a8b29593bd8bdd6aec5847f094c075 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 27 Nov 2019 10:59:19 +0100 Subject: [PATCH 0169/1055] gpio: Fix error message on out-of-range GPIO in lookup table commit d935bd50dd14a7714cbdba9a76435dbb56edb1ae upstream. When a GPIO offset in a lookup table is out-of-range, the printed error message (1) does not include the actual out-of-range value, and (2) contains an off-by-one error in the upper bound. Avoid user confusion by also printing the actual GPIO offset, and correcting the upper bound of the range. While at it, use "%u" for unsigned int. Sample impact: -requested GPIO 0 is out of range [0..32] for chip e6052000.gpio +requested GPIO 0 (45) is out of range [0..31] for chip e6052000.gpio Fixes: 2a3cf6a3599e9015 ("gpiolib: return -ENOENT if no GPIO mapping exists") Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20191127095919.4214-1-geert+renesas@glider.be Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpiolib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2b75aab8b3a0..f0777a7a4305 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3167,8 +3167,9 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, if (chip->ngpio <= p->chip_hwnum) { dev_err(dev, - "requested GPIO %d is out of range [0..%d] for chip %s\n", - idx, chip->ngpio, chip->label); + "requested GPIO %u (%u) is out of range [0..%u] for chip %s\n", + idx, p->chip_hwnum, chip->ngpio - 1, + chip->label); return ERR_PTR(-EINVAL); } -- GitLab From 8496401c9de59ad878ce13a05a717c62c41b4795 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Sun, 22 Dec 2019 11:27:08 +0000 Subject: [PATCH 0170/1055] hsr: reset network header when supervision frame is created commit 3ed0a1d563903bdb4b4c36c58c4d9c1bcb23a6e6 upstream. The supervision frame is L2 frame. When supervision frame is created, hsr module doesn't set network header. If tap routine is enabled, dev_queue_xmit_nit() is called and it checks network_header. If network_header pointer wasn't set(or invalid), it resets network_header and warns. In order to avoid unnecessary warning message, resetting network_header is needed. Test commands: ip netns add nst ip link add veth0 type veth peer name veth1 ip link add veth2 type veth peer name veth3 ip link set veth1 netns nst ip link set veth3 netns nst ip link set veth0 up ip link set veth2 up ip link add hsr0 type hsr slave1 veth0 slave2 veth2 ip a a 192.168.100.1/24 dev hsr0 ip link set hsr0 up ip netns exec nst ip link set veth1 up ip netns exec nst ip link set veth3 up ip netns exec nst ip link add hsr1 type hsr slave1 veth1 slave2 veth3 ip netns exec nst ip a a 192.168.100.2/24 dev hsr1 ip netns exec nst ip link set hsr1 up tcpdump -nei veth0 Splat looks like: [ 175.852292][ C3] protocol 88fb is buggy, dev veth0 Fixes: f421436a591d ("net/hsr: Add support for the High-availability Seamless Redundancy protocol (HSRv0)") Signed-off-by: Taehee Yoo Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/hsr/hsr_device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index cfe20f15f618..c962c406d7b1 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c @@ -281,6 +281,8 @@ static void send_hsr_supervision_frame(struct hsr_port *master, skb->dev->dev_addr, skb->len) <= 0) goto out; skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); if (hsrVer > 0) { hsr_tag = skb_put(skb, sizeof(struct hsr_tag)); -- GitLab From 7ffb1ac23fcc687db2624e09bde36a8deced6ac0 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 17 Dec 2019 20:04:51 -0700 Subject: [PATCH 0171/1055] cifs: Adjust indentation in smb2_open_file commit 7935799e041ae10d380d04ea23868240f082bd11 upstream. Clang warns: ../fs/cifs/smb2file.c:70:3: warning: misleading indentation; statement is not part of the previous 'if' [-Wmisleading-indentation] if (oparms->tcon->use_resilient) { ^ ../fs/cifs/smb2file.c:66:2: note: previous statement is here if (rc) ^ 1 warning generated. This warning occurs because there is a space after the tab on this line. Remove it so that the indentation is consistent with the Linux kernel coding style and clang no longer warns. Fixes: 592fafe644bf ("Add resilienthandles mount parm") Link: https://github.com/ClangBuiltLinux/linux/issues/826 Signed-off-by: Nathan Chancellor Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/smb2file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index 2c809233084b..e270812927cf 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c @@ -69,7 +69,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, goto out; - if (oparms->tcon->use_resilient) { + if (oparms->tcon->use_resilient) { nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */ nr_ioctl_req.Reserved = 0; rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid, -- GitLab From f04fb2025339f90d65c3473250c4ee8b6f482a60 Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Wed, 11 Sep 2019 11:45:15 -0500 Subject: [PATCH 0172/1055] btrfs: simplify inode locking for RWF_NOWAIT commit 9cf35f673583ccc9f3e2507498b3079d56614ad3 upstream. This is similar to 942491c9e6d6 ("xfs: fix AIM7 regression"). Apparently our current rwsem code doesn't like doing the trylock, then lock for real scheme. This causes extra contention on the lock and can be measured eg. by AIM7 benchmark. So change our read/write methods to just do the trylock for the RWF_NOWAIT case. Fixes: edf064e7c6fe ("btrfs: nowait aio support") Signed-off-by: Goldwyn Rodrigues Reviewed-by: David Sterba [ update changelog ] Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/file.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index bf654d48eb46..97be32da857a 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1890,9 +1890,10 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, (iocb->ki_flags & IOCB_NOWAIT)) return -EOPNOTSUPP; - if (!inode_trylock(inode)) { - if (iocb->ki_flags & IOCB_NOWAIT) + if (iocb->ki_flags & IOCB_NOWAIT) { + if (!inode_trylock(inode)) return -EAGAIN; + } else { inode_lock(inode); } -- GitLab From 4dbdf3e7c22c801e5d5b3bf489a091c43e78d37f Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 29 Oct 2019 07:57:21 +0200 Subject: [PATCH 0173/1055] RDMA/mlx5: Return proper error value commit 546d30099ed204792083f043cd7e016de86016a3 upstream. Returned value from mlx5_mr_cache_alloc() is checked to be error or real pointer. Return proper error code instead of NULL which is not checked later. Fixes: 81713d3788d2 ("IB/mlx5: Add implicit MR support") Link: https://lore.kernel.org/r/20191029055721.7192-1-leon@kernel.org Signed-off-by: Leon Romanovsky Reviewed-by: Jason Gunthorpe Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index cfddca850cb4..fb45bfa4f845 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -460,7 +460,7 @@ struct mlx5_ib_mr *mlx5_mr_cache_alloc(struct mlx5_ib_dev *dev, int entry) if (entry < 0 || entry >= MAX_MR_CACHE_ENTRIES) { mlx5_ib_err(dev, "cache entry %d is out of range\n", entry); - return NULL; + return ERR_PTR(-EINVAL); } ent = &cache->ent[entry]; -- GitLab From 56614548ff01c92cbae9870a462bde24dedaf194 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 5 Nov 2019 13:46:32 -0800 Subject: [PATCH 0174/1055] RDMA/srpt: Report the SCSI residual to the initiator commit e88982ad1bb12db699de96fbc07096359ef6176c upstream. The code added by this patch is similar to the code that already exists in ibmvscsis_determine_resid(). This patch has been tested by running the following command: strace sg_raw -r 1k /dev/sdb 12 00 00 00 60 00 -o inquiry.bin |& grep resid= Link: https://lore.kernel.org/r/20191105214632.183302-1-bvanassche@acm.org Fixes: a42d985bd5b2 ("ib_srpt: Initial SRP Target merge for v3.3-rc1") Signed-off-by: Bart Van Assche Acked-by: Honggang Li Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/srpt/ib_srpt.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 94161ca526fc..1446e1cc69ae 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1246,9 +1246,11 @@ static int srpt_build_cmd_rsp(struct srpt_rdma_ch *ch, struct srpt_send_ioctx *ioctx, u64 tag, int status) { + struct se_cmd *cmd = &ioctx->cmd; struct srp_rsp *srp_rsp; const u8 *sense_data; int sense_data_len, max_sense_len; + u32 resid = cmd->residual_count; /* * The lowest bit of all SAM-3 status codes is zero (see also @@ -1270,6 +1272,28 @@ static int srpt_build_cmd_rsp(struct srpt_rdma_ch *ch, srp_rsp->tag = tag; srp_rsp->status = status; + if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { + if (cmd->data_direction == DMA_TO_DEVICE) { + /* residual data from an underflow write */ + srp_rsp->flags = SRP_RSP_FLAG_DOUNDER; + srp_rsp->data_out_res_cnt = cpu_to_be32(resid); + } else if (cmd->data_direction == DMA_FROM_DEVICE) { + /* residual data from an underflow read */ + srp_rsp->flags = SRP_RSP_FLAG_DIUNDER; + srp_rsp->data_in_res_cnt = cpu_to_be32(resid); + } + } else if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { + if (cmd->data_direction == DMA_TO_DEVICE) { + /* residual data from an overflow write */ + srp_rsp->flags = SRP_RSP_FLAG_DOOVER; + srp_rsp->data_out_res_cnt = cpu_to_be32(resid); + } else if (cmd->data_direction == DMA_FROM_DEVICE) { + /* residual data from an overflow read */ + srp_rsp->flags = SRP_RSP_FLAG_DIOVER; + srp_rsp->data_in_res_cnt = cpu_to_be32(resid); + } + } + if (sense_data_len) { BUILD_BUG_ON(MIN_MAX_RSP_SIZE <= sizeof(*srp_rsp)); max_sense_len = ch->max_ti_iu_len - sizeof(*srp_rsp); -- GitLab From a97fdbf0f25c17b3c296dce6c1f2731cbdb39e7c Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 23 Apr 2018 11:41:33 +0100 Subject: [PATCH 0175/1055] arm64: add sentinel to kpti_safe_list commit 71c751f2a43fa03fae3cf5f0067ed3001a397013 upstream. We're missing a sentinel entry in kpti_safe_list. Thus is_midr_in_range_list() can walk past the end of kpti_safe_list. Depending on the contents of memory, this could erroneously match a CPU's MIDR, cause a data abort, or other bad outcomes. Add the sentinel entry to avoid this. Fixes: be5b299830c63ed7 ("arm64: capabilities: Add support for checks based on a list of MIDRs") Signed-off-by: Mark Rutland Reported-by: Jan Kiszka Tested-by: Jan Kiszka Reviewed-by: Suzuki K Poulose Cc: Catalin Marinas Cc: Suzuki K Poulose Cc: Will Deacon Signed-off-by: Will Deacon Signed-off-by: Juerg Haefliger Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpufeature.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 60066315d669..ae28979676c1 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -836,6 +836,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), MIDR_ALL_VERSIONS(MIDR_CORTEX_A72), MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), + { /* sentinel */ } }; char const *str = "kpti command line option"; bool meltdown_safe; -- GitLab From 87973b285545c45b2780f59ce4efda145b024d9b Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Wed, 25 Jul 2018 13:10:28 +0200 Subject: [PATCH 0176/1055] arm64: Check for errata before evaluating cpu features commit dc0e36581eb2da1aa3c63ceeff0f10ef1e899b2a upstream. Since commit d3aec8a28be3b8 ("arm64: capabilities: Restrict KPTI detection to boot-time CPUs") we rely on errata flags being already populated during feature enumeration. The order of errata and features was flipped as part of commit ed478b3f9e4a ("arm64: capabilities: Group handling of features and errata workarounds"). Return to the orginal order of errata and feature evaluation to ensure errata flags are present during feature evaluation. Fixes: ed478b3f9e4a ("arm64: capabilities: Group handling of features and errata workarounds") CC: Suzuki K Poulose CC: Marc Zyngier Signed-off-by: Dirk Mueller Reviewed-by: Suzuki K Poulose Signed-off-by: Will Deacon Signed-off-by: Juerg Haefliger Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpufeature.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index ae28979676c1..09c6499bc500 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1278,9 +1278,9 @@ static void __update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, static void update_cpu_capabilities(u16 scope_mask) { - __update_cpu_capabilities(arm64_features, scope_mask, "detected:"); __update_cpu_capabilities(arm64_errata, scope_mask, "enabling workaround for"); + __update_cpu_capabilities(arm64_features, scope_mask, "detected:"); } static int __enable_cpu_capability(void *arg) @@ -1335,8 +1335,8 @@ __enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps, static void __init enable_cpu_capabilities(u16 scope_mask) { - __enable_cpu_capabilities(arm64_features, scope_mask); __enable_cpu_capabilities(arm64_errata, scope_mask); + __enable_cpu_capabilities(arm64_features, scope_mask); } /* -- GitLab From e3258fc2fc74008ff4e5713c62ec1e95c79c8e77 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 8 Jan 2020 17:21:32 -0800 Subject: [PATCH 0177/1055] scsi: enclosure: Fix stale device oops with hot replug commit 529244bd1afc102ab164429d338d310d5d65e60d upstream. Doing an add/remove/add on a SCSI device in an enclosure leads to an oops caused by poisoned values in the enclosure device list pointers. The reason is because we are keeping the enclosure device across the enclosed device add/remove/add but the current code is doing a device_add/device_del/device_add on it. This is the wrong thing to do in sysfs, so fix it by not doing a device_del on the enclosure device simply because of a hot remove of the drive in the slot. [mkp: added missing email addresses] Fixes: 43d8eb9cfd0a ("[SCSI] ses: add support for enclosure component hot removal") Link: https://lore.kernel.org/r/1578532892.3852.10.camel@HansenPartnership.com Signed-off-by: James Bottomley Reported-by: Luo Jiaxing Tested-by: John Garry Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/misc/enclosure.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index eb29113e0bac..b11737f7bdca 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -419,10 +419,9 @@ int enclosure_remove_device(struct enclosure_device *edev, struct device *dev) cdev = &edev->component[i]; if (cdev->dev == dev) { enclosure_remove_links(cdev); - device_del(&cdev->cdev); put_device(dev); cdev->dev = NULL; - return device_add(&cdev->cdev); + return 0; } } return -ENODEV; -- GitLab From c301a4e96501e6f8333145efbda2aeb1ec0ba4fe Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Thu, 9 Jan 2020 09:12:24 +0800 Subject: [PATCH 0178/1055] scsi: sd: Clear sdkp->protection_type if disk is reformatted without PI commit 465f4edaecc6c37f81349233e84d46246bcac11a upstream. If an attached disk with protection information enabled is reformatted to Type 0 the revalidation code does not clear the original protection type and subsequent accesses will keep setting RDPROTECT/WRPROTECT. Set the protection type to 0 if the disk reports PROT_EN=0 in READ CAPACITY(16). [mkp: commit desc] Fixes: fe542396da73 ("[SCSI] sd: Ensure we correctly disable devices with unknown protection type") Link: https://lore.kernel.org/r/1578532344-101668-1-git-send-email-chenxiang66@hisilicon.com Signed-off-by: Xiang Chen Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 35cea5827a7a..dd7ca76c000a 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2206,8 +2206,10 @@ static int sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer u8 type; int ret = 0; - if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) + if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) { + sdkp->protection_type = 0; return ret; + } type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ -- GitLab From c2d4a986f979d4004be7f5a3460bc0f0b8f41c02 Mon Sep 17 00:00:00 2001 From: Jian-Hong Pan Date: Mon, 30 Dec 2019 16:30:45 +0800 Subject: [PATCH 0179/1055] platform/x86: asus-wmi: Fix keyboard brightness cannot be set to 0 commit 176a7fca81c5090a7240664e3002c106d296bf31 upstream. Some of ASUS laptops like UX431FL keyboard backlight cannot be set to brightness 0. According to ASUS' information, the brightness should be 0x80 ~ 0x83. This patch fixes it by following the logic. Fixes: e9809c0b9670 ("asus-wmi: add keyboard backlight support") Signed-off-by: Jian-Hong Pan Reviewed-by: Daniel Drake Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/asus-wmi.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 1c1999600717..af26ca49996d 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -457,13 +457,7 @@ static void kbd_led_update(struct work_struct *work) asus = container_of(work, struct asus_wmi, kbd_led_work); - /* - * bits 0-2: level - * bit 7: light on/off - */ - if (asus->kbd_led_wk > 0) - ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F); - + ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F); asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL); } -- GitLab From 760e1a2e4d220c7c1992bbb197790cedf0c86f3d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 3 Jan 2020 11:52:17 -0500 Subject: [PATCH 0180/1055] xprtrdma: Fix completion wait during device removal commit 13cb886c591f341a8759f175292ddf978ef903a1 upstream. I've found that on occasion, "rmmod " will hang while if an NFS is under load. Ensure that ri_remove_done is initialized only just before the transport is woken up to force a close. This avoids the completion possibly getting initialized again while the CM event handler is waiting for a wake-up. Fixes: bebd031866ca ("xprtrdma: Support unplugging an HCA from under an NFS mount") Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtrdma/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 2aaf46599126..c5e991d14888 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -264,6 +264,7 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) ia->ri_device->name, sap, rpc_get_port(sap)); #endif + init_completion(&ia->ri_remove_done); set_bit(RPCRDMA_IAF_REMOVING, &ia->ri_flags); ep->rep_connected = -ENODEV; xprt_force_disconnect(&xprt->rx_xprt); @@ -319,7 +320,6 @@ rpcrdma_create_id(struct rpcrdma_xprt *xprt, int rc; init_completion(&ia->ri_done); - init_completion(&ia->ri_remove_done); id = rdma_create_id(&init_net, rpcrdma_conn_upcall, xprt, RDMA_PS_TCP, IB_QPT_RC); -- GitLab From 34ed0dfdd8f561a05bbc62aae31ac29cc9cb8d07 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 13 Nov 2019 09:39:36 +0100 Subject: [PATCH 0181/1055] NFSv4.x: Drop the slot if nfs4_delegreturn_prepare waits for layoutreturn commit 5326de9e94bedcf7366e7e7625d4deb8c1f1ca8a upstream. If nfs4_delegreturn_prepare needs to wait for a layoutreturn to complete then make sure we drop the sequence slot if we hold it. Fixes: 1c5bd76d17cc ("pNFS: Enable layoutreturn operation for return-on-close") Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index f1526f65cc58..3dd403943b07 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5797,8 +5797,10 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) d_data = (struct nfs4_delegreturndata *)data; - if (!d_data->lr.roc && nfs4_wait_on_layoutreturn(d_data->inode, task)) + if (!d_data->lr.roc && nfs4_wait_on_layoutreturn(d_data->inode, task)) { + nfs4_sequence_done(task, &d_data->res.seq_res); return; + } nfs4_setup_sequence(d_data->res.server->nfs_client, &d_data->args.seq_args, -- GitLab From 9d9aee7be0dbb89d6ce4e64c996110a050727d54 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Fri, 1 Nov 2019 11:35:03 +0200 Subject: [PATCH 0182/1055] iio: imu: adis16480: assign bias value only if operation succeeded commit 9b742763d9d4195e823ae6ece760c9ed0500c1dc upstream. This was found only after the whole thing with the inline functions, but the compiler actually found something. The value of the `bias` (in adis16480_get_calibbias()) should only be set if the read operation was successful. No actual known problem occurs as users of this function all ultimately check the return value. Hence probably not stable material. Fixes: 2f3abe6cbb6c9 ("iio:imu: Add support for the ADIS16480 and similar IMUs") Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/imu/adis16480.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index c950aa10d0ae..5abe095901c8 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -372,12 +372,14 @@ static int adis16480_get_calibbias(struct iio_dev *indio_dev, case IIO_MAGN: case IIO_PRESSURE: ret = adis_read_reg_16(&st->adis, reg, &val16); - *bias = sign_extend32(val16, 15); + if (ret == 0) + *bias = sign_extend32(val16, 15); break; case IIO_ANGL_VEL: case IIO_ACCEL: ret = adis_read_reg_32(&st->adis, reg, &val32); - *bias = sign_extend32(val32, 31); + if (ret == 0) + *bias = sign_extend32(val32, 31); break; default: ret = -EINVAL; -- GitLab From 7e1a1d6e4140a3942882f245e6fe22c13ebee6ac Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 8 Oct 2019 03:57:34 +0300 Subject: [PATCH 0183/1055] mei: fix modalias documentation commit 73668309215285366c433489de70d31362987be9 upstream. mei client bus added the client protocol version to the device alias, but ABI documentation was not updated. Fixes: b26864cad1c9 (mei: bus: add client protocol version to the device alias) Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20191008005735.12707-1-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-mei | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-bus-mei b/Documentation/ABI/testing/sysfs-bus-mei index 6bd45346ac7e..3f8701e8fa24 100644 --- a/Documentation/ABI/testing/sysfs-bus-mei +++ b/Documentation/ABI/testing/sysfs-bus-mei @@ -4,7 +4,7 @@ KernelVersion: 3.10 Contact: Samuel Ortiz linux-mei@linux.intel.com Description: Stores the same MODALIAS value emitted by uevent - Format: mei::: + Format: mei::: What: /sys/bus/mei/devices/.../name Date: May 2015 -- GitLab From d0b83984688f218f4894652d71ec1e4c633f0d18 Mon Sep 17 00:00:00 2001 From: Marian Mihailescu Date: Tue, 29 Oct 2019 11:20:25 +1030 Subject: [PATCH 0184/1055] clk: samsung: exynos5420: Preserve CPU clocks configuration during suspend/resume commit e21be0d1d7bd7f78a77613f6bcb6965e72b22fc1 upstream. Save and restore top PLL related configuration registers for big (APLL) and LITTLE (KPLL) cores during suspend/resume cycle. So far, CPU clocks were reset to default values after suspend/resume cycle and performance after system resume was affected when performance governor has been selected. Fixes: 773424326b51 ("clk: samsung: exynos5420: add more registers to restore list") Signed-off-by: Marian Mihailescu Signed-off-by: Sylwester Nawrocki Signed-off-by: Greg Kroah-Hartman --- drivers/clk/samsung/clk-exynos5420.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 47a14f93f869..2f54df5bef8e 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -170,6 +170,8 @@ static const unsigned long exynos5x_clk_regs[] __initconst = { GATE_BUS_CPU, GATE_SCLK_CPU, CLKOUT_CMU_CPU, + APLL_CON0, + KPLL_CON0, CPLL_CON0, DPLL_CON0, EPLL_CON0, -- GitLab From 736af028aee8f168c5ac1e87b51611286a99fc19 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 20 Sep 2019 14:20:30 +0200 Subject: [PATCH 0185/1055] pinctl: ti: iodelay: fix error checking on pinctrl_count_index_with_args call commit 5ff8aca906f3a7a7db79fad92f2a4401107ef50d upstream. The call to pinctrl_count_index_with_args checks for a -EINVAL return however this function calls pinctrl_get_list_and_count and this can return -ENOENT. Rather than check for a specific error, fix this by checking for any error return to catch the -ENOENT case. Addresses-Coverity: ("Improper use of negative") Fixes: 003910ebc83b ("pinctrl: Introduce TI IOdelay configuration driver") Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20190920122030.14340-1-colin.king@canonical.com Acked-by: Tony Lindgren Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/ti/pinctrl-ti-iodelay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c index 5c1b6325d80d..8ac1f1ce4442 100644 --- a/drivers/pinctrl/ti/pinctrl-ti-iodelay.c +++ b/drivers/pinctrl/ti/pinctrl-ti-iodelay.c @@ -496,7 +496,7 @@ static int ti_iodelay_dt_node_to_map(struct pinctrl_dev *pctldev, return -EINVAL; rows = pinctrl_count_index_with_args(np, name); - if (rows == -EINVAL) + if (rows < 0) return rows; *map = devm_kzalloc(iod->dev, sizeof(**map), GFP_KERNEL); -- GitLab From 6cce9e0baee21f4ac76828ae75d7783c1bdca726 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 20 Nov 2019 15:37:39 +0200 Subject: [PATCH 0186/1055] pinctrl: lewisburg: Update pin list according to v1.1v6 commit e66ff71fd0dba36a53f91f39e4da6c7b84764f2e upstream. Version 1.1v6 of pin list has some changes in pin names for Intel Lewisburg. Update the driver accordingly. Note, it reveals the bug in the driver that misses two pins in GPP_L and has rather two extra ones. That's why the ordering of some groups is changed. Fixes: e480b745386e ("pinctrl: intel: Add Intel Lewisburg GPIO support") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20191120133739.54332-1-andriy.shevchenko@linux.intel.com Acked-by: Mika Westerberg Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/intel/pinctrl-lewisburg.c | 171 +++++++++++----------- 1 file changed, 86 insertions(+), 85 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-lewisburg.c b/drivers/pinctrl/intel/pinctrl-lewisburg.c index 14d56ea6cfdc..c2164db14e9c 100644 --- a/drivers/pinctrl/intel/pinctrl-lewisburg.c +++ b/drivers/pinctrl/intel/pinctrl-lewisburg.c @@ -34,6 +34,7 @@ .npins = ((e) - (s) + 1), \ } +/* Lewisburg */ static const struct pinctrl_pin_desc lbg_pins[] = { /* GPP_A */ PINCTRL_PIN(0, "RCINB"), @@ -73,7 +74,7 @@ static const struct pinctrl_pin_desc lbg_pins[] = { PINCTRL_PIN(33, "SRCCLKREQB_4"), PINCTRL_PIN(34, "SRCCLKREQB_5"), PINCTRL_PIN(35, "GPP_B_11"), - PINCTRL_PIN(36, "GLB_RST_WARN_N"), + PINCTRL_PIN(36, "SLP_S0B"), PINCTRL_PIN(37, "PLTRSTB"), PINCTRL_PIN(38, "SPKR"), PINCTRL_PIN(39, "GPP_B_15"), @@ -186,96 +187,96 @@ static const struct pinctrl_pin_desc lbg_pins[] = { PINCTRL_PIN(141, "GBE_PCI_DIS"), PINCTRL_PIN(142, "GBE_LAN_DIS"), PINCTRL_PIN(143, "GPP_I_10"), - PINCTRL_PIN(144, "GPIO_RCOMP_3P3"), /* GPP_J */ - PINCTRL_PIN(145, "GBE_LED_0_0"), - PINCTRL_PIN(146, "GBE_LED_0_1"), - PINCTRL_PIN(147, "GBE_LED_1_0"), - PINCTRL_PIN(148, "GBE_LED_1_1"), - PINCTRL_PIN(149, "GBE_LED_2_0"), - PINCTRL_PIN(150, "GBE_LED_2_1"), - PINCTRL_PIN(151, "GBE_LED_3_0"), - PINCTRL_PIN(152, "GBE_LED_3_1"), - PINCTRL_PIN(153, "GBE_SCL_0"), - PINCTRL_PIN(154, "GBE_SDA_0"), - PINCTRL_PIN(155, "GBE_SCL_1"), - PINCTRL_PIN(156, "GBE_SDA_1"), - PINCTRL_PIN(157, "GBE_SCL_2"), - PINCTRL_PIN(158, "GBE_SDA_2"), - PINCTRL_PIN(159, "GBE_SCL_3"), - PINCTRL_PIN(160, "GBE_SDA_3"), - PINCTRL_PIN(161, "GBE_SDP_0_0"), - PINCTRL_PIN(162, "GBE_SDP_0_1"), - PINCTRL_PIN(163, "GBE_SDP_1_0"), - PINCTRL_PIN(164, "GBE_SDP_1_1"), - PINCTRL_PIN(165, "GBE_SDP_2_0"), - PINCTRL_PIN(166, "GBE_SDP_2_1"), - PINCTRL_PIN(167, "GBE_SDP_3_0"), - PINCTRL_PIN(168, "GBE_SDP_3_1"), + PINCTRL_PIN(144, "GBE_LED_0_0"), + PINCTRL_PIN(145, "GBE_LED_0_1"), + PINCTRL_PIN(146, "GBE_LED_1_0"), + PINCTRL_PIN(147, "GBE_LED_1_1"), + PINCTRL_PIN(148, "GBE_LED_2_0"), + PINCTRL_PIN(149, "GBE_LED_2_1"), + PINCTRL_PIN(150, "GBE_LED_3_0"), + PINCTRL_PIN(151, "GBE_LED_3_1"), + PINCTRL_PIN(152, "GBE_SCL_0"), + PINCTRL_PIN(153, "GBE_SDA_0"), + PINCTRL_PIN(154, "GBE_SCL_1"), + PINCTRL_PIN(155, "GBE_SDA_1"), + PINCTRL_PIN(156, "GBE_SCL_2"), + PINCTRL_PIN(157, "GBE_SDA_2"), + PINCTRL_PIN(158, "GBE_SCL_3"), + PINCTRL_PIN(159, "GBE_SDA_3"), + PINCTRL_PIN(160, "GBE_SDP_0_0"), + PINCTRL_PIN(161, "GBE_SDP_0_1"), + PINCTRL_PIN(162, "GBE_SDP_1_0"), + PINCTRL_PIN(163, "GBE_SDP_1_1"), + PINCTRL_PIN(164, "GBE_SDP_2_0"), + PINCTRL_PIN(165, "GBE_SDP_2_1"), + PINCTRL_PIN(166, "GBE_SDP_3_0"), + PINCTRL_PIN(167, "GBE_SDP_3_1"), /* GPP_K */ - PINCTRL_PIN(169, "GBE_RMIICLK"), - PINCTRL_PIN(170, "GBE_RMII_TXD_0"), - PINCTRL_PIN(171, "GBE_RMII_TXD_1"), + PINCTRL_PIN(168, "GBE_RMIICLK"), + PINCTRL_PIN(169, "GBE_RMII_RXD_0"), + PINCTRL_PIN(170, "GBE_RMII_RXD_1"), + PINCTRL_PIN(171, "GBE_RMII_CRS_DV"), PINCTRL_PIN(172, "GBE_RMII_TX_EN"), - PINCTRL_PIN(173, "GBE_RMII_CRS_DV"), - PINCTRL_PIN(174, "GBE_RMII_RXD_0"), - PINCTRL_PIN(175, "GBE_RMII_RXD_1"), - PINCTRL_PIN(176, "GBE_RMII_RX_ER"), - PINCTRL_PIN(177, "GBE_RMII_ARBIN"), - PINCTRL_PIN(178, "GBE_RMII_ARB_OUT"), - PINCTRL_PIN(179, "PE_RST_N"), - PINCTRL_PIN(180, "GPIO_RCOMP_1P8_3P3"), + PINCTRL_PIN(173, "GBE_RMII_TXD_0"), + PINCTRL_PIN(174, "GBE_RMII_TXD_1"), + PINCTRL_PIN(175, "GBE_RMII_RX_ER"), + PINCTRL_PIN(176, "GBE_RMII_ARBIN"), + PINCTRL_PIN(177, "GBE_RMII_ARB_OUT"), + PINCTRL_PIN(178, "PE_RST_N"), /* GPP_G */ - PINCTRL_PIN(181, "FAN_TACH_0"), - PINCTRL_PIN(182, "FAN_TACH_1"), - PINCTRL_PIN(183, "FAN_TACH_2"), - PINCTRL_PIN(184, "FAN_TACH_3"), - PINCTRL_PIN(185, "FAN_TACH_4"), - PINCTRL_PIN(186, "FAN_TACH_5"), - PINCTRL_PIN(187, "FAN_TACH_6"), - PINCTRL_PIN(188, "FAN_TACH_7"), - PINCTRL_PIN(189, "FAN_PWM_0"), - PINCTRL_PIN(190, "FAN_PWM_1"), - PINCTRL_PIN(191, "FAN_PWM_2"), - PINCTRL_PIN(192, "FAN_PWM_3"), - PINCTRL_PIN(193, "GSXDOUT"), - PINCTRL_PIN(194, "GSXSLOAD"), - PINCTRL_PIN(195, "GSXDIN"), - PINCTRL_PIN(196, "GSXSRESETB"), - PINCTRL_PIN(197, "GSXCLK"), - PINCTRL_PIN(198, "ADR_COMPLETE"), - PINCTRL_PIN(199, "NMIB"), - PINCTRL_PIN(200, "SMIB"), - PINCTRL_PIN(201, "SSATA_DEVSLP_0"), - PINCTRL_PIN(202, "SSATA_DEVSLP_1"), - PINCTRL_PIN(203, "SSATA_DEVSLP_2"), - PINCTRL_PIN(204, "SSATAXPCIE0_SSATAGP0"), + PINCTRL_PIN(179, "FAN_TACH_0"), + PINCTRL_PIN(180, "FAN_TACH_1"), + PINCTRL_PIN(181, "FAN_TACH_2"), + PINCTRL_PIN(182, "FAN_TACH_3"), + PINCTRL_PIN(183, "FAN_TACH_4"), + PINCTRL_PIN(184, "FAN_TACH_5"), + PINCTRL_PIN(185, "FAN_TACH_6"), + PINCTRL_PIN(186, "FAN_TACH_7"), + PINCTRL_PIN(187, "FAN_PWM_0"), + PINCTRL_PIN(188, "FAN_PWM_1"), + PINCTRL_PIN(189, "FAN_PWM_2"), + PINCTRL_PIN(190, "FAN_PWM_3"), + PINCTRL_PIN(191, "GSXDOUT"), + PINCTRL_PIN(192, "GSXSLOAD"), + PINCTRL_PIN(193, "GSXDIN"), + PINCTRL_PIN(194, "GSXSRESETB"), + PINCTRL_PIN(195, "GSXCLK"), + PINCTRL_PIN(196, "ADR_COMPLETE"), + PINCTRL_PIN(197, "NMIB"), + PINCTRL_PIN(198, "SMIB"), + PINCTRL_PIN(199, "SSATA_DEVSLP_0"), + PINCTRL_PIN(200, "SSATA_DEVSLP_1"), + PINCTRL_PIN(201, "SSATA_DEVSLP_2"), + PINCTRL_PIN(202, "SSATAXPCIE0_SSATAGP0"), /* GPP_H */ - PINCTRL_PIN(205, "SRCCLKREQB_6"), - PINCTRL_PIN(206, "SRCCLKREQB_7"), - PINCTRL_PIN(207, "SRCCLKREQB_8"), - PINCTRL_PIN(208, "SRCCLKREQB_9"), - PINCTRL_PIN(209, "SRCCLKREQB_10"), - PINCTRL_PIN(210, "SRCCLKREQB_11"), - PINCTRL_PIN(211, "SRCCLKREQB_12"), - PINCTRL_PIN(212, "SRCCLKREQB_13"), - PINCTRL_PIN(213, "SRCCLKREQB_14"), - PINCTRL_PIN(214, "SRCCLKREQB_15"), - PINCTRL_PIN(215, "SML2CLK"), - PINCTRL_PIN(216, "SML2DATA"), - PINCTRL_PIN(217, "SML2ALERTB"), - PINCTRL_PIN(218, "SML3CLK"), - PINCTRL_PIN(219, "SML3DATA"), - PINCTRL_PIN(220, "SML3ALERTB"), - PINCTRL_PIN(221, "SML4CLK"), - PINCTRL_PIN(222, "SML4DATA"), - PINCTRL_PIN(223, "SML4ALERTB"), - PINCTRL_PIN(224, "SSATAXPCIE1_SSATAGP1"), - PINCTRL_PIN(225, "SSATAXPCIE2_SSATAGP2"), - PINCTRL_PIN(226, "SSATAXPCIE3_SSATAGP3"), - PINCTRL_PIN(227, "SSATAXPCIE4_SSATAGP4"), - PINCTRL_PIN(228, "SSATAXPCIE5_SSATAGP5"), + PINCTRL_PIN(203, "SRCCLKREQB_6"), + PINCTRL_PIN(204, "SRCCLKREQB_7"), + PINCTRL_PIN(205, "SRCCLKREQB_8"), + PINCTRL_PIN(206, "SRCCLKREQB_9"), + PINCTRL_PIN(207, "SRCCLKREQB_10"), + PINCTRL_PIN(208, "SRCCLKREQB_11"), + PINCTRL_PIN(209, "SRCCLKREQB_12"), + PINCTRL_PIN(210, "SRCCLKREQB_13"), + PINCTRL_PIN(211, "SRCCLKREQB_14"), + PINCTRL_PIN(212, "SRCCLKREQB_15"), + PINCTRL_PIN(213, "SML2CLK"), + PINCTRL_PIN(214, "SML2DATA"), + PINCTRL_PIN(215, "SML2ALERTB"), + PINCTRL_PIN(216, "SML3CLK"), + PINCTRL_PIN(217, "SML3DATA"), + PINCTRL_PIN(218, "SML3ALERTB"), + PINCTRL_PIN(219, "SML4CLK"), + PINCTRL_PIN(220, "SML4DATA"), + PINCTRL_PIN(221, "SML4ALERTB"), + PINCTRL_PIN(222, "SSATAXPCIE1_SSATAGP1"), + PINCTRL_PIN(223, "SSATAXPCIE2_SSATAGP2"), + PINCTRL_PIN(224, "SSATAXPCIE3_SSATAGP3"), + PINCTRL_PIN(225, "SSATAXPCIE4_SSATAGP4"), + PINCTRL_PIN(226, "SSATAXPCIE5_SSATAGP5"), /* GPP_L */ + PINCTRL_PIN(227, "GPP_L_0"), + PINCTRL_PIN(228, "EC_CSME_INTR_OUT"), PINCTRL_PIN(229, "VISA2CH0_D0"), PINCTRL_PIN(230, "VISA2CH0_D1"), PINCTRL_PIN(231, "VISA2CH0_D2"), -- GitLab From e35d296079d581036d929a09fc2ee29246207d3b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 15 Mar 2019 13:46:11 +0100 Subject: [PATCH 0187/1055] scsi: sd: enable compat ioctls for sed-opal commit 142b2ac82e31c174936c5719fa12ae28f51a55b7 upstream. The sed_ioctl() function is written to be compatible between 32-bit and 64-bit processes, however compat mode is only wired up for nvme, not for sd. Add the missing call to sed_ioctl() in sd_compat_ioctl(). Fixes: d80210f25ff0 ("sd: add support for TCG OPAL self encrypting disks") Cc: linux-scsi@vger.kernel.org Cc: "James E.J. Bottomley" Cc: "Martin K. Petersen" Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sd.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index dd7ca76c000a..2955b856e9ec 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1697,20 +1697,30 @@ static void sd_rescan(struct device *dev) static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device; + struct gendisk *disk = bdev->bd_disk; + struct scsi_disk *sdkp = scsi_disk(disk); + struct scsi_device *sdev = sdkp->device; + void __user *p = compat_ptr(arg); int error; + error = scsi_verify_blk_ioctl(bdev, cmd); + if (error < 0) + return error; + error = scsi_ioctl_block_when_processing_errors(sdev, cmd, (mode & FMODE_NDELAY) != 0); if (error) return error; + + if (is_sed_ioctl(cmd)) + return sed_ioctl(sdkp->opal_dev, cmd, p); /* * Let the static ioctl translation table take care of it. */ if (!sdev->host->hostt->compat_ioctl) return -ENOIOCTLCMD; - return sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); + return sdev->host->hostt->compat_ioctl(sdev, cmd, p); } #endif -- GitLab From d76a73388658d34ffa22a040d47be6e35f7b70ff Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Wed, 12 Dec 2018 18:13:26 +0100 Subject: [PATCH 0188/1055] arm64: dts: apq8096-db820c: Increase load on l21 for SDCARD commit e38161bd325ea541ef2f258d8e28281077dde524 upstream. In the same way as for msm8974-hammerhead, l21 load, used for SDCARD VMMC, needs to be increased in order to prevent any voltage drop issues (due to limited current) happening with some SDCARDS or during specific operations (e.g. write). Reviewed-by: Bjorn Andersson Fixes: 660a9763c6a9 (arm64: dts: qcom: db820c: Add pm8994 regulator node) Signed-off-by: Loic Poulain Signed-off-by: Bjorn Andersson Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi index 789f3e87321e..7a510505e0c2 100644 --- a/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi @@ -262,6 +262,8 @@ l21 { regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; + regulator-allow-set-load; + regulator-system-load = <200000>; }; l22 { regulator-min-microvolt = <3300000>; -- GitLab From 6b24f8fa8f265948c2e256d7f30315854fe8735e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 3 Jun 2019 22:03:44 +0200 Subject: [PATCH 0189/1055] af_unix: add compat_ioctl support commit 5f6beb9e0f633f3cc845cdd67973c506372931b4 upstream. The af_unix protocol family has a custom ioctl command (inexplicibly based on SIOCPROTOPRIVATE), but never had a compat_ioctl handler for 32-bit applications. Since all commands are compatible here, add a trivial wrapper that performs the compat_ptr() conversion for SIOCOUTQ/SIOCINQ. SIOCUNIXFILE does not use the argument, but it doesn't hurt to also use compat_ptr() here. Fixes: ba94f3088b79 ("unix: add ioctl to open a unix socket file with O_PATH") Cc: netdev@vger.kernel.org Cc: "David S. Miller" Cc: Eric Dumazet Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- net/unix/af_unix.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 99f581a61cfa..091e93798eac 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -644,6 +644,9 @@ static unsigned int unix_poll(struct file *, struct socket *, poll_table *); static unsigned int unix_dgram_poll(struct file *, struct socket *, poll_table *); static int unix_ioctl(struct socket *, unsigned int, unsigned long); +#ifdef CONFIG_COMPAT +static int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); +#endif static int unix_shutdown(struct socket *, int); static int unix_stream_sendmsg(struct socket *, struct msghdr *, size_t); static int unix_stream_recvmsg(struct socket *, struct msghdr *, size_t, int); @@ -685,6 +688,9 @@ static const struct proto_ops unix_stream_ops = { .getname = unix_getname, .poll = unix_poll, .ioctl = unix_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = unix_compat_ioctl, +#endif .listen = unix_listen, .shutdown = unix_shutdown, .setsockopt = sock_no_setsockopt, @@ -708,6 +714,9 @@ static const struct proto_ops unix_dgram_ops = { .getname = unix_getname, .poll = unix_dgram_poll, .ioctl = unix_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = unix_compat_ioctl, +#endif .listen = sock_no_listen, .shutdown = unix_shutdown, .setsockopt = sock_no_setsockopt, @@ -730,6 +739,9 @@ static const struct proto_ops unix_seqpacket_ops = { .getname = unix_getname, .poll = unix_dgram_poll, .ioctl = unix_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = unix_compat_ioctl, +#endif .listen = unix_listen, .shutdown = unix_shutdown, .setsockopt = sock_no_setsockopt, @@ -2650,6 +2662,13 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) return err; } +#ifdef CONFIG_COMPAT +static int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + return unix_ioctl(sock, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + static unsigned int unix_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; -- GitLab From 2e3f1f153b72509c2314dea9581fe0e35e4db94c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 3 Jun 2019 23:06:00 +0200 Subject: [PATCH 0190/1055] compat_ioctl: handle SIOCOUTQNSD commit 9d7bf41fafa5b5ddd4c13eb39446b0045f0a8167 upstream. Unlike the normal SIOCOUTQ, SIOCOUTQNSD was never handled in compat mode. Add it to the common socket compat handler along with similar ones. Fixes: 2f4e1b397097 ("tcp: ioctl type SIOCOUTQNSD returns amount of data not sent") Cc: Eric Dumazet Cc: netdev@vger.kernel.org Cc: "David S. Miller" Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- net/socket.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/socket.c b/net/socket.c index 5b134a6b6216..6a5ec658fcd8 100644 --- a/net/socket.c +++ b/net/socket.c @@ -3267,6 +3267,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, case SIOCSARP: case SIOCGARP: case SIOCDARP: + case SIOCOUTQNSD: case SIOCATMARK: return sock_do_ioctl(net, sock, cmd, arg); } -- GitLab From 7b7e8086030aa534245edd8d336b8d06a5591443 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 6 Nov 2019 15:30:48 -0600 Subject: [PATCH 0191/1055] PCI/PTM: Remove spurious "d" from granularity message commit 127a7709495db52a41012deaebbb7afc231dad91 upstream. The granularity message has an extra "d": pci 0000:02:00.0: PTM enabled, 4dns granularity Remove the "d" so the message is simply "PTM enabled, 4ns granularity". Fixes: 8b2ec318eece ("PCI: Add PTM clock granularity information") Link: https://lore.kernel.org/r/20191106222420.10216-2-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Andrew Murray Cc: Jonathan Yong Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pcie/ptm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pcie/ptm.c b/drivers/pci/pcie/ptm.c index bab8ac63c4f3..3008bba360f3 100644 --- a/drivers/pci/pcie/ptm.c +++ b/drivers/pci/pcie/ptm.c @@ -29,7 +29,7 @@ static void pci_ptm_info(struct pci_dev *dev) snprintf(clock_desc, sizeof(clock_desc), ">254ns"); break; default: - snprintf(clock_desc, sizeof(clock_desc), "%udns", + snprintf(clock_desc, sizeof(clock_desc), "%uns", dev->ptm_granularity); break; } -- GitLab From 6f0c76be8b0cb0250a68582c6bb2cc6c774ce597 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Mon, 18 Nov 2019 17:55:53 +1100 Subject: [PATCH 0192/1055] powerpc/powernv: Disable native PCIe port management commit 9d72dcef891030545f39ad386a30cf91df517fb2 upstream. On PowerNV the PCIe topology is (currently) managed by the powernv platform code in Linux in cooperation with the platform firmware. Linux's native PCIe port service drivers operate independently of both and this can cause problems. The main issue is that the portbus driver will conflict with the platform specific hotplug driver (pnv_php) over ownership of the MSI used to notify the host when a hotplug event occurs. The portbus driver claims this MSI on behalf of the individual port services because the same interrupt is used for hotplug events, PMEs (on root ports), and link bandwidth change notifications. The portbus driver will always claim the interrupt even if the individual port service drivers, such as pciehp, are compiled out. The second, bigger, problem is that the hotplug port service driver fundamentally does not work on PowerNV. The platform assumes that all PCI devices have a corresponding arch-specific handle derived from the DT node for the device (pci_dn) and without one the platform will not allow a PCI device to be enabled. This problem is largely due to historical baggage, but it can't be resolved without significant re-factoring of the platform PCI support. We can fix these problems in the interim by setting the "pcie_ports_disabled" flag during platform initialisation. The flag indicates the platform owns the PCIe ports which stops the portbus driver from being registered. This does have the side effect of disabling all port services drivers that is: AER, PME, BW notifications, hotplug, and DPC. However, this is not a huge disadvantage on PowerNV since these services are either unused or handled through other means. Fixes: 66725152fb9f ("PCI/hotplug: PowerPC PowerNV PCI hotplug driver") Signed-off-by: Oliver O'Halloran Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20191118065553.30362-1-oohall@gmail.com Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/pci.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index e2d031a3ec15..961c131a5b7e 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -1118,6 +1118,23 @@ void __init pnv_pci_init(void) if (!firmware_has_feature(FW_FEATURE_OPAL)) return; +#ifdef CONFIG_PCIEPORTBUS + /* + * On PowerNV PCIe devices are (currently) managed in cooperation + * with firmware. This isn't *strictly* required, but there's enough + * assumptions baked into both firmware and the platform code that + * it's unwise to allow the portbus services to be used. + * + * We need to fix this eventually, but for now set this flag to disable + * the portbus driver. The AER service isn't required since that AER + * events are handled via EEH. The pciehp hotplug driver can't work + * without kernel changes (and portbus binding breaks pnv_php). The + * other services also require some thinking about how we're going + * to integrate them. + */ + pcie_ports_disabled = true; +#endif + /* Look for IODA IO-Hubs. */ for_each_compatible_node(np, NULL, "ibm,ioda-hub") { pnv_pci_init_ioda_hub(np); -- GitLab From 9eee44f069bd76481598013c53e65ecd385d7438 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 7 Nov 2019 06:42:53 +0000 Subject: [PATCH 0193/1055] tty: serial: imx: use the sg count from dma_map_sg commit 596fd8dffb745afcebc0ec6968e17fe29f02044c upstream. The dmaengine_prep_slave_sg needs to use sg count returned by dma_map_sg, not use sport->dma_tx_nents, because the return value of dma_map_sg is not always same with "nents". Fixes: b4cdc8f61beb ("serial: imx: add DMA support for imx6q") Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/1573108875-26530-1-git-send-email-peng.fan@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index aae68230fb7b..a81a5be0cf7a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -542,7 +542,7 @@ static void imx_dma_tx(struct imx_port *sport) dev_err(dev, "DMA mapping error for TX.\n"); return; } - desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents, + desc = dmaengine_prep_slave_sg(chan, sgl, ret, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); if (!desc) { dma_unmap_sg(dev, sgl, sport->dma_tx_nents, -- GitLab From 77f33d715584a86c28758a36cd796dc5e5e592c9 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 13 Nov 2019 05:37:42 +0000 Subject: [PATCH 0194/1055] tty: serial: pch_uart: correct usage of dma_unmap_sg commit 74887542fdcc92ad06a48c0cca17cdf09fc8aa00 upstream. Per Documentation/DMA-API-HOWTO.txt, To unmap a scatterlist, just call: dma_unmap_sg(dev, sglist, nents, direction); .. note:: The 'nents' argument to the dma_unmap_sg call must be the _same_ one you passed into the dma_map_sg call, it should _NOT_ be the 'count' value _returned_ from the dma_map_sg call. However in the driver, priv->nent is directly assigned with value returned from dma_map_sg, and dma_unmap_sg use priv->nent for unmap, this breaks the API usage. So introduce a new entry orig_nent to remember 'nents'. Fixes: da3564ee027e ("pch_uart: add multi-scatter processing") Signed-off-by: Peng Fan Link: https://lore.kernel.org/r/1573623259-6339-1-git-send-email-peng.fan@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index d9123f995705..15ddcbd1f9d2 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -247,6 +247,7 @@ struct eg20t_port { struct dma_chan *chan_rx; struct scatterlist *sg_tx_p; int nent; + int orig_nent; struct scatterlist sg_rx; int tx_dma_use; void *rx_buf_virt; @@ -801,9 +802,10 @@ static void pch_dma_tx_complete(void *arg) } xmit->tail &= UART_XMIT_SIZE - 1; async_tx_ack(priv->desc_tx); - dma_unmap_sg(port->dev, sg, priv->nent, DMA_TO_DEVICE); + dma_unmap_sg(port->dev, sg, priv->orig_nent, DMA_TO_DEVICE); priv->tx_dma_use = 0; priv->nent = 0; + priv->orig_nent = 0; kfree(priv->sg_tx_p); pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_TX_INT); } @@ -1027,6 +1029,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) dev_err(priv->port.dev, "%s:dma_map_sg Failed\n", __func__); return 0; } + priv->orig_nent = num; priv->nent = nent; for (i = 0; i < nent; i++, sg++) { -- GitLab From 308f0585150c12e078b76331d5dc300b1dc005aa Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Tue, 3 Sep 2019 17:11:39 -0300 Subject: [PATCH 0195/1055] media: ov6650: Fix incorrect use of JPEG colorspace commit 12500731895ef09afc5b66b86b76c0884fb9c7bf upstream. Since its initial submission, the driver selects V4L2_COLORSPACE_JPEG for supported formats other than V4L2_MBUS_FMT_SBGGR8_1X8. According to v4l2-compliance test program, V4L2_COLORSPACE_JPEG applies exclusively to V4L2_PIX_FMT_JPEG. Since the sensor does not support JPEG format, fix it to always select V4L2_COLORSPACE_SRGB. Fixes: 2f6e2404799a ("[media] SoC Camera: add driver for OV6650 sensor") Signed-off-by: Janusz Krzysztofik Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/ov6650.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 348296be4925..5d6a231a4163 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -203,7 +203,6 @@ struct ov6650 { unsigned long pclk_max; /* from resolution and format */ struct v4l2_fract tpf; /* as requested with s_parm */ u32 code; - enum v4l2_colorspace colorspace; }; @@ -520,7 +519,7 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd, mf->width = priv->rect.width >> priv->half_scale; mf->height = priv->rect.height >> priv->half_scale; mf->code = priv->code; - mf->colorspace = priv->colorspace; + mf->colorspace = V4L2_COLORSPACE_SRGB; mf->field = V4L2_FIELD_NONE; return 0; @@ -627,11 +626,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) priv->pclk_max = 8000000; } - if (code == MEDIA_BUS_FMT_SBGGR8_1X8) - priv->colorspace = V4L2_COLORSPACE_SRGB; - else if (code != 0) - priv->colorspace = V4L2_COLORSPACE_JPEG; - if (half_scale) { dev_dbg(&client->dev, "max resolution: QCIF\n"); coma_set |= COMA_QCIF; @@ -666,7 +660,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) priv->code = code; if (!ret) { - mf->colorspace = priv->colorspace; mf->width = priv->rect.width >> half_scale; mf->height = priv->rect.height >> half_scale; } @@ -689,6 +682,7 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, &mf->height, 2, H_CIF, 1, 0); mf->field = V4L2_FIELD_NONE; + mf->colorspace = V4L2_COLORSPACE_SRGB; switch (mf->code) { case MEDIA_BUS_FMT_Y10_1X10: @@ -699,13 +693,11 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_UYVY8_2X8: - mf->colorspace = V4L2_COLORSPACE_JPEG; break; default: mf->code = MEDIA_BUS_FMT_SBGGR8_1X8; /* fall through */ case MEDIA_BUS_FMT_SBGGR8_1X8: - mf->colorspace = V4L2_COLORSPACE_SRGB; break; } @@ -1020,7 +1012,6 @@ static int ov6650_probe(struct i2c_client *client, priv->rect.height = H_CIF; priv->half_scale = false; priv->code = MEDIA_BUS_FMT_YUYV8_2X8; - priv->colorspace = V4L2_COLORSPACE_JPEG; ret = ov6650_video_probe(client); if (ret) -- GitLab From d739c826a15e887efb2c72355619b87e8dfc565c Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Tue, 3 Sep 2019 17:11:40 -0300 Subject: [PATCH 0196/1055] media: ov6650: Fix some format attributes not under control commit 1c6a2b63095154bbf9e8f38d79487a728331bf65 upstream. User arguments passed to .get/set_fmt() pad operation callbacks may contain unsupported values. The driver takes control over frame size and pixel code as well as colorspace and field attributes but has never cared for remainig format attributes, i.e., ycbcr_enc, quantization and xfer_func, introduced by commit 11ff030c7365 ("[media] v4l2-mediabus: improve colorspace support"). Fix it. Set up a static v4l2_mbus_framefmt structure with attributes initialized to reasonable defaults and use it for updating content of user provided arguments. In case of V4L2_SUBDEV_FORMAT_ACTIVE, postpone frame size update, now performed from inside ov6650_s_fmt() helper, util the user argument is first updated in ov6650_set_fmt() with default frame format content. For V4L2_SUBDEV_FORMAT_TRY, don't copy all attributes to pad config, only those handled by the driver, then fill the response with the default frame format updated with resulting pad config format code and frame size. Fixes: 11ff030c7365 ("[media] v4l2-mediabus: improve colorspace support") Signed-off-by: Janusz Krzysztofik Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/ov6650.c | 51 +++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 5d6a231a4163..044ede441fd6 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -215,6 +215,17 @@ static u32 ov6650_codes[] = { MEDIA_BUS_FMT_Y8_1X8, }; +static const struct v4l2_mbus_framefmt ov6650_def_fmt = { + .width = W_CIF, + .height = H_CIF, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .field = V4L2_FIELD_NONE, + .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, + .quantization = V4L2_QUANTIZATION_DEFAULT, + .xfer_func = V4L2_XFER_FUNC_DEFAULT, +}; + /* read a register */ static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) { @@ -516,11 +527,13 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd, if (format->pad) return -EINVAL; + /* initialize response with default media bus frame format */ + *mf = ov6650_def_fmt; + + /* update media bus format code and frame size */ mf->width = priv->rect.width >> priv->half_scale; mf->height = priv->rect.height >> priv->half_scale; mf->code = priv->code; - mf->colorspace = V4L2_COLORSPACE_SRGB; - mf->field = V4L2_FIELD_NONE; return 0; } @@ -659,10 +672,6 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) if (!ret) priv->code = code; - if (!ret) { - mf->width = priv->rect.width >> half_scale; - mf->height = priv->rect.height >> half_scale; - } return ret; } @@ -681,9 +690,6 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, v4l_bound_align_image(&mf->width, 2, W_CIF, 1, &mf->height, 2, H_CIF, 1, 0); - mf->field = V4L2_FIELD_NONE; - mf->colorspace = V4L2_COLORSPACE_SRGB; - switch (mf->code) { case MEDIA_BUS_FMT_Y10_1X10: mf->code = MEDIA_BUS_FMT_Y8_1X8; @@ -701,10 +707,31 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, break; } - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return ov6650_s_fmt(sd, mf); - cfg->try_fmt = *mf; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + /* store media bus format code and frame size in pad config */ + cfg->try_fmt.width = mf->width; + cfg->try_fmt.height = mf->height; + cfg->try_fmt.code = mf->code; + /* return default mbus frame format updated with pad config */ + *mf = ov6650_def_fmt; + mf->width = cfg->try_fmt.width; + mf->height = cfg->try_fmt.height; + mf->code = cfg->try_fmt.code; + + } else { + /* apply new media bus format code and frame size */ + int ret = ov6650_s_fmt(sd, mf); + + if (ret) + return ret; + + /* return default format updated with active size and code */ + *mf = ov6650_def_fmt; + mf->width = priv->rect.width >> priv->half_scale; + mf->height = priv->rect.height >> priv->half_scale; + mf->code = priv->code; + } return 0; } -- GitLab From 68b315b4df8f8a6ecb2345874e3e08177978734d Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Tue, 3 Sep 2019 17:11:41 -0300 Subject: [PATCH 0197/1055] media: ov6650: Fix .get_fmt() V4L2_SUBDEV_FORMAT_TRY support commit 39034bb0c26b76a2c3abc54aa28c185f18b40c2f upstream. Commit da298c6d98d5 ("[media] v4l2: replace video op g_mbus_fmt by pad op get_fmt") converted a former ov6650_g_fmt() video operation callback to an ov6650_get_fmt() pad operation callback. However, the converted function disregards a format->which flag that pad operations should obey and always returns active frame format settings. That can be fixed by always responding to V4L2_SUBDEV_FORMAT_TRY with -EINVAL, or providing the response from a pad config argument, likely updated by a former user call to V4L2_SUBDEV_FORMAT_TRY .set_fmt(). Since implementation of the latter is trivial, go for it. Fixes: da298c6d98d5 ("[media] v4l2: replace video op g_mbus_fmt by pad op get_fmt") Signed-off-by: Janusz Krzysztofik Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/ov6650.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 044ede441fd6..4f67a515bdd8 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -531,10 +531,16 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd, *mf = ov6650_def_fmt; /* update media bus format code and frame size */ - mf->width = priv->rect.width >> priv->half_scale; - mf->height = priv->rect.height >> priv->half_scale; - mf->code = priv->code; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + mf->width = cfg->try_fmt.width; + mf->height = cfg->try_fmt.height; + mf->code = cfg->try_fmt.code; + } else { + mf->width = priv->rect.width >> priv->half_scale; + mf->height = priv->rect.height >> priv->half_scale; + mf->code = priv->code; + } return 0; } -- GitLab From 4b4c9d23cf49e1aa694b042f3c5e01c291768eac Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Fri, 18 Oct 2019 07:20:52 -0300 Subject: [PATCH 0198/1055] media: exynos4-is: Fix recursive locking in isp_video_release() commit 704c6c80fb471d1bb0ef0d61a94617d1d55743cd upstream. >From isp_video_release(), &isp->video_lock is held and subsequent vb2_fop_release() tries to lock vdev->lock which is same with the previous one. Replace vb2_fop_release() with _vb2_fop_release() to fix the recursive locking. Fixes: 1380f5754cb0 ("[media] videobuf2: Add missing lock held on vb2_fop_release") Signed-off-by: Seung-Woo Kim Reviewed-by: Sylwester Nawrocki Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/exynos4-is/fimc-isp-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index a920164f53f1..39340abefd14 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -316,7 +316,7 @@ static int isp_video_release(struct file *file) ivc->streaming = 0; } - vb2_fop_release(file); + _vb2_fop_release(file, NULL); if (v4l2_fh_is_singular_file(file)) { fimc_pipeline_call(&ivc->ve, close); -- GitLab From 0e08a1875bb2eb5b7ae913c35ef2886823fcdffd Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 30 Oct 2019 21:48:59 +0300 Subject: [PATCH 0199/1055] mtd: spi-nor: fix silent truncation in spi_nor_read() commit a719a75a7761e4139dd099330d9fe3589d844f9b upstream. spi_nor_read() assigns the result of 'ssize_t spi_nor_read_data()' to the 'int ret' variable, while 'ssize_t' is a 64-bit type and *int* is a 32-bit type on the 64-bit machines. This silent truncation isn't really valid, so fix up the variable's type. Fixes: 59451e1233bd ("mtd: spi-nor: change return value of read/write") Signed-off-by: Sergei Shtylyov Signed-off-by: Tudor Ambarus Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/spi-nor/spi-nor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d550148177a0..114f75ec0088 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1216,7 +1216,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct spi_nor *nor = mtd_to_spi_nor(mtd); - int ret; + ssize_t ret; dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len); -- GitLab From 45d37bd0a80f25ecac6d9d23d2240bdc1c1a83b3 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 30 Oct 2019 21:53:03 +0300 Subject: [PATCH 0200/1055] mtd: spi-nor: fix silent truncation in spi_nor_read_raw() commit 3d63ee5deb466fd66ed6ffb164a87ce36425cf36 upstream. spi_nor_read_raw() assigns the result of 'ssize_t spi_nor_read_data()' to the 'int ret' variable, while 'ssize_t' is a 64-bit type and *int* is a 32-bit type on the 64-bit machines. This silent truncation isn't really valid, so fix up the variable's type. Fixes: f384b352cbf0 ("mtd: spi-nor: parse Serial Flash Discoverable Parameters (SFDP) tables") Signed-off-by: Sergei Shtylyov Signed-off-by: Tudor Ambarus Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/spi-nor/spi-nor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 114f75ec0088..0fe3e39f870f 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1445,7 +1445,7 @@ static int macronix_quad_enable(struct spi_nor *nor) */ static int write_sr_cr(struct spi_nor *nor, u8 *sr_cr) { - int ret; + ssize_t ret; write_enable(nor); -- GitLab From 9f499bd50632840c1eeebdf1ff87ef8b76f5299a Mon Sep 17 00:00:00 2001 From: Mans Rullgard Date: Fri, 18 Oct 2019 17:35:04 +0200 Subject: [PATCH 0201/1055] spi: atmel: fix handling of cs_change set on non-last xfer commit fed8d8c7a6dc2a76d7764842853d81c770b0788e upstream. The driver does the wrong thing when cs_change is set on a non-last xfer in a message. When cs_change is set, the driver deactivates the CS and leaves it off until a later xfer again has cs_change set whereas it should be briefly toggling CS off and on again. This patch brings the behaviour of the driver back in line with the documentation and common sense. The delay of 10 us is the same as is used by the default spi_transfer_one_message() function in spi.c. [gregory: rebased on for-5.5 from spi tree] Fixes: 8090d6d1a415 ("spi: atmel: Refactor spi-atmel to use SPI framework queue") Signed-off-by: Mans Rullgard Acked-by: Nicolas Ferre Signed-off-by: Gregory CLEMENT Link: https://lore.kernel.org/r/20191018153504.4249-1-gregory.clement@bootlin.com Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-atmel.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index d19331b66222..7b739c449227 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -301,7 +301,6 @@ struct atmel_spi { bool use_cs_gpios; bool keep_cs; - bool cs_active; u32 fifo_size; }; @@ -1338,11 +1337,9 @@ static int atmel_spi_one_transfer(struct spi_master *master, &msg->transfers)) { as->keep_cs = true; } else { - as->cs_active = !as->cs_active; - if (as->cs_active) - cs_activate(as, msg->spi); - else - cs_deactivate(as, msg->spi); + cs_deactivate(as, msg->spi); + udelay(10); + cs_activate(as, msg->spi); } } @@ -1365,7 +1362,6 @@ static int atmel_spi_transfer_one_message(struct spi_master *master, atmel_spi_lock(as); cs_activate(as, spi); - as->cs_active = true; as->keep_cs = false; msg->status = 0; -- GitLab From b9ffea4c1225aa5b1eba344708400a6fe6a71a1f Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 22 Oct 2019 17:47:03 -0700 Subject: [PATCH 0202/1055] rtlwifi: Remove unnecessary NULL check in rtl_regd_init commit 091c6e9c083f7ebaff00b37ad13562d51464d175 upstream. When building with Clang + -Wtautological-pointer-compare: drivers/net/wireless/realtek/rtlwifi/regd.c:389:33: warning: comparison of address of 'rtlpriv->regd' equal to a null pointer is always false [-Wtautological-pointer-compare] if (wiphy == NULL || &rtlpriv->regd == NULL) ~~~~~~~~~^~~~ ~~~~ 1 warning generated. The address of an array member is never NULL unless it is the first struct member so remove the unnecessary check. This was addressed in the staging version of the driver in commit f986978b32b3 ("Staging: rtlwifi: remove unnecessary NULL check"). While we are here, fix the following checkpatch warning: CHECK: Comparison to NULL could be written "!wiphy" 35: FILE: drivers/net/wireless/realtek/rtlwifi/regd.c:389: + if (wiphy == NULL) Fixes: 0c8173385e54 ("rtl8192ce: Add new driver") Link:https://github.com/ClangBuiltLinux/linux/issues/750 Signed-off-by: Nathan Chancellor Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/realtek/rtlwifi/regd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/regd.c b/drivers/net/wireless/realtek/rtlwifi/regd.c index 1bf3eb25c1da..72ca370331fb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/regd.c +++ b/drivers/net/wireless/realtek/rtlwifi/regd.c @@ -427,7 +427,7 @@ int rtl_regd_init(struct ieee80211_hw *hw, struct wiphy *wiphy = hw->wiphy; struct country_code_to_enum_rd *country = NULL; - if (wiphy == NULL || &rtlpriv->regd == NULL) + if (!wiphy) return -EINVAL; /* init country_code from efuse channel plan */ -- GitLab From 872340aa041eb12c831abee7d26d8e8f685a6a70 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 7 Nov 2019 17:29:00 +0800 Subject: [PATCH 0203/1055] f2fs: fix potential overflow commit 1f0d5c911b64165c9754139a26c8c2fad352c132 upstream. We expect 64-bit calculation result from below statement, however in 32-bit machine, looped left shift operation on pgoff_t type variable may cause overflow issue, fix it by forcing type cast. page->index << PAGE_SHIFT; Fixes: 26de9b117130 ("f2fs: avoid unnecessary updating inode during fsync") Fixes: 0a2aa8fbb969 ("f2fs: refactor __exchange_data_block for speed up") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/data.c | 2 +- fs/f2fs/file.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index ac3fa4bbed2d..afe7dcfff036 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1512,7 +1512,7 @@ static int __write_data_page(struct page *page, bool *submitted, loff_t i_size = i_size_read(inode); const pgoff_t end_index = ((unsigned long long) i_size) >> PAGE_SHIFT; - loff_t psize = (page->index + 1) << PAGE_SHIFT; + loff_t psize = (loff_t)(page->index + 1) << PAGE_SHIFT; unsigned offset = 0; bool need_balance_fs = false; int err = 0; diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index a90173b856f6..d98acc20a38a 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1059,7 +1059,7 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode, } dn.ofs_in_node++; i++; - new_size = (dst + i) << PAGE_SHIFT; + new_size = (loff_t)(dst + i) << PAGE_SHIFT; if (dst_inode->i_size < new_size) f2fs_i_size_write(dst_inode, new_size); } while (--ilen && (do_replace[i] || blkaddr[i] == NULL_ADDR)); -- GitLab From 4e1f6dfffa11e264a669df3998f960adb8efaac8 Mon Sep 17 00:00:00 2001 From: Kars de Jong Date: Sat, 16 Nov 2019 12:05:48 +0100 Subject: [PATCH 0204/1055] rtc: msm6242: Fix reading of 10-hour digit commit e34494c8df0cd96fc432efae121db3212c46ae48 upstream. The driver was reading the wrong register as the 10-hour digit due to a misplaced ')'. It was in fact reading the 1-second digit register due to this bug. Also remove the use of a magic number for the hour mask and use the define for it which was already present. Fixes: 4f9b9bba1dd1 ("rtc: Add an RTC driver for the Oki MSM6242") Tested-by: Kars de Jong Signed-off-by: Kars de Jong Link: https://lore.kernel.org/r/20191116110548.8562-1-jongk@linux-m68k.org Reviewed-by: Geert Uytterhoeven Signed-off-by: Alexandre Belloni Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-msm6242.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c index c1c5c4e3b3b4..c981301efbe5 100644 --- a/drivers/rtc/rtc-msm6242.c +++ b/drivers/rtc/rtc-msm6242.c @@ -132,7 +132,8 @@ static int msm6242_read_time(struct device *dev, struct rtc_time *tm) msm6242_read(priv, MSM6242_SECOND1); tm->tm_min = msm6242_read(priv, MSM6242_MINUTE10) * 10 + msm6242_read(priv, MSM6242_MINUTE1); - tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10 & 3)) * 10 + + tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10) & + MSM6242_HOUR10_HR_MASK) * 10 + msm6242_read(priv, MSM6242_HOUR1); tm->tm_mday = msm6242_read(priv, MSM6242_DAY10) * 10 + msm6242_read(priv, MSM6242_DAY1); -- GitLab From 749b39e7c6552de2db2b5610b22532fd3a9563fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johnson=20CH=20Chen=20=28=E9=99=B3=E6=98=AD=E5=8B=B3=29?= Date: Tue, 26 Nov 2019 06:51:11 +0000 Subject: [PATCH 0205/1055] gpio: mpc8xxx: Add platform device to gpiochip->parent [ Upstream commit 322f6a3182d42df18059a89c53b09d33919f755e ] Dear Linus Walleij, In old kernels, some APIs still try to use parent->of_node from struct gpio_chip, and it could be resulted in kernel panic because parent is NULL. Adding platform device to gpiochip->parent can fix this problem. Signed-off-by: Johnson Chen Link: https://patchwork.kernel.org/patch/11234609 Link: https://lore.kernel.org/r/HK0PR01MB3521489269F76467DFD7843FFA450@HK0PR01MB3521.apcprd01.prod.exchangelabs.com Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin --- drivers/gpio/gpio-mpc8xxx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index e7783b852d69..d5f735ce0dd4 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -306,6 +306,7 @@ static int mpc8xxx_probe(struct platform_device *pdev) return -ENOMEM; gc = &mpc8xxx_gc->gc; + gc->parent = &pdev->dev; if (of_property_read_bool(np, "little-endian")) { ret = bgpio_init(gc, &pdev->dev, 4, -- GitLab From 248a7fd151393b5b5e00d3d6a4e2144f67717ba0 Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Wed, 18 Dec 2019 19:15:31 +0530 Subject: [PATCH 0206/1055] scsi: libcxgbi: fix NULL pointer dereference in cxgbi_device_destroy() [ Upstream commit 71482fde704efdd8c3abe0faf34d922c61e8d76b ] If cxgb4i_ddp_init() fails then cdev->cdev2ppm will be NULL, so add a check for NULL pointer before dereferencing it. Link: https://lore.kernel.org/r/1576676731-3068-1-git-send-email-varun@chelsio.com Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/cxgbi/libcxgbi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index 902f5e03ec94..0d45658f163a 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -121,7 +121,8 @@ static inline void cxgbi_device_destroy(struct cxgbi_device *cdev) "cdev 0x%p, p# %u.\n", cdev, cdev->nports); cxgbi_hbas_remove(cdev); cxgbi_device_portmap_cleanup(cdev); - cxgbi_ppm_release(cdev->cdev2ppm(cdev)); + if (cdev->cdev2ppm) + cxgbi_ppm_release(cdev->cdev2ppm(cdev)); if (cdev->pmap.max_connect) cxgbi_free_big_mem(cdev->pmap.port_csk); kfree(cdev); -- GitLab From d3c981eb0bd7444039b5950fc06602e92f676f6c Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Wed, 11 Dec 2019 11:28:57 -0500 Subject: [PATCH 0207/1055] rseq/selftests: Turn off timeout setting [ Upstream commit af9cb29c5488381083b0b5ccdfb3cd931063384a ] As the rseq selftests can run for a long period of time, disable the timeout that the general selftests have. Signed-off-by: Mathieu Desnoyers Cc: Shuah Khan Cc: Thomas Gleixner Cc: Peter Zijlstra (Intel) Cc: "Paul E. McKenney" Cc: Boqun Feng Cc: "H . Peter Anvin" Cc: Paul Turner Cc: Dmitry Vyukov Signed-off-by: Shuah Khan Signed-off-by: Sasha Levin --- tools/testing/selftests/rseq/settings | 1 + 1 file changed, 1 insertion(+) create mode 100644 tools/testing/selftests/rseq/settings diff --git a/tools/testing/selftests/rseq/settings b/tools/testing/selftests/rseq/settings new file mode 100644 index 000000000000..e7b9417537fb --- /dev/null +++ b/tools/testing/selftests/rseq/settings @@ -0,0 +1 @@ +timeout=0 -- GitLab From ac9951c4894ee3a6c2d8b1e110a95b1ab1e8625b Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Sun, 24 Nov 2019 16:07:31 +0200 Subject: [PATCH 0208/1055] mips: cacheinfo: report shared CPU map [ Upstream commit 3b1313eb32c499d46dc4c3e896d19d9564c879c4 ] Report L1 caches as shared per core; L2 - per cluster. This fixes "perf" that went crazy if shared_cpu_map attribute not reported on sysfs, in form of /sys/devices/system/cpu/cpu*/cache/index*/shared_cpu_list /sys/devices/system/cpu/cpu*/cache/index*/shared_cpu_map Signed-off-by: Vladimir Kondratiev Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Sasha Levin --- arch/mips/kernel/cacheinfo.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/cacheinfo.c b/arch/mips/kernel/cacheinfo.c index 428ef2189203..3ea95568ece4 100644 --- a/arch/mips/kernel/cacheinfo.c +++ b/arch/mips/kernel/cacheinfo.c @@ -61,6 +61,25 @@ static int __init_cache_level(unsigned int cpu) return 0; } +static void fill_cpumask_siblings(int cpu, cpumask_t *cpu_map) +{ + int cpu1; + + for_each_possible_cpu(cpu1) + if (cpus_are_siblings(cpu, cpu1)) + cpumask_set_cpu(cpu1, cpu_map); +} + +static void fill_cpumask_cluster(int cpu, cpumask_t *cpu_map) +{ + int cpu1; + int cluster = cpu_cluster(&cpu_data[cpu]); + + for_each_possible_cpu(cpu1) + if (cpu_cluster(&cpu_data[cpu1]) == cluster) + cpumask_set_cpu(cpu1, cpu_map); +} + static int __populate_cache_leaves(unsigned int cpu) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -68,14 +87,20 @@ static int __populate_cache_leaves(unsigned int cpu) struct cacheinfo *this_leaf = this_cpu_ci->info_list; if (c->icache.waysize) { + /* L1 caches are per core */ + fill_cpumask_siblings(cpu, &this_leaf->shared_cpu_map); populate_cache(dcache, this_leaf, 1, CACHE_TYPE_DATA); + fill_cpumask_siblings(cpu, &this_leaf->shared_cpu_map); populate_cache(icache, this_leaf, 1, CACHE_TYPE_INST); } else { populate_cache(dcache, this_leaf, 1, CACHE_TYPE_UNIFIED); } - if (c->scache.waysize) + if (c->scache.waysize) { + /* L2 cache is per cluster */ + fill_cpumask_cluster(cpu, &this_leaf->shared_cpu_map); populate_cache(scache, this_leaf, 2, CACHE_TYPE_UNIFIED); + } if (c->tcache.waysize) populate_cache(tcache, this_leaf, 3, CACHE_TYPE_UNIFIED); -- GitLab From babf91acca033201ce29fdb2914ea1ee64c186e2 Mon Sep 17 00:00:00 2001 From: Jouni Hogander Date: Mon, 9 Dec 2019 14:37:07 +0200 Subject: [PATCH 0209/1055] MIPS: Prevent link failure with kcov instrumentation [ Upstream commit a4a3893114a41e365274d5fab5d9ff5acc235ff0 ] __sanitizer_cov_trace_pc() is not linked in and causing link failure if KCOV_INSTRUMENT is enabled. Fix this by disabling instrumentation for compressed image. Signed-off-by: Jouni Hogander Signed-off-by: Paul Burton Cc: Lukas Bulwahn Cc: linux-mips@vger.kernel.org Signed-off-by: Sasha Levin --- arch/mips/boot/compressed/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index 331b9e0a8072..baa34e4deb78 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -29,6 +29,9 @@ KBUILD_AFLAGS := $(KBUILD_AFLAGS) -D__ASSEMBLY__ \ -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \ -DKERNEL_ENTRY=$(VMLINUX_ENTRY_ADDRESS) +# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. +KCOV_INSTRUMENT := n + # decompressor objects (linked with vmlinuz) vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o -- GitLab From ed4e771283ff1f04e9f409ff4485ad0430c160b9 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Wed, 18 Dec 2019 19:09:06 +0000 Subject: [PATCH 0210/1055] dmaengine: k3dma: Avoid null pointer traversal [ Upstream commit 2f42e05b942fe2fbfb9bbc6e34e1dd8c3ce4f3a4 ] In some cases we seem to submit two transactions in a row, which causes us to lose track of the first. If we then cancel the request, we may still get an interrupt, which traverses a null ds_run value. So try to avoid starting a new transaction if the ds_run value is set. While this patch avoids the null pointer crash, I've had some reports of the k3dma driver still getting confused, which suggests the ds_run/ds_done value handling still isn't quite right. However, I've not run into an issue recently with it so I think this patch is worth pushing upstream to avoid the crash. Signed-off-by: John Stultz [add ss tag] Link: https://lore.kernel.org/r/20191218190906.6641-1-john.stultz@linaro.org Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/k3dma.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index 219ae3b545db..803045c92f3b 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -222,9 +222,11 @@ static irqreturn_t k3_dma_int_handler(int irq, void *dev_id) c = p->vchan; if (c && (tc1 & BIT(i))) { spin_lock_irqsave(&c->vc.lock, flags); - vchan_cookie_complete(&p->ds_run->vd); - p->ds_done = p->ds_run; - p->ds_run = NULL; + if (p->ds_run != NULL) { + vchan_cookie_complete(&p->ds_run->vd); + p->ds_done = p->ds_run; + p->ds_run = NULL; + } spin_unlock_irqrestore(&c->vc.lock, flags); } if (c && (tc2 & BIT(i))) { @@ -264,6 +266,10 @@ static int k3_dma_start_txd(struct k3_dma_chan *c) if (BIT(c->phy->idx) & k3_dma_get_chan_stat(d)) return -EAGAIN; + /* Avoid losing track of ds_run if a transaction is in flight */ + if (c->phy->ds_run) + return -EAGAIN; + if (vd) { struct k3_dma_desc_sw *ds = container_of(vd, struct k3_dma_desc_sw, vd); -- GitLab From 8e2b251811f2848f77b3eb58344623b146633097 Mon Sep 17 00:00:00 2001 From: "Alexander.Barabash@dell.com" Date: Wed, 25 Dec 2019 17:55:30 +0000 Subject: [PATCH 0211/1055] ioat: ioat_alloc_ring() failure handling. [ Upstream commit b0b5ce1010ffc50015eaec72b0028aaae3f526bb ] If dma_alloc_coherent() returns NULL in ioat_alloc_ring(), ring allocation must not proceed. Until now, if the first call to dma_alloc_coherent() in ioat_alloc_ring() returned NULL, the processing could proceed, failing with NULL-pointer dereferencing further down the line. Signed-off-by: Alexander Barabash Acked-by: Dave Jiang Link: https://lore.kernel.org/r/75e9c0e84c3345d693c606c64f8b9ab5@x13pwhopdag1307.AMER.DELL.COM Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/ioat/dma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index f70cc74032ea..e3899ae429e0 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -388,10 +388,11 @@ ioat_alloc_ring(struct dma_chan *c, int order, gfp_t flags) descs->virt = dma_alloc_coherent(to_dev(ioat_chan), SZ_2M, &descs->hw, flags); - if (!descs->virt && (i > 0)) { + if (!descs->virt) { int idx; for (idx = 0; idx < i; idx++) { + descs = &ioat_chan->descs[idx]; dma_free_coherent(to_dev(ioat_chan), SZ_2M, descs->virt, descs->hw); descs->virt = NULL; -- GitLab From 42df34c76c87e797a56b67a511b7bfcff3879874 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Sat, 4 Jan 2020 12:59:59 -0800 Subject: [PATCH 0212/1055] hexagon: parenthesize registers in asm predicates [ Upstream commit 780a0cfda9006a9a22d6473c2d4c527f5c68eb2e ] Hexagon requires that register predicates in assembly be parenthesized. Link: https://github.com/ClangBuiltLinux/linux/issues/754 Link: http://lkml.kernel.org/r/20191209222956.239798-3-ndesaulniers@google.com Signed-off-by: Nick Desaulniers Suggested-by: Sid Manning Acked-by: Brian Cain Cc: Lee Jones Cc: Andy Shevchenko Cc: Tuowen Zhao Cc: Mika Westerberg Cc: Luis Chamberlain Cc: Greg Kroah-Hartman Cc: Alexios Zavras Cc: Allison Randal Cc: Will Deacon Cc: Richard Fontana Cc: Thomas Gleixner Cc: Peter Zijlstra Cc: Boqun Feng Cc: Ingo Molnar Cc: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- arch/hexagon/include/asm/atomic.h | 8 ++++---- arch/hexagon/include/asm/bitops.h | 8 ++++---- arch/hexagon/include/asm/cmpxchg.h | 2 +- arch/hexagon/include/asm/futex.h | 6 +++--- arch/hexagon/include/asm/spinlock.h | 20 ++++++++++---------- arch/hexagon/kernel/vm_entry.S | 2 +- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h index fb3dfb2a667e..d4e283b4f335 100644 --- a/arch/hexagon/include/asm/atomic.h +++ b/arch/hexagon/include/asm/atomic.h @@ -105,7 +105,7 @@ static inline void atomic_##op(int i, atomic_t *v) \ "1: %0 = memw_locked(%1);\n" \ " %0 = "#op "(%0,%2);\n" \ " memw_locked(%1,P3)=%0;\n" \ - " if !P3 jump 1b;\n" \ + " if (!P3) jump 1b;\n" \ : "=&r" (output) \ : "r" (&v->counter), "r" (i) \ : "memory", "p3" \ @@ -121,7 +121,7 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ "1: %0 = memw_locked(%1);\n" \ " %0 = "#op "(%0,%2);\n" \ " memw_locked(%1,P3)=%0;\n" \ - " if !P3 jump 1b;\n" \ + " if (!P3) jump 1b;\n" \ : "=&r" (output) \ : "r" (&v->counter), "r" (i) \ : "memory", "p3" \ @@ -138,7 +138,7 @@ static inline int atomic_fetch_##op(int i, atomic_t *v) \ "1: %0 = memw_locked(%2);\n" \ " %1 = "#op "(%0,%3);\n" \ " memw_locked(%2,P3)=%1;\n" \ - " if !P3 jump 1b;\n" \ + " if (!P3) jump 1b;\n" \ : "=&r" (output), "=&r" (val) \ : "r" (&v->counter), "r" (i) \ : "memory", "p3" \ @@ -187,7 +187,7 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) " }" " memw_locked(%2, p3) = %1;" " {" - " if !p3 jump 1b;" + " if (!p3) jump 1b;" " }" "2:" : "=&r" (__oldval), "=&r" (tmp) diff --git a/arch/hexagon/include/asm/bitops.h b/arch/hexagon/include/asm/bitops.h index 2691a1857d20..634306cda006 100644 --- a/arch/hexagon/include/asm/bitops.h +++ b/arch/hexagon/include/asm/bitops.h @@ -52,7 +52,7 @@ static inline int test_and_clear_bit(int nr, volatile void *addr) "1: R12 = memw_locked(R10);\n" " { P0 = tstbit(R12,R11); R12 = clrbit(R12,R11); }\n" " memw_locked(R10,P1) = R12;\n" - " {if !P1 jump 1b; %0 = mux(P0,#1,#0);}\n" + " {if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n" : "=&r" (oldval) : "r" (addr), "r" (nr) : "r10", "r11", "r12", "p0", "p1", "memory" @@ -76,7 +76,7 @@ static inline int test_and_set_bit(int nr, volatile void *addr) "1: R12 = memw_locked(R10);\n" " { P0 = tstbit(R12,R11); R12 = setbit(R12,R11); }\n" " memw_locked(R10,P1) = R12;\n" - " {if !P1 jump 1b; %0 = mux(P0,#1,#0);}\n" + " {if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n" : "=&r" (oldval) : "r" (addr), "r" (nr) : "r10", "r11", "r12", "p0", "p1", "memory" @@ -102,7 +102,7 @@ static inline int test_and_change_bit(int nr, volatile void *addr) "1: R12 = memw_locked(R10);\n" " { P0 = tstbit(R12,R11); R12 = togglebit(R12,R11); }\n" " memw_locked(R10,P1) = R12;\n" - " {if !P1 jump 1b; %0 = mux(P0,#1,#0);}\n" + " {if (!P1) jump 1b; %0 = mux(P0,#1,#0);}\n" : "=&r" (oldval) : "r" (addr), "r" (nr) : "r10", "r11", "r12", "p0", "p1", "memory" @@ -237,7 +237,7 @@ static inline int ffs(int x) int r; asm("{ P0 = cmp.eq(%1,#0); %0 = ct0(%1);}\n" - "{ if P0 %0 = #0; if !P0 %0 = add(%0,#1);}\n" + "{ if (P0) %0 = #0; if (!P0) %0 = add(%0,#1);}\n" : "=&r" (r) : "r" (x) : "p0"); diff --git a/arch/hexagon/include/asm/cmpxchg.h b/arch/hexagon/include/asm/cmpxchg.h index a6e34e2acbba..db258424059f 100644 --- a/arch/hexagon/include/asm/cmpxchg.h +++ b/arch/hexagon/include/asm/cmpxchg.h @@ -44,7 +44,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, __asm__ __volatile__ ( "1: %0 = memw_locked(%1);\n" /* load into retval */ " memw_locked(%1,P0) = %2;\n" /* store into memory */ - " if !P0 jump 1b;\n" + " if (!P0) jump 1b;\n" : "=&r" (retval) : "r" (ptr), "r" (x) : "memory", "p0" diff --git a/arch/hexagon/include/asm/futex.h b/arch/hexagon/include/asm/futex.h index c889f5993ecd..e8e5e47afb37 100644 --- a/arch/hexagon/include/asm/futex.h +++ b/arch/hexagon/include/asm/futex.h @@ -16,7 +16,7 @@ /* For example: %1 = %4 */ \ insn \ "2: memw_locked(%3,p2) = %1;\n" \ - " if !p2 jump 1b;\n" \ + " if (!p2) jump 1b;\n" \ " %1 = #0;\n" \ "3:\n" \ ".section .fixup,\"ax\"\n" \ @@ -84,10 +84,10 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, "1: %1 = memw_locked(%3)\n" " {\n" " p2 = cmp.eq(%1,%4)\n" - " if !p2.new jump:NT 3f\n" + " if (!p2.new) jump:NT 3f\n" " }\n" "2: memw_locked(%3,p2) = %5\n" - " if !p2 jump 1b\n" + " if (!p2) jump 1b\n" "3:\n" ".section .fixup,\"ax\"\n" "4: %0 = #%6\n" diff --git a/arch/hexagon/include/asm/spinlock.h b/arch/hexagon/include/asm/spinlock.h index 53a8d5885887..007056263b8e 100644 --- a/arch/hexagon/include/asm/spinlock.h +++ b/arch/hexagon/include/asm/spinlock.h @@ -44,9 +44,9 @@ static inline void arch_read_lock(arch_rwlock_t *lock) __asm__ __volatile__( "1: R6 = memw_locked(%0);\n" " { P3 = cmp.ge(R6,#0); R6 = add(R6,#1);}\n" - " { if !P3 jump 1b; }\n" + " { if (!P3) jump 1b; }\n" " memw_locked(%0,P3) = R6;\n" - " { if !P3 jump 1b; }\n" + " { if (!P3) jump 1b; }\n" : : "r" (&lock->lock) : "memory", "r6", "p3" @@ -60,7 +60,7 @@ static inline void arch_read_unlock(arch_rwlock_t *lock) "1: R6 = memw_locked(%0);\n" " R6 = add(R6,#-1);\n" " memw_locked(%0,P3) = R6\n" - " if !P3 jump 1b;\n" + " if (!P3) jump 1b;\n" : : "r" (&lock->lock) : "memory", "r6", "p3" @@ -75,7 +75,7 @@ static inline int arch_read_trylock(arch_rwlock_t *lock) __asm__ __volatile__( " R6 = memw_locked(%1);\n" " { %0 = #0; P3 = cmp.ge(R6,#0); R6 = add(R6,#1);}\n" - " { if !P3 jump 1f; }\n" + " { if (!P3) jump 1f; }\n" " memw_locked(%1,P3) = R6;\n" " { %0 = P3 }\n" "1:\n" @@ -102,9 +102,9 @@ static inline void arch_write_lock(arch_rwlock_t *lock) __asm__ __volatile__( "1: R6 = memw_locked(%0)\n" " { P3 = cmp.eq(R6,#0); R6 = #-1;}\n" - " { if !P3 jump 1b; }\n" + " { if (!P3) jump 1b; }\n" " memw_locked(%0,P3) = R6;\n" - " { if !P3 jump 1b; }\n" + " { if (!P3) jump 1b; }\n" : : "r" (&lock->lock) : "memory", "r6", "p3" @@ -118,7 +118,7 @@ static inline int arch_write_trylock(arch_rwlock_t *lock) __asm__ __volatile__( " R6 = memw_locked(%1)\n" " { %0 = #0; P3 = cmp.eq(R6,#0); R6 = #-1;}\n" - " { if !P3 jump 1f; }\n" + " { if (!P3) jump 1f; }\n" " memw_locked(%1,P3) = R6;\n" " %0 = P3;\n" "1:\n" @@ -141,9 +141,9 @@ static inline void arch_spin_lock(arch_spinlock_t *lock) __asm__ __volatile__( "1: R6 = memw_locked(%0);\n" " P3 = cmp.eq(R6,#0);\n" - " { if !P3 jump 1b; R6 = #1; }\n" + " { if (!P3) jump 1b; R6 = #1; }\n" " memw_locked(%0,P3) = R6;\n" - " { if !P3 jump 1b; }\n" + " { if (!P3) jump 1b; }\n" : : "r" (&lock->lock) : "memory", "r6", "p3" @@ -163,7 +163,7 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock) __asm__ __volatile__( " R6 = memw_locked(%1);\n" " P3 = cmp.eq(R6,#0);\n" - " { if !P3 jump 1f; R6 = #1; %0 = #0; }\n" + " { if (!P3) jump 1f; R6 = #1; %0 = #0; }\n" " memw_locked(%1,P3) = R6;\n" " %0 = P3;\n" "1:\n" diff --git a/arch/hexagon/kernel/vm_entry.S b/arch/hexagon/kernel/vm_entry.S index 67c6ccc14770..9f4a73ff7203 100644 --- a/arch/hexagon/kernel/vm_entry.S +++ b/arch/hexagon/kernel/vm_entry.S @@ -382,7 +382,7 @@ ret_from_fork: R26.L = #LO(do_work_pending); R0 = #VM_INT_DISABLE; } - if P0 jump check_work_pending + if (P0) jump check_work_pending { R0 = R25; callr R24 -- GitLab From ffcb1af55b18fe05089c6faf831839febeca22b1 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Sat, 4 Jan 2020 13:00:02 -0800 Subject: [PATCH 0213/1055] hexagon: work around compiler crash [ Upstream commit 63e80314ab7cf4783526d2e44ee57a90514911c9 ] Clang cannot translate the string "r30" into a valid register yet. Link: https://github.com/ClangBuiltLinux/linux/issues/755 Link: http://lkml.kernel.org/r/20191028155722.23419-1-ndesaulniers@google.com Signed-off-by: Nick Desaulniers Suggested-by: Sid Manning Reviewed-by: Brian Cain Cc: Allison Randal Cc: Greg Kroah-Hartman Cc: Richard Fontana Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- arch/hexagon/kernel/stacktrace.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/hexagon/kernel/stacktrace.c b/arch/hexagon/kernel/stacktrace.c index 41866a06adf7..ec4ef682923d 100644 --- a/arch/hexagon/kernel/stacktrace.c +++ b/arch/hexagon/kernel/stacktrace.c @@ -24,8 +24,6 @@ #include #include -register unsigned long current_frame_pointer asm("r30"); - struct stackframe { unsigned long fp; unsigned long rets; @@ -43,7 +41,7 @@ void save_stack_trace(struct stack_trace *trace) low = (unsigned long)task_stack_page(current); high = low + THREAD_SIZE; - fp = current_frame_pointer; + fp = (unsigned long)__builtin_frame_address(0); while (fp >= low && fp <= (high - sizeof(*frame))) { frame = (struct stackframe *)fp; -- GitLab From e6af540790d6057f9f31e693167d3bfc847af200 Mon Sep 17 00:00:00 2001 From: Kai Li Date: Sat, 4 Jan 2020 13:00:18 -0800 Subject: [PATCH 0214/1055] ocfs2: call journal flush to mark journal as empty after journal recovery when mount [ Upstream commit 397eac17f86f404f5ba31d8c3e39ec3124b39fd3 ] If journal is dirty when mount, it will be replayed but jbd2 sb log tail cannot be updated to mark a new start because journal->j_flag has already been set with JBD2_ABORT first in journal_init_common. When a new transaction is committed, it will be recored in block 1 first(journal->j_tail is set to 1 in journal_reset). If emergency restart happens again before journal super block is updated unfortunately, the new recorded trans will not be replayed in the next mount. The following steps describe this procedure in detail. 1. mount and touch some files 2. these transactions are committed to journal area but not checkpointed 3. emergency restart 4. mount again and its journals are replayed 5. journal super block's first s_start is 1, but its s_seq is not updated 6. touch a new file and its trans is committed but not checkpointed 7. emergency restart again 8. mount and journal is dirty, but trans committed in 6 will not be replayed. This exception happens easily when this lun is used by only one node. If it is used by multi-nodes, other node will replay its journal and its journal super block will be updated after recovery like what this patch does. ocfs2_recover_node->ocfs2_replay_journal. The following jbd2 journal can be generated by touching a new file after journal is replayed, and seq 15 is the first valid commit, but first seq is 13 in journal super block. logdump: Block 0: Journal Superblock Seq: 0 Type: 4 (JBD2_SUPERBLOCK_V2) Blocksize: 4096 Total Blocks: 32768 First Block: 1 First Commit ID: 13 Start Log Blknum: 1 Error: 0 Feature Compat: 0 Feature Incompat: 2 block64 Feature RO compat: 0 Journal UUID: 4ED3822C54294467A4F8E87D2BA4BC36 FS Share Cnt: 1 Dynamic Superblk Blknum: 0 Per Txn Block Limit Journal: 0 Data: 0 Block 1: Journal Commit Block Seq: 14 Type: 2 (JBD2_COMMIT_BLOCK) Block 2: Journal Descriptor Seq: 15 Type: 1 (JBD2_DESCRIPTOR_BLOCK) No. Blocknum Flags 0. 587 none UUID: 00000000000000000000000000000000 1. 8257792 JBD2_FLAG_SAME_UUID 2. 619 JBD2_FLAG_SAME_UUID 3. 24772864 JBD2_FLAG_SAME_UUID 4. 8257802 JBD2_FLAG_SAME_UUID 5. 513 JBD2_FLAG_SAME_UUID JBD2_FLAG_LAST_TAG ... Block 7: Inode Inode: 8257802 Mode: 0640 Generation: 57157641 (0x3682809) FS Generation: 2839773110 (0xa9437fb6) CRC32: 00000000 ECC: 0000 Type: Regular Attr: 0x0 Flags: Valid Dynamic Features: (0x1) InlineData User: 0 (root) Group: 0 (root) Size: 7 Links: 1 Clusters: 0 ctime: 0x5de5d870 0x11104c61 -- Tue Dec 3 11:37:20.286280801 2019 atime: 0x5de5d870 0x113181a1 -- Tue Dec 3 11:37:20.288457121 2019 mtime: 0x5de5d870 0x11104c61 -- Tue Dec 3 11:37:20.286280801 2019 dtime: 0x0 -- Thu Jan 1 08:00:00 1970 ... Block 9: Journal Commit Block Seq: 15 Type: 2 (JBD2_COMMIT_BLOCK) The following is journal recovery log when recovering the upper jbd2 journal when mount again. syslog: ocfs2: File system on device (252,1) was not unmounted cleanly, recovering it. fs/jbd2/recovery.c:(do_one_pass, 449): Starting recovery pass 0 fs/jbd2/recovery.c:(do_one_pass, 449): Starting recovery pass 1 fs/jbd2/recovery.c:(do_one_pass, 449): Starting recovery pass 2 fs/jbd2/recovery.c:(jbd2_journal_recover, 278): JBD2: recovery, exit status 0, recovered transactions 13 to 13 Due to first commit seq 13 recorded in journal super is not consistent with the value recorded in block 1(seq is 14), journal recovery will be terminated before seq 15 even though it is an unbroken commit, inode 8257802 is a new file and it will be lost. Link: http://lkml.kernel.org/r/20191217020140.2197-1-li.kai4@h3c.com Signed-off-by: Kai Li Reviewed-by: Joseph Qi Reviewed-by: Changwei Ge Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Cc: Gang He Cc: Jun Piao Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- fs/ocfs2/journal.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 2459ae9d2234..39bb80fb2934 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -1080,6 +1080,14 @@ int ocfs2_journal_load(struct ocfs2_journal *journal, int local, int replayed) ocfs2_clear_journal_error(osb->sb, journal->j_journal, osb->slot_num); + if (replayed) { + jbd2_journal_lock_updates(journal->j_journal); + status = jbd2_journal_flush(journal->j_journal); + jbd2_journal_unlock_updates(journal->j_journal); + if (status < 0) + mlog_errno(status); + } + status = ocfs2_journal_toggle_dirty(osb, 1, replayed); if (status < 0) { mlog_errno(status); -- GitLab From c1141b3aab36eb0d9b2bcae4aff69e77d0554386 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Jan 2020 19:45:55 +0100 Subject: [PATCH 0215/1055] Linux 4.14.166 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 166e18aa9ca9..7c62b4078c1b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 165 +SUBLEVEL = 166 EXTRAVERSION = NAME = Petit Gorille -- GitLab From 2f1f0637838408a0e99ee443a72b74f44fb54401 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 30 Nov 2019 19:53:37 +0100 Subject: [PATCH 0216/1055] dt-bindings: reset: meson8b: fix duplicate reset IDs commit 4881873f4cc1460f63d85fa81363d56be328ccdc upstream. According to the public S805 datasheet the RESET2 register uses the following bits for the PIC_DC, PSC and NAND reset lines: - PIC_DC is at bit 3 (meaning: RESET_VD_RMEM + 3) - PSC is at bit 4 (meaning: RESET_VD_RMEM + 4) - NAND is at bit 5 (meaning: RESET_VD_RMEM + 4) Update the reset IDs of these three reset lines so they don't conflict with PIC_DC and map to the actual hardware reset lines. Fixes: 79795e20a184eb ("dt-bindings: reset: Add bindings for the Meson SoC Reset Controller") Signed-off-by: Martin Blumenstingl Signed-off-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman --- include/dt-bindings/reset/amlogic,meson8b-reset.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/dt-bindings/reset/amlogic,meson8b-reset.h b/include/dt-bindings/reset/amlogic,meson8b-reset.h index 614aff2c7aff..a03e86fe2c57 100644 --- a/include/dt-bindings/reset/amlogic,meson8b-reset.h +++ b/include/dt-bindings/reset/amlogic,meson8b-reset.h @@ -95,9 +95,9 @@ #define RESET_VD_RMEM 64 #define RESET_AUDIN 65 #define RESET_DBLK 66 -#define RESET_PIC_DC 66 -#define RESET_PSC 66 -#define RESET_NAND 66 +#define RESET_PIC_DC 67 +#define RESET_PSC 68 +#define RESET_NAND 69 #define RESET_GE2D 70 #define RESET_PARSER_REG 71 #define RESET_PARSER_FETCH 72 -- GitLab From 692dcea72e4aaf1d25833a1f42663bf83efd344c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 25 Dec 2019 08:34:29 -0800 Subject: [PATCH 0217/1055] clk: Don't try to enable critical clocks if prepare failed commit 12ead77432f2ce32dea797742316d15c5800cb32 upstream. The following traceback is seen if a critical clock fails to prepare. bcm2835-clk 3f101000.cprman: plld: couldn't lock PLL ------------[ cut here ]------------ Enabling unprepared plld_per WARNING: CPU: 1 PID: 1 at drivers/clk/clk.c:1014 clk_core_enable+0xcc/0x2c0 ... Call trace: clk_core_enable+0xcc/0x2c0 __clk_register+0x5c4/0x788 devm_clk_hw_register+0x4c/0xb0 bcm2835_register_pll_divider+0xc0/0x150 bcm2835_clk_probe+0x134/0x1e8 platform_drv_probe+0x50/0xa0 really_probe+0xd4/0x308 driver_probe_device+0x54/0xe8 device_driver_attach+0x6c/0x78 __driver_attach+0x54/0xd8 ... Check return values from clk_core_prepare() and clk_core_enable() and bail out if any of those functions returns an error. Cc: Jerome Brunet Fixes: 99652a469df1 ("clk: migrate the count of orphaned clocks at init") Signed-off-by: Guenter Roeck Link: https://lkml.kernel.org/r/20191225163429.29694-1-linux@roeck-us.net Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/clk.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index a3f52f678211..8341a128dab1 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2482,11 +2482,17 @@ static int __clk_core_init(struct clk_core *core) if (core->flags & CLK_IS_CRITICAL) { unsigned long flags; - clk_core_prepare(core); + ret = clk_core_prepare(core); + if (ret) + goto out; flags = clk_enable_lock(); - clk_core_enable(core); + ret = clk_core_enable(core); clk_enable_unlock(flags); + if (ret) { + clk_core_unprepare(core); + goto out; + } } /* -- GitLab From 00bbc127415f104ed0f195a994fc3892f2d5383e Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Sat, 11 Jan 2020 17:40:03 +0100 Subject: [PATCH 0218/1055] ASoC: msm8916-wcd-analog: Fix selected events for MIC BIAS External1 commit e0beec88397b163c7c4ea6fcfb67e8e07a2671dc upstream. MIC BIAS External1 sets pm8916_wcd_analog_enable_micbias_ext1() as event handler, which ends up in pm8916_wcd_analog_enable_micbias_ext(). But pm8916_wcd_analog_enable_micbias_ext() only handles the POST_PMU event, which is not specified in the event flags for MIC BIAS External1. This means that the code in the event handler is never actually run. Set SND_SOC_DAPM_POST_PMU as the only event for the handler to fix this. Fixes: 585e881e5b9e ("ASoC: codecs: Add msm8916-wcd analog codec") Cc: Srinivas Kandagatla Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20200111164006.43074-2-stephan@gerhold.net Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/msm8916-wcd-analog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 969283737787..3633eb30dd13 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -876,10 +876,10 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("MIC BIAS External1", CDC_A_MICB_1_EN, 7, 0, pm8916_wcd_analog_enable_micbias_ext1, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_SUPPLY("MIC BIAS External2", CDC_A_MICB_2_EN, 7, 0, pm8916_wcd_analog_enable_micbias_ext2, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_ADC_E("ADC1", NULL, CDC_A_TX_1_EN, 7, 0, pm8916_wcd_analog_enable_adc, -- GitLab From 43bb0a16b25d5030193935b5c292648fa9abc0fc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 15 Jan 2020 21:37:33 +0100 Subject: [PATCH 0219/1055] ALSA: seq: Fix racy access for queue timer in proc read commit 60adcfde92fa40fcb2dbf7cc52f9b096e0cd109a upstream. snd_seq_info_timer_read() reads the information of the timer assigned for each queue, but it's done in a racy way which may lead to UAF as spotted by syzkaller. This patch applies the missing q->timer_mutex lock while accessing the timer object as well as a slight code change to adapt the standard coding style. Reported-by: syzbot+2b2ef983f973e5c40943@syzkaller.appspotmail.com Cc: Link: https://lore.kernel.org/r/20200115203733.26530-1-tiwai@suse.de Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/seq_timer.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index b80985fbc334..0e1feb597586 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -479,15 +479,19 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry, q = queueptr(idx); if (q == NULL) continue; - if ((tmr = q->timer) == NULL || - (ti = tmr->timeri) == NULL) { - queuefree(q); - continue; - } + mutex_lock(&q->timer_mutex); + tmr = q->timer; + if (!tmr) + goto unlock; + ti = tmr->timeri; + if (!ti) + goto unlock; snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name); resolution = snd_timer_resolution(ti) * tmr->ticks; snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000); snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base); +unlock: + mutex_unlock(&q->timer_mutex); queuefree(q); } } -- GitLab From 8085d56065edc52628efb502e5fc03c7230c8fe2 Mon Sep 17 00:00:00 2001 From: Jari Ruusu Date: Sun, 12 Jan 2020 15:00:53 +0200 Subject: [PATCH 0220/1055] Fix built-in early-load Intel microcode alignment commit f5ae2ea6347a308cfe91f53b53682ce635497d0d upstream. Intel Software Developer's Manual, volume 3, chapter 9.11.6 says: "Note that the microcode update must be aligned on a 16-byte boundary and the size of the microcode update must be 1-KByte granular" When early-load Intel microcode is loaded from initramfs, userspace tool 'iucode_tool' has already 16-byte aligned those microcode bits in that initramfs image. Image that was created something like this: iucode_tool --write-earlyfw=FOO.cpio microcode-files... However, when early-load Intel microcode is loaded from built-in firmware BLOB using CONFIG_EXTRA_FIRMWARE= kernel config option, that 16-byte alignment is not guaranteed. Fix this by forcing all built-in firmware BLOBs to 16-byte alignment. [ If we end up having other firmware with much bigger alignment requirements, we might need to introduce some method for the firmware to specify it, this is the minimal "just increase the alignment a bit to account for this one special case" patch - Linus ] Signed-off-by: Jari Ruusu Cc: Borislav Petkov Cc: Fenghua Yu Cc: Luis Chamberlain Cc: stable@kernel.org Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- firmware/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/Makefile b/firmware/Makefile index 168094a3fae7..30e6b738839e 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -19,7 +19,7 @@ quiet_cmd_fwbin = MK_FW $@ PROGBITS=$(if $(CONFIG_ARM),%,@)progbits; \ echo "/* Generated by firmware/Makefile */" > $@;\ echo " .section .rodata" >>$@;\ - echo " .p2align $${ASM_ALIGN}" >>$@;\ + echo " .p2align 4" >>$@;\ echo "_fw_$${FWSTR}_bin:" >>$@;\ echo " .incbin \"$(2)\"" >>$@;\ echo "_fw_end:" >>$@;\ -- GitLab From 0c7a7d8e62bd942bf8e5d80486132d3ec0173b69 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 15 Jan 2020 08:35:25 -0500 Subject: [PATCH 0221/1055] block: fix an integer overflow in logical block size commit ad6bf88a6c19a39fb3b0045d78ea880325dfcf15 upstream. Logical block size has type unsigned short. That means that it can be at most 32768. However, there are architectures that can run with 64k pages (for example arm64) and on these architectures, it may be possible to create block devices with 64k block size. For exmaple (run this on an architecture with 64k pages): Mount will fail with this error because it tries to read the superblock using 2-sector access: device-mapper: writecache: I/O is not aligned, sector 2, size 1024, block size 65536 EXT4-fs (dm-0): unable to read superblock This patch changes the logical block size from unsigned short to unsigned int to avoid the overflow. Cc: stable@vger.kernel.org Reviewed-by: Martin K. Petersen Reviewed-by: Ming Lei Signed-off-by: Mikulas Patocka Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/blk-settings.c | 2 +- drivers/md/dm-snap-persistent.c | 2 +- drivers/md/raid0.c | 2 +- include/linux/blkdev.h | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/block/blk-settings.c b/block/blk-settings.c index 474b0b95fcd1..6c2faaa38cc1 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -379,7 +379,7 @@ EXPORT_SYMBOL(blk_queue_max_segment_size); * storage device can address. The default of 512 covers most * hardware. **/ -void blk_queue_logical_block_size(struct request_queue *q, unsigned short size) +void blk_queue_logical_block_size(struct request_queue *q, unsigned int size) { q->limits.logical_block_size = size; diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c index c5534d294773..00025569e807 100644 --- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -17,7 +17,7 @@ #include "dm-bufio.h" #define DM_MSG_PREFIX "persistent snapshot" -#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32 /* 16KB */ +#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32U /* 16KB */ #define DM_PREFETCH_CHUNKS 12 diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 204adde004a3..cdafa5e0ea6d 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -94,7 +94,7 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf) char b[BDEVNAME_SIZE]; char b2[BDEVNAME_SIZE]; struct r0conf *conf = kzalloc(sizeof(*conf), GFP_KERNEL); - unsigned short blksize = 512; + unsigned blksize = 512; *private_conf = ERR_PTR(-ENOMEM); if (!conf) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 4d4af0e94059..ad940102451c 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -343,6 +343,7 @@ struct queue_limits { unsigned int max_sectors; unsigned int max_segment_size; unsigned int physical_block_size; + unsigned int logical_block_size; unsigned int alignment_offset; unsigned int io_min; unsigned int io_opt; @@ -353,7 +354,6 @@ struct queue_limits { unsigned int discard_granularity; unsigned int discard_alignment; - unsigned short logical_block_size; unsigned short max_segments; unsigned short max_integrity_segments; unsigned short max_discard_segments; @@ -1178,7 +1178,7 @@ extern void blk_queue_max_write_same_sectors(struct request_queue *q, unsigned int max_write_same_sectors); extern void blk_queue_max_write_zeroes_sectors(struct request_queue *q, unsigned int max_write_same_sectors); -extern void blk_queue_logical_block_size(struct request_queue *, unsigned short); +extern void blk_queue_logical_block_size(struct request_queue *, unsigned int); extern void blk_queue_physical_block_size(struct request_queue *, unsigned int); extern void blk_queue_alignment_offset(struct request_queue *q, unsigned int alignment); @@ -1436,7 +1436,7 @@ static inline unsigned int queue_max_segment_size(struct request_queue *q) return q->limits.max_segment_size; } -static inline unsigned short queue_logical_block_size(struct request_queue *q) +static inline unsigned queue_logical_block_size(struct request_queue *q) { int retval = 512; @@ -1446,7 +1446,7 @@ static inline unsigned short queue_logical_block_size(struct request_queue *q) return retval; } -static inline unsigned short bdev_logical_block_size(struct block_device *bdev) +static inline unsigned int bdev_logical_block_size(struct block_device *bdev) { return queue_logical_block_size(bdev_get_queue(bdev)); } -- GitLab From f27885c16525c3e4d4c5fa79ba9fcfcf3d1ab96c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Tue, 17 Dec 2019 14:21:23 +0530 Subject: [PATCH 0222/1055] ARM: dts: am571x-idk: Fix gpios property to have the correct gpio number commit 0c4eb2a6b3c6b0facd0a3bccda5db22e7b3b6f96 upstream. commit d23f3839fe97d8dce03d ("ARM: dts: DRA7: Add pcie1 dt node for EP mode") while adding the dt node for EP mode for DRA7 platform, added rc node for am571x-idk and populated gpios property with "gpio3 23". However the GPIO_PCIE_SWRST line is actually connected to "gpio5 18". Fix it here. (The patch adding "gpio3 23" was tested with another am57x board in EP mode which doesn't rely on reset from host). Cc: stable # 4.14+ Fixes: d23f3839fe97d8dce03d ("ARM: dts: DRA7: Add pcie1 dt node for EP mode") Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/am571x-idk.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/am571x-idk.dts b/arch/arm/boot/dts/am571x-idk.dts index debf9464403e..96a4df4109d7 100644 --- a/arch/arm/boot/dts/am571x-idk.dts +++ b/arch/arm/boot/dts/am571x-idk.dts @@ -93,7 +93,7 @@ &pcie1_rc { status = "okay"; - gpios = <&gpio3 23 GPIO_ACTIVE_HIGH>; + gpios = <&gpio5 18 GPIO_ACTIVE_HIGH>; }; &pcie1_ep { -- GitLab From ca76e5b3504fc0a72168c4982053604b4d7814ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=B6llendorf?= Date: Fri, 13 Dec 2019 14:50:55 +0100 Subject: [PATCH 0223/1055] iio: buffer: align the size of scan bytes to size of the largest element MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 883f616530692d81cb70f8a32d85c0d2afc05f69 upstream. Previous versions of `iio_compute_scan_bytes` only aligned each element to its own length (i.e. its own natural alignment). Because multiple consecutive sets of scan elements are buffered this does not work in case the computed scan bytes do not align with the natural alignment of the first scan element in the set. This commit fixes this by aligning the scan bytes to the natural alignment of the largest scan element in the set. Fixes: 959d2952d124 ("staging:iio: make iio_sw_buffer_preenable much more general.") Signed-off-by: Lars Möllendorf Reviewed-by: Lars-Peter Clausen Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/industrialio-buffer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index d50125766093..c3badf634378 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -570,7 +570,7 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const unsigned long *mask, bool timestamp) { unsigned bytes = 0; - int length, i; + int length, i, largest = 0; /* How much space will the demuxed element take? */ for_each_set_bit(i, mask, @@ -578,13 +578,17 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, length = iio_storage_bytes_for_si(indio_dev, i); bytes = ALIGN(bytes, length); bytes += length; + largest = max(largest, length); } if (timestamp) { length = iio_storage_bytes_for_timestamp(indio_dev); bytes = ALIGN(bytes, length); bytes += length; + largest = max(largest, length); } + + bytes = ALIGN(bytes, largest); return bytes; } -- GitLab From a31be20233df25e202bfc8ed9a52a93b34385f7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jer=C3=B3nimo=20Borque?= Date: Thu, 9 Jan 2020 12:23:34 -0300 Subject: [PATCH 0224/1055] USB: serial: simple: Add Motorola Solutions TETRA MTP3xxx and MTP85xx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 260e41ac4dd3e5acb90be624c03ba7f019615b75 upstream. Add device-ids for the Motorola Solutions TETRA radios MTP3xxx series and MTP85xx series $ lsusb -vd 0cad: Bus 001 Device 009: ID 0cad:9015 Motorola CGISS TETRA PEI interface Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0cad Motorola CGISS idProduct 0x9015 bcdDevice 24.16 iManufacturer 1 iProduct 2 iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0037 bNumInterfaces 2 bConfigurationValue 1 iConfiguration 3 bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Bus 001 Device 010: ID 0cad:9013 Motorola CGISS TETRA PEI interface Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0cad Motorola CGISS idProduct 0x9013 bcdDevice 24.16 iManufacturer 1 iProduct 2 iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0037 bNumInterfaces 2 bConfigurationValue 1 iConfiguration 3 bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Signed-off-by: Jerónimo Borque Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial-simple.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 511242111403..15e05ebf37ac 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -89,6 +89,8 @@ DEVICE(moto_modem, MOTO_IDS); #define MOTOROLA_TETRA_IDS() \ { USB_DEVICE(0x0cad, 0x9011) }, /* Motorola Solutions TETRA PEI */ \ { USB_DEVICE(0x0cad, 0x9012) }, /* MTP6550 */ \ + { USB_DEVICE(0x0cad, 0x9013) }, /* MTP3xxx */ \ + { USB_DEVICE(0x0cad, 0x9015) }, /* MTP85xx */ \ { USB_DEVICE(0x0cad, 0x9016) } /* TPG2200 */ DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS); -- GitLab From 223f97fc43cda4bce578641ffbec60aa02edfb1e Mon Sep 17 00:00:00 2001 From: Kristian Evensen Date: Mon, 13 Jan 2020 15:14:05 +0100 Subject: [PATCH 0225/1055] USB: serial: option: Add support for Quectel RM500Q commit accf227de4d211b52c830a58b2df00d5739f2389 upstream. RM500Q is a 5G module from Quectel, supporting both standalone and non-standalone modes. Unlike other recent Quectel modems, it is possible to identify the diagnostic interface (bInterfaceProtocol is unique). Thus, there is no need to check for the number of endpoints or reserve interfaces. The interface number is still dynamic though, so matching on interface number is not possible and two entries have to be added to the table. Output from usb-devices with all interfaces enabled (order is diag, nmea, at_port, modem, rmnet and adb): Bus 004 Device 007: ID 2c7c:0800 Quectel Wireless Solutions Co., Ltd. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 3.20 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 9 idVendor 0x2c7c Quectel Wireless Solutions Co., Ltd. idProduct 0x0800 bcdDevice 4.14 iManufacturer 1 Quectel iProduct 2 LTE-A Module iSerial 3 40046d60 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 328 bNumInterfaces 6 bConfigurationValue 1 iConfiguration 4 DIAG_SER_RMNET bmAttributes 0xa0 (Bus Powered) Remote Wakeup MaxPower 224mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 48 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 0 bMaxBurst 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 0 bMaxBurst 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 ** UNRECOGNIZED: 05 24 00 10 01 ** UNRECOGNIZED: 05 24 01 00 00 ** UNRECOGNIZED: 04 24 02 02 ** UNRECOGNIZED: 05 24 06 00 00 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x83 EP 3 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x000a 1x 10 bytes bInterval 9 bMaxBurst 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 0 bMaxBurst 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 0 bMaxBurst 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 ** UNRECOGNIZED: 05 24 00 10 01 ** UNRECOGNIZED: 05 24 01 00 00 ** UNRECOGNIZED: 04 24 02 02 ** UNRECOGNIZED: 05 24 06 00 00 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x000a 1x 10 bytes bInterval 9 bMaxBurst 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x84 EP 4 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 0 bMaxBurst 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x03 EP 3 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 0 bMaxBurst 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 3 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 ** UNRECOGNIZED: 05 24 00 10 01 ** UNRECOGNIZED: 05 24 01 00 00 ** UNRECOGNIZED: 04 24 02 02 ** UNRECOGNIZED: 05 24 06 00 00 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x87 EP 7 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x000a 1x 10 bytes bInterval 9 bMaxBurst 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x86 EP 6 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 0 bMaxBurst 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x04 EP 4 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 0 bMaxBurst 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 4 bAlternateSetting 0 bNumEndpoints 3 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 255 Vendor Specific Subclass bInterfaceProtocol 255 Vendor Specific Protocol iInterface 5 CDEV Serial Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x88 EP 8 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes bInterval 9 bMaxBurst 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x8e EP 14 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 0 bMaxBurst 6 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x0f EP 15 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 0 bMaxBurst 2 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 5 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 66 bInterfaceProtocol 1 iInterface 6 ADB Interface Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x05 EP 5 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 0 bMaxBurst 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x89 EP 9 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0400 1x 1024 bytes bInterval 0 bMaxBurst 0 Binary Object Store Descriptor: bLength 5 bDescriptorType 15 wTotalLength 42 bNumDeviceCaps 3 USB 2.0 Extension Device Capability: bLength 7 bDescriptorType 16 bDevCapabilityType 2 bmAttributes 0x00000006 Link Power Management (LPM) Supported SuperSpeed USB Device Capability: bLength 10 bDescriptorType 16 bDevCapabilityType 3 bmAttributes 0x00 wSpeedsSupported 0x000f Device can operate at Low Speed (1Mbps) Device can operate at Full Speed (12Mbps) Device can operate at High Speed (480Mbps) Device can operate at SuperSpeed (5Gbps) bFunctionalitySupport 1 Lowest fully-functional device speed is Full Speed (12Mbps) bU1DevExitLat 1 micro seconds bU2DevExitLat 500 micro seconds ** UNRECOGNIZED: 14 10 0a 00 01 00 00 00 00 11 00 00 30 40 0a 00 b0 40 0a 00 Device Status: 0x0000 (Bus Powered) Signed-off-by: Kristian Evensen Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e69e31539914..d40f31c18030 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -251,6 +251,7 @@ static void option_instat_callback(struct urb *urb); #define QUECTEL_PRODUCT_BG96 0x0296 #define QUECTEL_PRODUCT_EP06 0x0306 #define QUECTEL_PRODUCT_EM12 0x0512 +#define QUECTEL_PRODUCT_RM500Q 0x0800 #define CMOTECH_VENDOR_ID 0x16d8 #define CMOTECH_PRODUCT_6001 0x6001 @@ -1107,6 +1108,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0xff, 0xff), .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0xff, 0x30) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0, 0) }, + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003), -- GitLab From 7f61deb9c4d54dff9e005f18f319a2c356041ab6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Jan 2020 18:22:13 +0100 Subject: [PATCH 0226/1055] USB: serial: opticon: fix control-message timeouts commit 5e28055f340275a8616eee88ef19186631b4d136 upstream. The driver was issuing synchronous uninterruptible control requests without using a timeout. This could lead to the driver hanging on open() or tiocmset() due to a malfunctioning (or malicious) device until the device is physically disconnected. The USB upper limit of five seconds per request should be more than enough. Fixes: 309a057932ab ("USB: opticon: add rts and cts support") Cc: stable # 2.6.39 Cc: Martin Jansen Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/opticon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 58657d64678b..c37572a8bb06 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -116,7 +116,7 @@ static int send_control_msg(struct usb_serial_port *port, u8 requesttype, retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), requesttype, USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, - 0, 0, buffer, 1, 0); + 0, 0, buffer, 1, USB_CTRL_SET_TIMEOUT); kfree(buffer); if (retval < 0) -- GitLab From e19bcd176c4e844560749981221103c58e40e407 Mon Sep 17 00:00:00 2001 From: Reinhard Speyerer Date: Tue, 14 Jan 2020 14:29:23 +0100 Subject: [PATCH 0227/1055] USB: serial: option: add support for Quectel RM500Q in QDL mode commit f3eaabbfd093c93d791eb930cc68d9b15246a65e upstream. Add support for Quectel RM500Q in QDL mode. T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 24 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=2c7c ProdID=0800 Rev= 0.00 S: Manufacturer=Qualcomm CDMA Technologies MSM S: Product=QUSB_BULK_SN:xxxxxxxx S: SerialNumber=xxxxxxxx C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr= 2mA I:* If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=10 Driver=option E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms It is assumed that the ZLP flag required for other Qualcomm-based 5G devices also applies to Quectel RM500Q. Signed-off-by: Reinhard Speyerer Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index d40f31c18030..eff353de47cd 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1110,6 +1110,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500Q, 0xff, 0xff, 0x10), + .driver_info = ZLP }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, -- GitLab From bcca7cb09cc58dabb871f4f2fca13399d344ef63 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 16 Jan 2020 17:07:05 +0100 Subject: [PATCH 0228/1055] USB: serial: suppress driver bind attributes commit fdb838efa31e1ed9a13ae6ad0b64e30fdbd00570 upstream. USB-serial drivers must not be unbound from their ports before the corresponding USB driver is unbound from the parent interface so suppress the bind and unbind attributes. Unbinding a serial driver while it's port is open is a sure way to trigger a crash as any driver state is released on unbind while port hangup is handled on the parent USB interface level. Drivers for multiport devices where ports share a resource such as an interrupt endpoint also generally cannot handle individual ports going away. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 8115b7cccf1a..3dc3464626fb 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1332,6 +1332,9 @@ static int usb_serial_register(struct usb_serial_driver *driver) return -EINVAL; } + /* Prevent individual ports from being unbound. */ + driver->driver.suppress_bind_attrs = true; + usb_serial_operations_init(driver); /* Add this device to our list of devices */ -- GitLab From 1c63fa75f0cb67928c251ac575590bda61fdcc0a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 17 Jan 2020 10:50:22 +0100 Subject: [PATCH 0229/1055] USB: serial: ch341: handle unbound port at reset_resume commit 4d5ef53f75c22d28f490bcc5c771fcc610a9afa4 upstream. Check for NULL port data in reset_resume() to avoid dereferencing a NULL pointer in case the port device isn't bound to a driver (e.g. after a failed control request at port probe). Fixes: 1ded7ea47b88 ("USB: ch341 serial: fix port number changed after resume") Cc: stable # 2.6.30 Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ch341.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 578596d301b8..31cd798d2dac 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -592,9 +592,13 @@ static int ch341_tiocmget(struct tty_struct *tty) static int ch341_reset_resume(struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; - struct ch341_private *priv = usb_get_serial_port_data(port); + struct ch341_private *priv; int ret; + priv = usb_get_serial_port_data(port); + if (!priv) + return 0; + /* reconfigure ch341 serial port after bus-reset */ ch341_configure(serial->dev, priv); -- GitLab From e804bb78f21cebc10ddfba62d1dc3ac498a109cc Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 17 Jan 2020 10:50:24 +0100 Subject: [PATCH 0230/1055] USB: serial: io_edgeport: add missing active-port sanity check commit 1568c58d11a7c851bd09341aeefd6a1c308ac40d upstream. The driver receives the active port number from the device, but never made sure that the port number was valid. This could lead to a NULL-pointer dereference or memory corruption in case a device sends data for an invalid port. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/io_edgeport.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 51b61545ccf2..467870f504a5 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1733,7 +1733,8 @@ static void edge_break(struct tty_struct *tty, int break_state) static void process_rcvd_data(struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength) { - struct device *dev = &edge_serial->serial->dev->dev; + struct usb_serial *serial = edge_serial->serial; + struct device *dev = &serial->dev->dev; struct usb_serial_port *port; struct edgeport_port *edge_port; __u16 lastBufferLength; @@ -1838,9 +1839,8 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, /* spit this data back into the tty driver if this port is open */ - if (rxLen) { - port = edge_serial->serial->port[ - edge_serial->rxPort]; + if (rxLen && edge_serial->rxPort < serial->num_ports) { + port = serial->port[edge_serial->rxPort]; edge_port = usb_get_serial_port_data(port); if (edge_port->open) { dev_dbg(dev, "%s - Sending %d bytes to TTY for port %d\n", @@ -1850,8 +1850,8 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, rxLen); edge_port->port->icount.rx += rxLen; } - buffer += rxLen; } + buffer += rxLen; break; case EXPECT_HDR3: /* Expect 3rd byte of status header */ @@ -1886,6 +1886,8 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, __u8 code = edge_serial->rxStatusCode; /* switch the port pointer to the one being currently talked about */ + if (edge_serial->rxPort >= edge_serial->serial->num_ports) + return; port = edge_serial->serial->port[edge_serial->rxPort]; edge_port = usb_get_serial_port_data(port); if (edge_port == NULL) { -- GitLab From 534afe14ec5f5aec941f66e3bc4b417e442b8298 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 17 Jan 2020 10:50:25 +0100 Subject: [PATCH 0231/1055] USB: serial: keyspan: handle unbound ports commit 3018dd3fa114b13261e9599ddb5656ef97a1fa17 upstream. Check for NULL port data in the control URB completion handlers to avoid dereferencing a NULL pointer in the unlikely case where a port device isn't bound to a driver (e.g. after an allocation failure on port probe()). Fixes: 0ca1268e109a ("USB Serial Keyspan: add support for USA-49WG & USA-28XG") Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable 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, 4 insertions(+) diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 2c5a53bdccd4..55a768487990 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -1062,6 +1062,8 @@ static void usa49_glocont_callback(struct urb *urb) for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; p_priv = usb_get_serial_port_data(port); + if (!p_priv) + continue; if (p_priv->resend_cont) { dev_dbg(&port->dev, "%s - sending setup\n", __func__); @@ -1463,6 +1465,8 @@ static void usa67_glocont_callback(struct urb *urb) for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; p_priv = usb_get_serial_port_data(port); + if (!p_priv) + continue; if (p_priv->resend_cont) { dev_dbg(&port->dev, "%s - sending setup\n", __func__); -- GitLab From 3afe35a859aca32ad888193cf171a86a0a23eac8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 17 Jan 2020 15:35:26 +0100 Subject: [PATCH 0232/1055] USB: serial: quatech2: handle unbound ports commit 9715a43eea77e42678a1002623f2d9a78f5b81a1 upstream. Check for NULL port data in the modem- and line-status handlers to avoid dereferencing a NULL pointer in the unlikely case where a port device isn't bound to a driver (e.g. after an allocation failure on port probe). Note that the other (stubbed) event handlers qt2_process_xmit_empty() and qt2_process_flush() would need similar sanity checks in case they are ever implemented. Fixes: f7a33e608d9a ("USB: serial: add quatech2 usb to serial driver") Cc: stable # 3.5 Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/quatech2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 60e17d1444c3..f16e0b8c1ed4 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -867,7 +867,10 @@ static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch) u8 newMSR = (u8) *ch; unsigned long flags; + /* May be called from qt2_process_read_urb() for an unbound port. */ port_priv = usb_get_serial_port_data(port); + if (!port_priv) + return; spin_lock_irqsave(&port_priv->lock, flags); port_priv->shadowMSR = newMSR; @@ -895,7 +898,10 @@ static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch) unsigned long flags; u8 newLSR = (u8) *ch; + /* May be called from qt2_process_read_urb() for an unbound port. */ port_priv = usb_get_serial_port_data(port); + if (!port_priv) + return; if (newLSR & UART_LSR_BI) newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI); -- GitLab From f250729c0385b4371cb6bf33c6ff48e942b3baa0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 7 Jan 2020 21:15:49 +0100 Subject: [PATCH 0233/1055] scsi: fnic: fix invalid stack access commit 42ec15ceaea74b5f7a621fc6686cbf69ca66c4cf upstream. gcc -O3 warns that some local variables are not properly initialized: drivers/scsi/fnic/vnic_dev.c: In function 'fnic_dev_hang_notify': drivers/scsi/fnic/vnic_dev.c:511:16: error: 'a0' is used uninitialized in this function [-Werror=uninitialized] vdev->args[0] = *a0; ~~~~~~~~~~~~~~^~~~~ drivers/scsi/fnic/vnic_dev.c:691:6: note: 'a0' was declared here u64 a0, a1; ^~ drivers/scsi/fnic/vnic_dev.c:512:16: error: 'a1' is used uninitialized in this function [-Werror=uninitialized] vdev->args[1] = *a1; ~~~~~~~~~~~~~~^~~~~ drivers/scsi/fnic/vnic_dev.c:691:10: note: 'a1' was declared here u64 a0, a1; ^~ drivers/scsi/fnic/vnic_dev.c: In function 'fnic_dev_mac_addr': drivers/scsi/fnic/vnic_dev.c:512:16: error: 'a1' is used uninitialized in this function [-Werror=uninitialized] vdev->args[1] = *a1; ~~~~~~~~~~~~~~^~~~~ drivers/scsi/fnic/vnic_dev.c:698:10: note: 'a1' was declared here u64 a0, a1; ^~ Apparently the code relies on the local variables occupying adjacent memory locations in the same order, but this is of course not guaranteed. Use an array of two u64 variables where needed to make it work correctly. I suspect there is also an endianness bug here, but have not digged in deep enough to be sure. Fixes: 5df6d737dd4b ("[SCSI] fnic: Add new Cisco PCI-Express FCoE HBA") Fixes: mmtom ("init/Kconfig: enable -O3 for all arches") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20200107201602.4096790-1-arnd@arndb.de Signed-off-by: Arnd Bergmann Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/fnic/vnic_dev.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/fnic/vnic_dev.c b/drivers/scsi/fnic/vnic_dev.c index ba69d6112fa1..c5b89a003d2a 100644 --- a/drivers/scsi/fnic/vnic_dev.c +++ b/drivers/scsi/fnic/vnic_dev.c @@ -445,26 +445,26 @@ int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done) int vnic_dev_hang_notify(struct vnic_dev *vdev) { - u64 a0, a1; + u64 a0 = 0, a1 = 0; int wait = 1000; return vnic_dev_cmd(vdev, CMD_HANG_NOTIFY, &a0, &a1, wait); } int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr) { - u64 a0, a1; + u64 a[2] = {}; int wait = 1000; int err, i; for (i = 0; i < ETH_ALEN; i++) mac_addr[i] = 0; - err = vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait); + err = vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a[0], &a[1], wait); if (err) return err; for (i = 0; i < ETH_ALEN; i++) - mac_addr[i] = ((u8 *)&a0)[i]; + mac_addr[i] = ((u8 *)&a)[i]; return 0; } @@ -489,30 +489,30 @@ void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) { - u64 a0 = 0, a1 = 0; + u64 a[2] = {}; int wait = 1000; int err; int i; for (i = 0; i < ETH_ALEN; i++) - ((u8 *)&a0)[i] = addr[i]; + ((u8 *)&a)[i] = addr[i]; - err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); + err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a[0], &a[1], wait); if (err) pr_err("Can't add addr [%pM], %d\n", addr, err); } void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) { - u64 a0 = 0, a1 = 0; + u64 a[2] = {}; int wait = 1000; int err; int i; for (i = 0; i < ETH_ALEN; i++) - ((u8 *)&a0)[i] = addr[i]; + ((u8 *)&a)[i] = addr[i]; - err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait); + err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a[0], &a[1], wait); if (err) pr_err("Can't del addr [%pM], %d\n", addr, err); } -- GitLab From fedf64ea8f461ac51d9772998b277a30cbf8375e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 14 Jan 2020 15:34:14 +0300 Subject: [PATCH 0234/1055] scsi: mptfusion: Fix double fetch bug in ioctl commit 28d76df18f0ad5bcf5fa48510b225f0ed262a99b upstream. Tom Hatskevich reported that we look up "iocp" then, in the called functions we do a second copy_from_user() and look it up again. The problem that could cause is: drivers/message/fusion/mptctl.c 674 /* All of these commands require an interrupt or 675 * are unknown/illegal. 676 */ 677 if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) ^^^^ We take this lock. 678 return ret; 679 680 if (cmd == MPTFWDOWNLOAD) 681 ret = mptctl_fw_download(arg); ^^^ Then the user memory changes and we look up "iocp" again but a different one so now we are holding the incorrect lock and have a race condition. 682 else if (cmd == MPTCOMMAND) 683 ret = mptctl_mpt_command(arg); The security impact of this bug is not as bad as it could have been because these operations are all privileged and root already has enormous destructive power. But it's still worth fixing. This patch passes the "iocp" pointer to the functions to avoid the second lookup. That deletes 100 lines of code from the driver so it's a nice clean up as well. Link: https://lore.kernel.org/r/20200114123414.GA7957@kadam Reported-by: Tom Hatskevich Reviewed-by: Greg Kroah-Hartman Signed-off-by: Dan Carpenter Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/message/fusion/mptctl.c | 213 ++++++++------------------------ 1 file changed, 50 insertions(+), 163 deletions(-) diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index cf6ce9f600ca..f9b2e652c399 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -100,19 +100,19 @@ struct buflist { * Function prototypes. Called from OS entry point mptctl_ioctl. * arg contents specific to function. */ -static int mptctl_fw_download(unsigned long arg); -static int mptctl_getiocinfo(unsigned long arg, unsigned int cmd); -static int mptctl_gettargetinfo(unsigned long arg); -static int mptctl_readtest(unsigned long arg); -static int mptctl_mpt_command(unsigned long arg); -static int mptctl_eventquery(unsigned long arg); -static int mptctl_eventenable(unsigned long arg); -static int mptctl_eventreport(unsigned long arg); -static int mptctl_replace_fw(unsigned long arg); - -static int mptctl_do_reset(unsigned long arg); -static int mptctl_hp_hostinfo(unsigned long arg, unsigned int cmd); -static int mptctl_hp_targetinfo(unsigned long arg); +static int mptctl_fw_download(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_getiocinfo(MPT_ADAPTER *iocp, unsigned long arg, unsigned int cmd); +static int mptctl_gettargetinfo(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_readtest(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_mpt_command(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_eventquery(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_eventenable(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_eventreport(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_replace_fw(MPT_ADAPTER *iocp, unsigned long arg); + +static int mptctl_do_reset(MPT_ADAPTER *iocp, unsigned long arg); +static int mptctl_hp_hostinfo(MPT_ADAPTER *iocp, unsigned long arg, unsigned int cmd); +static int mptctl_hp_targetinfo(MPT_ADAPTER *iocp, unsigned long arg); static int mptctl_probe(struct pci_dev *, const struct pci_device_id *); static void mptctl_remove(struct pci_dev *); @@ -123,8 +123,8 @@ static long compat_mpctl_ioctl(struct file *f, unsigned cmd, unsigned long arg); /* * Private function calls. */ -static int mptctl_do_mpt_command(struct mpt_ioctl_command karg, void __user *mfPtr); -static int mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen); +static int mptctl_do_mpt_command(MPT_ADAPTER *iocp, struct mpt_ioctl_command karg, void __user *mfPtr); +static int mptctl_do_fw_download(MPT_ADAPTER *iocp, char __user *ufwbuf, size_t fwlen); static MptSge_t *kbuf_alloc_2_sgl(int bytes, u32 dir, int sge_offset, int *frags, struct buflist **blp, dma_addr_t *sglbuf_dma, MPT_ADAPTER *ioc); static void kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, @@ -656,19 +656,19 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) * by TM and FW reloads. */ if ((cmd & ~IOCSIZE_MASK) == (MPTIOCINFO & ~IOCSIZE_MASK)) { - return mptctl_getiocinfo(arg, _IOC_SIZE(cmd)); + return mptctl_getiocinfo(iocp, arg, _IOC_SIZE(cmd)); } else if (cmd == MPTTARGETINFO) { - return mptctl_gettargetinfo(arg); + return mptctl_gettargetinfo(iocp, arg); } else if (cmd == MPTTEST) { - return mptctl_readtest(arg); + return mptctl_readtest(iocp, arg); } else if (cmd == MPTEVENTQUERY) { - return mptctl_eventquery(arg); + return mptctl_eventquery(iocp, arg); } else if (cmd == MPTEVENTENABLE) { - return mptctl_eventenable(arg); + return mptctl_eventenable(iocp, arg); } else if (cmd == MPTEVENTREPORT) { - return mptctl_eventreport(arg); + return mptctl_eventreport(iocp, arg); } else if (cmd == MPTFWREPLACE) { - return mptctl_replace_fw(arg); + return mptctl_replace_fw(iocp, arg); } /* All of these commands require an interrupt or @@ -678,15 +678,15 @@ __mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return ret; if (cmd == MPTFWDOWNLOAD) - ret = mptctl_fw_download(arg); + ret = mptctl_fw_download(iocp, arg); else if (cmd == MPTCOMMAND) - ret = mptctl_mpt_command(arg); + ret = mptctl_mpt_command(iocp, arg); else if (cmd == MPTHARDRESET) - ret = mptctl_do_reset(arg); + ret = mptctl_do_reset(iocp, arg); else if ((cmd & ~IOCSIZE_MASK) == (HP_GETHOSTINFO & ~IOCSIZE_MASK)) - ret = mptctl_hp_hostinfo(arg, _IOC_SIZE(cmd)); + ret = mptctl_hp_hostinfo(iocp, arg, _IOC_SIZE(cmd)); else if (cmd == HP_GETTARGETINFO) - ret = mptctl_hp_targetinfo(arg); + ret = mptctl_hp_targetinfo(iocp, arg); else ret = -EINVAL; @@ -705,11 +705,10 @@ mptctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return ret; } -static int mptctl_do_reset(unsigned long arg) +static int mptctl_do_reset(MPT_ADAPTER *iocp, unsigned long arg) { struct mpt_ioctl_diag_reset __user *urinfo = (void __user *) arg; struct mpt_ioctl_diag_reset krinfo; - MPT_ADAPTER *iocp; if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) { printk(KERN_ERR MYNAM "%s@%d::mptctl_do_reset - " @@ -718,12 +717,6 @@ static int mptctl_do_reset(unsigned long arg) return -EFAULT; } - if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) { - printk(KERN_DEBUG MYNAM "%s@%d::mptctl_do_reset - ioc%d not found!\n", - __FILE__, __LINE__, krinfo.hdr.iocnum); - return -ENODEV; /* (-6) No such device or address */ - } - dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "mptctl_do_reset called.\n", iocp->name)); @@ -754,7 +747,7 @@ static int mptctl_do_reset(unsigned long arg) * -ENOMSG if FW upload returned bad status */ static int -mptctl_fw_download(unsigned long arg) +mptctl_fw_download(MPT_ADAPTER *iocp, unsigned long arg) { struct mpt_fw_xfer __user *ufwdl = (void __user *) arg; struct mpt_fw_xfer kfwdl; @@ -766,7 +759,7 @@ mptctl_fw_download(unsigned long arg) return -EFAULT; } - return mptctl_do_fw_download(kfwdl.iocnum, kfwdl.bufp, kfwdl.fwlen); + return mptctl_do_fw_download(iocp, kfwdl.bufp, kfwdl.fwlen); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -784,11 +777,10 @@ mptctl_fw_download(unsigned long arg) * -ENOMSG if FW upload returned bad status */ static int -mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) +mptctl_do_fw_download(MPT_ADAPTER *iocp, char __user *ufwbuf, size_t fwlen) { FWDownload_t *dlmsg; MPT_FRAME_HDR *mf; - MPT_ADAPTER *iocp; FWDownloadTCSGE_t *ptsge; MptSge_t *sgl, *sgIn; char *sgOut; @@ -808,17 +800,10 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) pFWDownloadReply_t ReplyMsg = NULL; unsigned long timeleft; - if (mpt_verify_adapter(ioc, &iocp) < 0) { - printk(KERN_DEBUG MYNAM "ioctl_fwdl - ioc%d not found!\n", - ioc); - return -ENODEV; /* (-6) No such device or address */ - } else { - - /* Valid device. Get a message frame and construct the FW download message. - */ - if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL) - return -EAGAIN; - } + /* Valid device. Get a message frame and construct the FW download message. + */ + if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL) + return -EAGAIN; dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "mptctl_do_fwdl called. mptctl_id = %xh.\n", iocp->name, mptctl_id)); @@ -826,8 +811,6 @@ mptctl_do_fw_download(int ioc, char __user *ufwbuf, size_t fwlen) iocp->name, ufwbuf)); dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.fwlen = %d\n", iocp->name, (int)fwlen)); - dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.ioc = %04xh\n", - iocp->name, ioc)); dlmsg = (FWDownload_t*) mf; ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL; @@ -1238,13 +1221,11 @@ kfree_sgl(MptSge_t *sgl, dma_addr_t sgl_dma, struct buflist *buflist, MPT_ADAPTE * -ENODEV if no such device/adapter */ static int -mptctl_getiocinfo (unsigned long arg, unsigned int data_size) +mptctl_getiocinfo (MPT_ADAPTER *ioc, unsigned long arg, unsigned int data_size) { struct mpt_ioctl_iocinfo __user *uarg = (void __user *) arg; struct mpt_ioctl_iocinfo *karg; - MPT_ADAPTER *ioc; struct pci_dev *pdev; - int iocnum; unsigned int port; int cim_rev; struct scsi_device *sdev; @@ -1272,14 +1253,6 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) return PTR_ERR(karg); } - if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - kfree(karg); - return -ENODEV; - } - /* Verify the data transfer size is correct. */ if (karg->hdr.maxDataSize != data_size) { printk(MYIOC_s_ERR_FMT "%s@%d::mptctl_getiocinfo - " @@ -1385,15 +1358,13 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) * -ENODEV if no such device/adapter */ static int -mptctl_gettargetinfo (unsigned long arg) +mptctl_gettargetinfo (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_targetinfo __user *uarg = (void __user *) arg; struct mpt_ioctl_targetinfo karg; - MPT_ADAPTER *ioc; VirtDevice *vdevice; char *pmem; int *pdata; - int iocnum; int numDevices = 0; int lun; int maxWordsLeft; @@ -1408,13 +1379,6 @@ mptctl_gettargetinfo (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_gettargetinfo called.\n", ioc->name)); /* Get the port number and set the maximum number of bytes @@ -1510,12 +1474,10 @@ mptctl_gettargetinfo (unsigned long arg) * -ENODEV if no such device/adapter */ static int -mptctl_readtest (unsigned long arg) +mptctl_readtest (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_test __user *uarg = (void __user *) arg; struct mpt_ioctl_test karg; - MPT_ADAPTER *ioc; - int iocnum; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) { printk(KERN_ERR MYNAM "%s@%d::mptctl_readtest - " @@ -1524,13 +1486,6 @@ mptctl_readtest (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_readtest() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_readtest called.\n", ioc->name)); /* Fill in the data and return the structure to the calling @@ -1571,12 +1526,10 @@ mptctl_readtest (unsigned long arg) * -ENODEV if no such device/adapter */ static int -mptctl_eventquery (unsigned long arg) +mptctl_eventquery (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_eventquery __user *uarg = (void __user *) arg; struct mpt_ioctl_eventquery karg; - MPT_ADAPTER *ioc; - int iocnum; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) { printk(KERN_ERR MYNAM "%s@%d::mptctl_eventquery - " @@ -1585,13 +1538,6 @@ mptctl_eventquery (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_eventquery() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventquery called.\n", ioc->name)); karg.eventEntries = MPTCTL_EVENT_LOG_SIZE; @@ -1610,12 +1556,10 @@ mptctl_eventquery (unsigned long arg) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int -mptctl_eventenable (unsigned long arg) +mptctl_eventenable (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_eventenable __user *uarg = (void __user *) arg; struct mpt_ioctl_eventenable karg; - MPT_ADAPTER *ioc; - int iocnum; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) { printk(KERN_ERR MYNAM "%s@%d::mptctl_eventenable - " @@ -1624,13 +1568,6 @@ mptctl_eventenable (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_eventenable() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventenable called.\n", ioc->name)); if (ioc->events == NULL) { @@ -1658,12 +1595,10 @@ mptctl_eventenable (unsigned long arg) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int -mptctl_eventreport (unsigned long arg) +mptctl_eventreport (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_eventreport __user *uarg = (void __user *) arg; struct mpt_ioctl_eventreport karg; - MPT_ADAPTER *ioc; - int iocnum; int numBytes, maxEvents, max; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) { @@ -1673,12 +1608,6 @@ mptctl_eventreport (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_eventreport() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n", ioc->name)); @@ -1712,12 +1641,10 @@ mptctl_eventreport (unsigned long arg) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int -mptctl_replace_fw (unsigned long arg) +mptctl_replace_fw (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_replace_fw __user *uarg = (void __user *) arg; struct mpt_ioctl_replace_fw karg; - MPT_ADAPTER *ioc; - int iocnum; int newFwSize; if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) { @@ -1727,13 +1654,6 @@ mptctl_replace_fw (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_replace_fw() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_replace_fw called.\n", ioc->name)); /* If caching FW, Free the old FW image @@ -1780,12 +1700,10 @@ mptctl_replace_fw (unsigned long arg) * -ENOMEM if memory allocation error */ static int -mptctl_mpt_command (unsigned long arg) +mptctl_mpt_command (MPT_ADAPTER *ioc, unsigned long arg) { struct mpt_ioctl_command __user *uarg = (void __user *) arg; struct mpt_ioctl_command karg; - MPT_ADAPTER *ioc; - int iocnum; int rc; @@ -1796,14 +1714,7 @@ mptctl_mpt_command (unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_mpt_command() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - - rc = mptctl_do_mpt_command (karg, &uarg->MF); + rc = mptctl_do_mpt_command (ioc, karg, &uarg->MF); return rc; } @@ -1821,9 +1732,8 @@ mptctl_mpt_command (unsigned long arg) * -EPERM if SCSI I/O and target is untagged */ static int -mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) +mptctl_do_mpt_command (MPT_ADAPTER *ioc, struct mpt_ioctl_command karg, void __user *mfPtr) { - MPT_ADAPTER *ioc; MPT_FRAME_HDR *mf = NULL; MPIHeader_t *hdr; char *psge; @@ -1832,7 +1742,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) dma_addr_t dma_addr_in; dma_addr_t dma_addr_out; int sgSize = 0; /* Num SG elements */ - int iocnum, flagsLength; + int flagsLength; int sz, rc = 0; int msgContext; u16 req_idx; @@ -1847,13 +1757,6 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) bufIn.kptr = bufOut.kptr = NULL; bufIn.len = bufOut.len = 0; - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } - spin_lock_irqsave(&ioc->taskmgmt_lock, flags); if (ioc->ioc_reset_in_progress) { spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); @@ -2418,17 +2321,15 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) * -ENOMEM if memory allocation error */ static int -mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) +mptctl_hp_hostinfo(MPT_ADAPTER *ioc, unsigned long arg, unsigned int data_size) { hp_host_info_t __user *uarg = (void __user *) arg; - MPT_ADAPTER *ioc; struct pci_dev *pdev; char *pbuf=NULL; dma_addr_t buf_dma; hp_host_info_t karg; CONFIGPARMS cfg; ConfigPageHeader_t hdr; - int iocnum; int rc, cim_rev; ToolboxIstwiReadWriteRequest_t *IstwiRWRequest; MPT_FRAME_HDR *mf = NULL; @@ -2452,12 +2353,6 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n", ioc->name)); @@ -2670,15 +2565,13 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) * -ENOMEM if memory allocation error */ static int -mptctl_hp_targetinfo(unsigned long arg) +mptctl_hp_targetinfo(MPT_ADAPTER *ioc, unsigned long arg) { hp_target_info_t __user *uarg = (void __user *) arg; SCSIDevicePage0_t *pg0_alloc; SCSIDevicePage3_t *pg3_alloc; - MPT_ADAPTER *ioc; MPT_SCSI_HOST *hd = NULL; hp_target_info_t karg; - int iocnum; int data_sz; dma_addr_t page_dma; CONFIGPARMS cfg; @@ -2692,12 +2585,6 @@ mptctl_hp_targetinfo(unsigned long arg) return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || - (ioc == NULL)) { - printk(KERN_DEBUG MYNAM "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum); - return -ENODEV; - } if (karg.hdr.id >= MPT_MAX_FC_DEVICES) return -EINVAL; dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n", @@ -2865,7 +2752,7 @@ compat_mptfwxfer_ioctl(struct file *filp, unsigned int cmd, kfw.fwlen = kfw32.fwlen; kfw.bufp = compat_ptr(kfw32.bufp); - ret = mptctl_do_fw_download(kfw.iocnum, kfw.bufp, kfw.fwlen); + ret = mptctl_do_fw_download(iocp, kfw.bufp, kfw.fwlen); mutex_unlock(&iocp->ioctl_cmds.mutex); @@ -2919,7 +2806,7 @@ compat_mpt_command(struct file *filp, unsigned int cmd, /* Pass new structure to do_mpt_command */ - ret = mptctl_do_mpt_command (karg, &uarg->MF); + ret = mptctl_do_mpt_command (iocp, karg, &uarg->MF); mutex_unlock(&iocp->ioctl_cmds.mutex); -- GitLab From f8812ddea4ea3b8a6ee5e4b9fb2333da7ee4022c Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 15 Jan 2020 14:42:34 +0100 Subject: [PATCH 0235/1055] ptrace: reintroduce usage of subjective credentials in ptrace_has_cap() commit 6b3ad6649a4c75504edeba242d3fd36b3096a57f upstream. Commit 69f594a38967 ("ptrace: do not audit capability check when outputing /proc/pid/stat") introduced the ability to opt out of audit messages for accesses to various proc files since they are not violations of policy. While doing so it somehow switched the check from ns_capable() to has_ns_capability{_noaudit}(). That means it switched from checking the subjective credentials of the task to using the objective credentials. This is wrong since. ptrace_has_cap() is currently only used in ptrace_may_access() And is used to check whether the calling task (subject) has the CAP_SYS_PTRACE capability in the provided user namespace to operate on the target task (object). According to the cred.h comments this would mean the subjective credentials of the calling task need to be used. This switches ptrace_has_cap() to use security_capable(). Because we only call ptrace_has_cap() in ptrace_may_access() and in there we already have a stable reference to the calling task's creds under rcu_read_lock() there's no need to go through another series of dereferences and rcu locking done in ns_capable{_noaudit}(). As one example where this might be particularly problematic, Jann pointed out that in combination with the upcoming IORING_OP_OPENAT feature, this bug might allow unprivileged users to bypass the capability checks while asynchronously opening files like /proc/*/mem, because the capability checks for this would be performed against kernel credentials. To illustrate on the former point about this being exploitable: When io_uring creates a new context it records the subjective credentials of the caller. Later on, when it starts to do work it creates a kernel thread and registers a callback. The callback runs with kernel creds for ktask->real_cred and ktask->cred. To prevent this from becoming a full-blown 0-day io_uring will call override_cred() and override ktask->cred with the subjective credentials of the creator of the io_uring instance. With ptrace_has_cap() currently looking at ktask->real_cred this override will be ineffective and the caller will be able to open arbitray proc files as mentioned above. Luckily, this is currently not exploitable but will turn into a 0-day once IORING_OP_OPENAT{2} land in v5.6. Fix it now! Cc: Oleg Nesterov Cc: Eric Paris Cc: stable@vger.kernel.org Reviewed-by: Kees Cook Reviewed-by: Serge Hallyn Reviewed-by: Jann Horn Fixes: 69f594a38967 ("ptrace: do not audit capability check when outputing /proc/pid/stat") Signed-off-by: Christian Brauner Signed-off-by: Greg Kroah-Hartman --- kernel/ptrace.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 09fb3f58a838..43a283041296 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -258,12 +258,17 @@ static int ptrace_check_attach(struct task_struct *child, bool ignore_state) return ret; } -static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) +static bool ptrace_has_cap(const struct cred *cred, struct user_namespace *ns, + unsigned int mode) { + int ret; + if (mode & PTRACE_MODE_NOAUDIT) - return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE); + ret = security_capable(cred, ns, CAP_SYS_PTRACE); else - return has_ns_capability(current, ns, CAP_SYS_PTRACE); + ret = security_capable(cred, ns, CAP_SYS_PTRACE); + + return ret == 0; } /* Returns 0 on success, -errno on denial. */ @@ -315,7 +320,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) gid_eq(caller_gid, tcred->sgid) && gid_eq(caller_gid, tcred->gid)) goto ok; - if (ptrace_has_cap(tcred->user_ns, mode)) + if (ptrace_has_cap(cred, tcred->user_ns, mode)) goto ok; rcu_read_unlock(); return -EPERM; @@ -334,7 +339,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) mm = task->mm; if (mm && ((get_dumpable(mm) != SUID_DUMP_USER) && - !ptrace_has_cap(mm->user_ns, mode))) + !ptrace_has_cap(cred, mm->user_ns, mode))) return -EPERM; return security_ptrace_access_check(task, mode); -- GitLab From cd20d0e31c63f8c5ac1dbcb57b96a757c0dd56cd Mon Sep 17 00:00:00 2001 From: Keiya Nobuta Date: Thu, 9 Jan 2020 14:14:48 +0900 Subject: [PATCH 0236/1055] usb: core: hub: Improved device recognition on remote wakeup commit 9c06ac4c83df6d6fbdbf7488fbad822b4002ba19 upstream. If hub_activate() is called before D+ has stabilized after remote wakeup, the following situation might occur: __ ___________________ / \ / D+ __/ \__/ Hub _______________________________ | ^ ^ ^ | | | | Host _____v__|___|___________|______ | | | | | | | \-- Interrupt Transfer (*3) | | \-- ClearPortFeature (*2) | \-- GetPortStatus (*1) \-- Host detects remote wakeup - D+ goes high, Host starts running by remote wakeup - D+ is not stable, goes low - Host requests GetPortStatus at (*1) and gets the following hub status: - Current Connect Status bit is 0 - Connect Status Change bit is 1 - D+ stabilizes, goes high - Host requests ClearPortFeature and thus Connect Status Change bit is cleared at (*2) - After waiting 100 ms, Host starts the Interrupt Transfer at (*3) - Since the Connect Status Change bit is 0, Hub returns NAK. In this case, port_event() is not called in hub_event() and Host cannot recognize device. To solve this issue, flag change_bits even if only Connect Status Change bit is 1 when got in the first GetPortStatus. This issue occurs rarely because it only if D+ changes during a very short time between GetPortStatus and ClearPortFeature. However, it is fatal if it occurs in embedded system. Signed-off-by: Keiya Nobuta Cc: stable Acked-by: Alan Stern Link: https://lore.kernel.org/r/20200109051448.28150-1-nobuta.keiya@fujitsu.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 4efccf8bf99f..7d5ecf36a33c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1164,6 +1164,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) * PORT_OVER_CURRENT is not. So check for any of them. */ if (udev || (portstatus & USB_PORT_STAT_CONNECTION) || + (portchange & USB_PORT_STAT_C_CONNECTION) || (portstatus & USB_PORT_STAT_OVERCURRENT) || (portchange & USB_PORT_STAT_C_OVERCURRENT)) set_bit(port1, hub->change_bits); -- GitLab From bf76318ed06c298d8464923dce81edf6ef349931 Mon Sep 17 00:00:00 2001 From: Qian Cai Date: Tue, 10 Dec 2019 22:30:42 -0500 Subject: [PATCH 0237/1055] x86/resctrl: Fix an imbalance in domain_remove_cpu() commit e278af89f1ba0a9ef20947db6afc2c9afa37e85b upstream. A system that supports resource monitoring may have multiple resources while not all of these resources are capable of monitoring. Monitoring related state is initialized only for resources that are capable of monitoring and correspondingly this state should subsequently only be removed from these resources that are capable of monitoring. domain_add_cpu() calls domain_setup_mon_state() only when r->mon_capable is true where it will initialize d->mbm_over. However, domain_remove_cpu() calls cancel_delayed_work(&d->mbm_over) without checking r->mon_capable resulting in an attempt to cancel d->mbm_over on all resources, even those that never initialized d->mbm_over because they are not capable of monitoring. Hence, it triggers a debugobjects warning when offlining CPUs because those timer debugobjects are never initialized: ODEBUG: assert_init not available (active state 0) object type: timer_list hint: 0x0 WARNING: CPU: 143 PID: 789 at lib/debugobjects.c:484 debug_print_object Hardware name: HP Synergy 680 Gen9/Synergy 680 Gen9 Compute Module, BIOS I40 05/23/2018 RIP: 0010:debug_print_object Call Trace: debug_object_assert_init del_timer try_to_grab_pending cancel_delayed_work resctrl_offline_cpu cpuhp_invoke_callback cpuhp_thread_fun smpboot_thread_fn kthread ret_from_fork Fixes: e33026831bdb ("x86/intel_rdt/mbm: Handle counter overflow") Signed-off-by: Qian Cai Signed-off-by: Borislav Petkov Acked-by: Reinette Chatre Cc: Fenghua Yu Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: john.stultz@linaro.org Cc: sboyd@kernel.org Cc: Cc: Thomas Gleixner Cc: tj@kernel.org Cc: Tony Luck Cc: Vikas Shivappa Cc: x86-ml Link: https://lkml.kernel.org/r/20191211033042.2188-1-cai@lca.pw Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/intel_rdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/intel_rdt.c b/arch/x86/kernel/cpu/intel_rdt.c index 665d0f6cd62f..3f731d7f04bf 100644 --- a/arch/x86/kernel/cpu/intel_rdt.c +++ b/arch/x86/kernel/cpu/intel_rdt.c @@ -526,7 +526,7 @@ static void domain_remove_cpu(int cpu, struct rdt_resource *r) if (static_branch_unlikely(&rdt_mon_enable_key)) rmdir_mondata_subdir_allrdtgrp(r, d->id); list_del(&d->list); - if (is_mbm_enabled()) + if (r->mon_capable && is_mbm_enabled()) cancel_delayed_work(&d->mbm_over); if (is_llc_occupancy_enabled() && has_busy_rmid(r, d)) { /* -- GitLab From 991ef5ce9b4e3e87c9008744d58ba42ba70ab638 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 24 Dec 2019 14:29:09 +0100 Subject: [PATCH 0238/1055] x86/efistub: Disable paging at mixed mode entry commit 4911ee401b7ceff8f38e0ac597cbf503d71e690c upstream. The EFI mixed mode entry code goes through the ordinary startup_32() routine before jumping into the kernel's EFI boot code in 64-bit mode. The 32-bit startup code must be entered with paging disabled, but this is not documented as a requirement for the EFI handover protocol, and so we should disable paging explicitly when entering the kernel from 32-bit EFI firmware. Signed-off-by: Ard Biesheuvel Cc: Cc: Arvind Sankar Cc: Hans de Goede Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: https://lkml.kernel.org/r/20191224132909.102540-4-ardb@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/boot/compressed/head_64.S | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index 4b3d92a37c80..39fdede523f2 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -227,6 +227,11 @@ ENTRY(efi32_stub_entry) leal efi32_config(%ebp), %eax movl %eax, efi_config(%ebp) + /* Disable paging */ + movl %cr0, %eax + btrl $X86_CR0_PG_BIT, %eax + movl %eax, %cr0 + jmp startup_32 ENDPROC(efi32_stub_entry) #endif -- GitLab From 14f820498a133d729a5782d4e502baa589cb2194 Mon Sep 17 00:00:00 2001 From: Yuya Fujita Date: Thu, 19 Dec 2019 08:08:32 +0000 Subject: [PATCH 0239/1055] perf hists: Fix variable name's inconsistency in hists__for_each() macro commit 55347ec340af401437680fd0e88df6739a967f9f upstream. Variable names are inconsistent in hists__for_each macro(). Due to this inconsistency, the macro replaces its second argument with "fmt" regardless of its original name. So far it works because only "fmt" is passed to the second argument. However, this behavior is not expected and should be fixed. Fixes: f0786af536bb ("perf hists: Introduce hists__for_each_format macro") Fixes: aa6f50af822a ("perf hists: Introduce hists__for_each_sort_list macro") Signed-off-by: Yuya Fujita Acked-by: Jiri Olsa Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/OSAPR01MB1588E1C47AC22043175DE1B2E8520@OSAPR01MB1588.jpnprd01.prod.outlook.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/hist.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index b99d68943f25..595f91f46811 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -317,10 +317,10 @@ static inline void perf_hpp__prepend_sort_field(struct perf_hpp_fmt *format) list_for_each_entry_safe(format, tmp, &(_list)->sorts, sort_list) #define hists__for_each_format(hists, format) \ - perf_hpp_list__for_each_format((hists)->hpp_list, fmt) + perf_hpp_list__for_each_format((hists)->hpp_list, format) #define hists__for_each_sort_list(hists, format) \ - perf_hpp_list__for_each_sort_list((hists)->hpp_list, fmt) + perf_hpp_list__for_each_sort_list((hists)->hpp_list, format) extern struct perf_hpp_fmt perf_hpp__format[]; -- GitLab From 8ce84610f581ef104a8f274b50bc775599bbb446 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Fri, 20 Dec 2019 09:37:19 +0800 Subject: [PATCH 0240/1055] perf report: Fix incorrectly added dimensions as switch perf data file commit 0feba17bd7ee3b7e03d141f119049dcc23efa94e upstream. We observed an issue that was some extra columns displayed after switching perf data file in browser. The steps to reproduce: 1. perf record -a -e cycles,instructions -- sleep 3 2. perf report --group 3. In browser, we use hotkey 's' to switch to another perf.data 4. Now in browser, the extra columns 'Self' and 'Children' are displayed. The issue is setup_sorting() executed again after repeat path, so dimensions are added again. This patch checks the last key returned from __cmd_report(). If it's K_SWITCH_INPUT_DATA, skips the setup_sorting(). Fixes: ad0de0971b7f ("perf report: Enable the runtime switching of perf data file") Signed-off-by: Jin Yao Tested-by: Arnaldo Carvalho de Melo Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Feng Tang Cc: Jin Yao Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20191220013722.20592-1-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/builtin-report.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index fd4dd12b8f9d..17b26661b2f6 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -742,6 +742,7 @@ int cmd_report(int argc, const char **argv) struct stat st; bool has_br_stack = false; int branch_mode = -1; + int last_key = 0; bool branch_call_mode = false; char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT; const char * const report_usage[] = { @@ -1048,7 +1049,8 @@ int cmd_report(int argc, const char **argv) else use_browser = 0; - if (setup_sorting(session->evlist) < 0) { + if ((last_key != K_SWITCH_INPUT_DATA) && + (setup_sorting(session->evlist) < 0)) { if (sort_order) parse_options_usage(report_usage, options, "s", 1); if (field_order) @@ -1108,6 +1110,7 @@ int cmd_report(int argc, const char **argv) ret = __cmd_report(&report); if (ret == K_SWITCH_INPUT_DATA) { perf_session__delete(session); + last_key = K_SWITCH_INPUT_DATA; goto repeat; } else ret = 0; -- GitLab From ccf53a8db73c58b1a8135ef5ea9eb99680c77a08 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Mon, 13 Jan 2020 16:29:13 -0800 Subject: [PATCH 0241/1055] mm/shmem.c: thp, shmem: fix conflict of above-47bit hint address and PMD alignment commit 991589974d9c9ecb24ee3799ec8c415c730598a2 upstream. Shmem/tmpfs tries to provide THP-friendly mappings if huge pages are enabled. But it doesn't work well with above-47bit hint address. Normally, the kernel doesn't create userspace mappings above 47-bit, even if the machine allows this (such as with 5-level paging on x86-64). Not all user space is ready to handle wide addresses. It's known that at least some JIT compilers use higher bits in pointers to encode their information. Userspace can ask for allocation from full address space by specifying hint address (with or without MAP_FIXED) above 47-bits. If the application doesn't need a particular address, but wants to allocate from whole address space it can specify -1 as a hint address. Unfortunately, this trick breaks THP alignment in shmem/tmp: shmem_get_unmapped_area() would not try to allocate PMD-aligned area if *any* hint address specified. This can be fixed by requesting the aligned area if the we failed to allocated at user-specified hint address. The request with inflated length will also take the user-specified hint address. This way we will not lose an allocation request from the full address space. [kirill@shutemov.name: fold in a fixup] Link: http://lkml.kernel.org/r/20191223231309.t6bh5hkbmokihpfu@box Link: http://lkml.kernel.org/r/20191220142548.7118-3-kirill.shutemov@linux.intel.com Fixes: b569bab78d8d ("x86/mm: Prepare to expose larger address space to userspace") Signed-off-by: Kirill A. Shutemov Cc: "Willhalm, Thomas" Cc: Dan Williams Cc: "Bruggeman, Otto G" Cc: "Aneesh Kumar K . V" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/shmem.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mm/shmem.c b/mm/shmem.c index 69106c600692..0b6db162083c 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2052,9 +2052,10 @@ unsigned long shmem_get_unmapped_area(struct file *file, /* * Our priority is to support MAP_SHARED mapped hugely; * and support MAP_PRIVATE mapped hugely too, until it is COWed. - * But if caller specified an address hint, respect that as before. + * But if caller specified an address hint and we allocated area there + * successfully, respect that as before. */ - if (uaddr) + if (uaddr == addr) return addr; if (shmem_huge != SHMEM_HUGE_FORCE) { @@ -2088,7 +2089,7 @@ unsigned long shmem_get_unmapped_area(struct file *file, if (inflated_len < len) return addr; - inflated_addr = get_area(NULL, 0, inflated_len, 0, flags); + inflated_addr = get_area(NULL, uaddr, inflated_len, 0, flags); if (IS_ERR_VALUE(inflated_addr)) return addr; if (inflated_addr & ~PAGE_MASK) -- GitLab From 90515d01c05eea9475e324a6e1605251606fee74 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Wed, 8 Jan 2020 21:07:32 +0900 Subject: [PATCH 0242/1055] btrfs: fix memory leak in qgroup accounting commit 26ef8493e1ab771cb01d27defca2fa1315dc3980 upstream. When running xfstests on the current btrfs I get the following splat from kmemleak: unreferenced object 0xffff88821b2404e0 (size 32): comm "kworker/u4:7", pid 26663, jiffies 4295283698 (age 8.776s) hex dump (first 32 bytes): 01 00 00 00 00 00 00 00 10 ff fd 26 82 88 ff ff ...........&.... 10 ff fd 26 82 88 ff ff 20 ff fd 26 82 88 ff ff ...&.... ..&.... backtrace: [<00000000f94fd43f>] ulist_alloc+0x25/0x60 [btrfs] [<00000000fd023d99>] btrfs_find_all_roots_safe+0x41/0x100 [btrfs] [<000000008f17bd32>] btrfs_find_all_roots+0x52/0x70 [btrfs] [<00000000b7660afb>] btrfs_qgroup_rescan_worker+0x343/0x680 [btrfs] [<0000000058e66778>] btrfs_work_helper+0xac/0x1e0 [btrfs] [<00000000f0188930>] process_one_work+0x1cf/0x350 [<00000000af5f2f8e>] worker_thread+0x28/0x3c0 [<00000000b55a1add>] kthread+0x109/0x120 [<00000000f88cbd17>] ret_from_fork+0x35/0x40 This corresponds to: (gdb) l *(btrfs_find_all_roots_safe+0x41) 0x8d7e1 is in btrfs_find_all_roots_safe (fs/btrfs/backref.c:1413). 1408 1409 tmp = ulist_alloc(GFP_NOFS); 1410 if (!tmp) 1411 return -ENOMEM; 1412 *roots = ulist_alloc(GFP_NOFS); 1413 if (!*roots) { 1414 ulist_free(tmp); 1415 return -ENOMEM; 1416 } 1417 Following the lifetime of the allocated 'roots' ulist, it gets freed again in btrfs_qgroup_account_extent(). But this does not happen if the function is called with the 'BTRFS_FS_QUOTA_ENABLED' flag cleared, then btrfs_qgroup_account_extent() does a short leave and directly returns. Instead of directly returning we should jump to the 'out_free' in order to free all resources as expected. CC: stable@vger.kernel.org # 4.14+ Reviewed-by: Qu Wenruo Signed-off-by: Johannes Thumshirn [ add comment ] Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/qgroup.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index cb6e8cb0de94..39a00b57ff01 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -1928,8 +1928,12 @@ btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 nr_old_roots = 0; int ret = 0; + /* + * If quotas get disabled meanwhile, the resouces need to be freed and + * we can't just exit here. + */ if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) - return 0; + goto out_free; if (new_roots) { if (!maybe_fs_roots(new_roots)) -- GitLab From 14dc0e8ee11b7a60e6517aee2e11b8d3162b1ce6 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Mon, 13 Jan 2020 16:29:23 -0800 Subject: [PATCH 0243/1055] mm/page-writeback.c: avoid potential division by zero in wb_min_max_ratio() commit 6d9e8c651dd979aa666bee15f086745f3ea9c4b3 upstream. Patch series "use div64_ul() instead of div_u64() if the divisor is unsigned long". We were first inspired by commit b0ab99e7736a ("sched: Fix possible divide by zero in avg_atom () calculation"), then refer to the recently analyzed mm code, we found this suspicious place. 201 if (min) { 202 min *= this_bw; 203 do_div(min, tot_bw); 204 } And we also disassembled and confirmed it: /usr/src/debug/kernel-4.9.168-016.ali3000/linux-4.9.168-016.ali3000.alios7.x86_64/mm/page-writeback.c: 201 0xffffffff811c37da <__wb_calc_thresh+234>: xor %r10d,%r10d 0xffffffff811c37dd <__wb_calc_thresh+237>: test %rax,%rax 0xffffffff811c37e0 <__wb_calc_thresh+240>: je 0xffffffff811c3800 <__wb_calc_thresh+272> /usr/src/debug/kernel-4.9.168-016.ali3000/linux-4.9.168-016.ali3000.alios7.x86_64/mm/page-writeback.c: 202 0xffffffff811c37e2 <__wb_calc_thresh+242>: imul %r8,%rax /usr/src/debug/kernel-4.9.168-016.ali3000/linux-4.9.168-016.ali3000.alios7.x86_64/mm/page-writeback.c: 203 0xffffffff811c37e6 <__wb_calc_thresh+246>: mov %r9d,%r10d ---> truncates it to 32 bits here 0xffffffff811c37e9 <__wb_calc_thresh+249>: xor %edx,%edx 0xffffffff811c37eb <__wb_calc_thresh+251>: div %r10 0xffffffff811c37ee <__wb_calc_thresh+254>: imul %rbx,%rax 0xffffffff811c37f2 <__wb_calc_thresh+258>: shr $0x2,%rax 0xffffffff811c37f6 <__wb_calc_thresh+262>: mul %rcx 0xffffffff811c37f9 <__wb_calc_thresh+265>: shr $0x2,%rdx 0xffffffff811c37fd <__wb_calc_thresh+269>: mov %rdx,%r10 This series uses div64_ul() instead of div_u64() if the divisor is unsigned long, to avoid truncation to 32-bit on 64-bit platforms. This patch (of 3): The variables 'min' and 'max' are unsigned long and do_div truncates them to 32 bits, which means it can test non-zero and be truncated to zero for division. Fix this issue by using div64_ul() instead. Link: http://lkml.kernel.org/r/20200102081442.8273-2-wenyang@linux.alibaba.com Fixes: 693108a8a667 ("writeback: make bdi->min/max_ratio handling cgroup writeback aware") Signed-off-by: Wen Yang Reviewed-by: Andrew Morton Cc: Qian Cai Cc: Tejun Heo Cc: Jens Axboe Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/page-writeback.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/page-writeback.c b/mm/page-writeback.c index a40c075fd8f1..29f9980c13ac 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -201,11 +201,11 @@ static void wb_min_max_ratio(struct bdi_writeback *wb, if (this_bw < tot_bw) { if (min) { min *= this_bw; - do_div(min, tot_bw); + min = div64_ul(min, tot_bw); } if (max < 100) { max *= this_bw; - do_div(max, tot_bw); + max = div64_ul(max, tot_bw); } } -- GitLab From 7e74b77cf84095e012c179952a4fc8b5689f1a75 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Wed, 18 Dec 2019 11:17:41 +0100 Subject: [PATCH 0244/1055] net: stmmac: 16KB buffer must be 16 byte aligned commit 8605131747e7e1fd8f6c9f97a00287aae2b2c640 upstream. The 16KB RX Buffer must also be 16 byte aligned. Fix it. Fixes: 7ac6653a085b ("stmmac: Move the STMicroelectronics driver") Signed-off-by: Jose Abreu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/stmicro/stmmac/common.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index efc4a1a8343a..e51b50d94074 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -338,9 +338,8 @@ struct dma_features { unsigned int rx_fifo_size; }; -/* GMAC TX FIFO is 8K, Rx FIFO is 16K */ -#define BUF_SIZE_16KiB 16384 -/* RX Buffer size must be < 8191 and multiple of 4/8/16 bytes */ +/* RX Buffer size must be multiple of 4/8/16 bytes */ +#define BUF_SIZE_16KiB 16368 #define BUF_SIZE_8KiB 8188 #define BUF_SIZE_4KiB 4096 #define BUF_SIZE_2KiB 2048 -- GitLab From 4a5bf2de396f1a310285cbcba59a3be0528140e3 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Wed, 18 Dec 2019 11:17:42 +0100 Subject: [PATCH 0245/1055] net: stmmac: Enable 16KB buffer size commit b2f3a481c4cd62f78391b836b64c0a6e72b503d2 upstream. XGMAC supports maximum MTU that can go to 16KB. Lets add this check in the calculation of RX buffer size. Fixes: 7ac6653a085b ("stmmac: Move the STMicroelectronics driver") Signed-off-by: Jose Abreu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index e89466bd432d..81d446469a35 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1043,7 +1043,9 @@ static int stmmac_set_bfsize(int mtu, int bufsize) { int ret = bufsize; - if (mtu >= BUF_SIZE_4KiB) + if (mtu >= BUF_SIZE_8KiB) + ret = BUF_SIZE_16KiB; + else if (mtu >= BUF_SIZE_4KiB) ret = BUF_SIZE_8KiB; else if (mtu >= BUF_SIZE_2KiB) ret = BUF_SIZE_4KiB; -- GitLab From 12b803e03d3156aa83f9446c91551da72233bf5e Mon Sep 17 00:00:00 2001 From: John Ogness Date: Sun, 24 Jun 2018 00:32:06 +0200 Subject: [PATCH 0246/1055] USB: serial: io_edgeport: use irqsave() in USB's complete callback [ Upstream commit dd1fae527612543e560e84f2eba4f6ef2006ac55 ] The USB completion callback does not disable interrupts while acquiring the lock. We want to remove the local_irq_disable() invocation from __usb_hcd_giveback_urb() and therefore it is required for the callback handler to disable the interrupts while acquiring the lock. The callback may be invoked either in IRQ or BH context depending on the USB host controller. Use the _irqsave() variant of the locking primitives. Signed-off-by: John Ogness Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Johan Hovold Signed-off-by: Sasha Levin --- drivers/usb/serial/io_edgeport.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 467870f504a5..8810de817095 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -652,6 +652,7 @@ static void edge_interrupt_callback(struct urb *urb) struct usb_serial_port *port; unsigned char *data = urb->transfer_buffer; int length = urb->actual_length; + unsigned long flags; int bytes_avail; int position; int txCredits; @@ -683,7 +684,7 @@ static void edge_interrupt_callback(struct urb *urb) if (length > 1) { bytes_avail = data[0] | (data[1] << 8); if (bytes_avail) { - spin_lock(&edge_serial->es_lock); + spin_lock_irqsave(&edge_serial->es_lock, flags); edge_serial->rxBytesAvail += bytes_avail; dev_dbg(dev, "%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d\n", @@ -706,7 +707,8 @@ static void edge_interrupt_callback(struct urb *urb) edge_serial->read_in_progress = false; } } - spin_unlock(&edge_serial->es_lock); + spin_unlock_irqrestore(&edge_serial->es_lock, + flags); } } /* grab the txcredits for the ports if available */ @@ -719,9 +721,11 @@ static void edge_interrupt_callback(struct urb *urb) port = edge_serial->serial->port[portNumber]; edge_port = usb_get_serial_port_data(port); if (edge_port->open) { - spin_lock(&edge_port->ep_lock); + spin_lock_irqsave(&edge_port->ep_lock, + flags); edge_port->txCredits += txCredits; - spin_unlock(&edge_port->ep_lock); + spin_unlock_irqrestore(&edge_port->ep_lock, + flags); dev_dbg(dev, "%s - txcredits for port%d = %d\n", __func__, portNumber, edge_port->txCredits); @@ -762,6 +766,7 @@ static void edge_bulk_in_callback(struct urb *urb) int retval; __u16 raw_data_length; int status = urb->status; + unsigned long flags; if (status) { dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n", @@ -781,7 +786,7 @@ static void edge_bulk_in_callback(struct urb *urb) usb_serial_debug_data(dev, __func__, raw_data_length, data); - spin_lock(&edge_serial->es_lock); + spin_lock_irqsave(&edge_serial->es_lock, flags); /* decrement our rxBytes available by the number that we just got */ edge_serial->rxBytesAvail -= raw_data_length; @@ -805,7 +810,7 @@ static void edge_bulk_in_callback(struct urb *urb) edge_serial->read_in_progress = false; } - spin_unlock(&edge_serial->es_lock); + spin_unlock_irqrestore(&edge_serial->es_lock, flags); } -- GitLab From abde18153f831447c61fbef12dd331aa9998cf1f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 17 Jan 2020 10:50:23 +0100 Subject: [PATCH 0247/1055] USB: serial: io_edgeport: handle unbound ports on URB completion [ Upstream commit e37d1aeda737a20b1846a91a3da3f8b0f00cf690 ] Check for NULL port data in the shared interrupt and bulk completion callbacks to avoid dereferencing a NULL pointer in case a device sends data for a port device which isn't bound to a driver (e.g. due to a malicious device having unexpected endpoints or after an allocation failure on port probe). Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Sasha Levin --- drivers/usb/serial/io_edgeport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 8810de817095..3705b64ab948 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -720,7 +720,7 @@ static void edge_interrupt_callback(struct urb *urb) if (txCredits) { port = edge_serial->serial->port[portNumber]; edge_port = usb_get_serial_port_data(port); - if (edge_port->open) { + if (edge_port && edge_port->open) { spin_lock_irqsave(&edge_port->ep_lock, flags); edge_port->txCredits += txCredits; @@ -1847,7 +1847,7 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, if (rxLen && edge_serial->rxPort < serial->num_ports) { port = serial->port[edge_serial->rxPort]; edge_port = usb_get_serial_port_data(port); - if (edge_port->open) { + if (edge_port && edge_port->open) { dev_dbg(dev, "%s - Sending %d bytes to TTY for port %d\n", __func__, rxLen, edge_serial->rxPort); -- GitLab From 26da70406bd88d5c65d7ec79b01888771756c6a8 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Mon, 13 May 2019 17:23:17 -0700 Subject: [PATCH 0248/1055] mm/huge_memory.c: make __thp_get_unmapped_area static [ Upstream commit b3b07077b01ecbbd98efede778c195567de25b71 ] __thp_get_unmapped_area is only used in mm/huge_memory.c. Make it static. Tested by building and booting the kernel. Link: http://lkml.kernel.org/r/20190504102353.GA22525@bharath12345-Inspiron-5559 Signed-off-by: Bharath Vedartham Acked-by: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- mm/huge_memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 1adc2e6c50f9..6d835535946d 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -502,7 +502,7 @@ void prep_transhuge_page(struct page *page) set_compound_page_dtor(page, TRANSHUGE_PAGE_DTOR); } -unsigned long __thp_get_unmapped_area(struct file *filp, unsigned long len, +static unsigned long __thp_get_unmapped_area(struct file *filp, unsigned long len, loff_t off, unsigned long flags, unsigned long size) { unsigned long addr; -- GitLab From ae6f36741273f59e0a0c9f1388461ee5d101b2b9 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Mon, 13 Jan 2020 16:29:10 -0800 Subject: [PATCH 0249/1055] mm/huge_memory.c: thp: fix conflict of above-47bit hint address and PMD alignment [ Upstream commit 97d3d0f9a1cf132c63c0b8b8bd497b8a56283dd9 ] Patch series "Fix two above-47bit hint address vs. THP bugs". The two get_unmapped_area() implementations have to be fixed to provide THP-friendly mappings if above-47bit hint address is specified. This patch (of 2): Filesystems use thp_get_unmapped_area() to provide THP-friendly mappings. For DAX in particular. Normally, the kernel doesn't create userspace mappings above 47-bit, even if the machine allows this (such as with 5-level paging on x86-64). Not all user space is ready to handle wide addresses. It's known that at least some JIT compilers use higher bits in pointers to encode their information. Userspace can ask for allocation from full address space by specifying hint address (with or without MAP_FIXED) above 47-bits. If the application doesn't need a particular address, but wants to allocate from whole address space it can specify -1 as a hint address. Unfortunately, this trick breaks thp_get_unmapped_area(): the function would not try to allocate PMD-aligned area if *any* hint address specified. Modify the routine to handle it correctly: - Try to allocate the space at the specified hint address with length padding required for PMD alignment. - If failed, retry without length padding (but with the same hint address); - If the returned address matches the hint address return it. - Otherwise, align the address as required for THP and return. The user specified hint address is passed down to get_unmapped_area() so above-47bit hint address will be taken into account without breaking alignment requirements. Link: http://lkml.kernel.org/r/20191220142548.7118-2-kirill.shutemov@linux.intel.com Fixes: b569bab78d8d ("x86/mm: Prepare to expose larger address space to userspace") Signed-off-by: Kirill A. Shutemov Reported-by: Thomas Willhalm Tested-by: Dan Williams Cc: "Aneesh Kumar K . V" Cc: "Bruggeman, Otto G" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- mm/huge_memory.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 6d835535946d..92915cc87549 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -502,13 +502,13 @@ void prep_transhuge_page(struct page *page) set_compound_page_dtor(page, TRANSHUGE_PAGE_DTOR); } -static unsigned long __thp_get_unmapped_area(struct file *filp, unsigned long len, +static unsigned long __thp_get_unmapped_area(struct file *filp, + unsigned long addr, unsigned long len, loff_t off, unsigned long flags, unsigned long size) { - unsigned long addr; loff_t off_end = off + len; loff_t off_align = round_up(off, size); - unsigned long len_pad; + unsigned long len_pad, ret; if (off_end <= off_align || (off_end - off_align) < size) return 0; @@ -517,30 +517,40 @@ static unsigned long __thp_get_unmapped_area(struct file *filp, unsigned long le if (len_pad < len || (off + len_pad) < off) return 0; - addr = current->mm->get_unmapped_area(filp, 0, len_pad, + ret = current->mm->get_unmapped_area(filp, addr, len_pad, off >> PAGE_SHIFT, flags); - if (IS_ERR_VALUE(addr)) + + /* + * The failure might be due to length padding. The caller will retry + * without the padding. + */ + if (IS_ERR_VALUE(ret)) return 0; - addr += (off - addr) & (size - 1); - return addr; + /* + * Do not try to align to THP boundary if allocation at the address + * hint succeeds. + */ + if (ret == addr) + return addr; + + ret += (off - ret) & (size - 1); + return ret; } unsigned long thp_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { + unsigned long ret; loff_t off = (loff_t)pgoff << PAGE_SHIFT; - if (addr) - goto out; if (!IS_DAX(filp->f_mapping->host) || !IS_ENABLED(CONFIG_FS_DAX_PMD)) goto out; - addr = __thp_get_unmapped_area(filp, len, off, flags, PMD_SIZE); - if (addr) - return addr; - - out: + ret = __thp_get_unmapped_area(filp, addr, len, off, flags, PMD_SIZE); + if (ret) + return ret; +out: return current->mm->get_unmapped_area(filp, addr, len, pgoff, flags); } EXPORT_SYMBOL_GPL(thp_get_unmapped_area); -- GitLab From 9510f18a019aa30d50d499fdae1176183132368c Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Wed, 20 Nov 2019 09:15:17 -0600 Subject: [PATCH 0250/1055] arm64: dts: agilex/stratix10: fix pmu interrupt numbers [ Upstream commit 210de0e996aee8e360ccc9e173fe7f0a7ed2f695 ] Fix up the correct interrupt numbers for the PMU unit on Agilex and Stratix10. Fixes: 78cd6a9d8e15 ("arm64: dts: Add base stratix 10 dtsi") Cc: linux-stable Reported-by: Meng Li Signed-off-by: Dinh Nguyen Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi index e79f3defe002..c2ad4f97cef0 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi @@ -56,10 +56,10 @@ pmu { compatible = "arm,armv8-pmuv3"; - interrupts = <0 120 8>, - <0 121 8>, - <0 122 8>, - <0 123 8>; + interrupts = <0 170 4>, + <0 171 4>, + <0 172 4>, + <0 173 4>; interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, -- GitLab From 99e739733fd2794ad9b27d99294061e756046ae2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 13 Jan 2020 19:21:07 +0100 Subject: [PATCH 0251/1055] cfg80211: fix page refcount issue in A-MSDU decap commit 81c044fc3bdc5b7be967cd3682528ea94b58c06a upstream. The fragments attached to a skb can be part of a compound page. In that case, page_ref_inc will increment the refcount for the wrong page. Fix this by using get_page instead, which calls page_ref_inc on the compound head and also checks for overflow. Fixes: 2b67f944f88c ("cfg80211: reuse existing page fragments in A-MSDU rx") Cc: stable@vger.kernel.org Signed-off-by: Felix Fietkau Link: https://lore.kernel.org/r/20200113182107.20461-1-nbd@nbd.name Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/wireless/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/util.c b/net/wireless/util.c index 2234817f5dbb..935929b45411 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -652,7 +652,7 @@ __frame_add_frag(struct sk_buff *skb, struct page *page, struct skb_shared_info *sh = skb_shinfo(skb); int page_offset; - page_ref_inc(page); + get_page(page); page_offset = ptr - page_address(page); skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size); } -- GitLab From 071b66b3808260ab35b725fc9f7e5466637a2b9e Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 10 Jan 2020 11:53:08 -0800 Subject: [PATCH 0252/1055] netfilter: fix a use-after-free in mtype_destroy() commit c120959387efa51479056fd01dc90adfba7a590c upstream. map->members is freed by ip_set_free() right before using it in mtype_ext_cleanup() again. So we just have to move it down. Reported-by: syzbot+4c3cc6dbe7259dbf9054@syzkaller.appspotmail.com Fixes: 40cd63bf33b2 ("netfilter: ipset: Support extensions which need a per data destroy function") Acked-by: Jozsef Kadlecsik Signed-off-by: Cong Wang Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/ipset/ip_set_bitmap_gen.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h index 8ad2b52a0b32..b0701f6259cc 100644 --- a/net/netfilter/ipset/ip_set_bitmap_gen.h +++ b/net/netfilter/ipset/ip_set_bitmap_gen.h @@ -64,9 +64,9 @@ mtype_destroy(struct ip_set *set) if (SET_WITH_TIMEOUT(set)) del_timer_sync(&map->gc); - ip_set_free(map->members); if (set->dsize && set->extensions & IPSET_EXT_DESTROY) mtype_ext_cleanup(set); + ip_set_free(map->members); ip_set_free(map); set->data = NULL; -- GitLab From 4130fabf9ed246d35108182bb1e444d4ceeccff7 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 11 Jan 2020 23:19:53 +0100 Subject: [PATCH 0253/1055] netfilter: arp_tables: init netns pointer in xt_tgdtor_param struct commit 212e7f56605ef9688d0846db60c6c6ec06544095 upstream. An earlier commit (1b789577f655060d98d20e, "netfilter: arp_tables: init netns pointer in xt_tgchk_param struct") fixed missing net initialization for arptables, but turns out it was incomplete. We can get a very similar struct net NULL deref during error unwinding: general protection fault: 0000 [#1] PREEMPT SMP KASAN RIP: 0010:xt_rateest_put+0xa1/0x440 net/netfilter/xt_RATEEST.c:77 xt_rateest_tg_destroy+0x72/0xa0 net/netfilter/xt_RATEEST.c:175 cleanup_entry net/ipv4/netfilter/arp_tables.c:509 [inline] translate_table+0x11f4/0x1d80 net/ipv4/netfilter/arp_tables.c:587 do_replace net/ipv4/netfilter/arp_tables.c:981 [inline] do_arpt_set_ctl+0x317/0x650 net/ipv4/netfilter/arp_tables.c:1461 Also init the netns pointer in xt_tgdtor_param struct. Fixes: add67461240c1d ("netfilter: add struct net * to target parameters") Reported-by: syzbot+91bdd8eece0f6629ec8b@syzkaller.appspotmail.com Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/ipv4/netfilter/arp_tables.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index e288489ae3d5..6dd727e0a72f 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -506,12 +506,13 @@ static inline int check_entry_size_and_hooks(struct arpt_entry *e, return 0; } -static inline void cleanup_entry(struct arpt_entry *e) +static void cleanup_entry(struct arpt_entry *e, struct net *net) { struct xt_tgdtor_param par; struct xt_entry_target *t; t = arpt_get_target(e); + par.net = net; par.target = t->u.kernel.target; par.targinfo = t->data; par.family = NFPROTO_ARP; @@ -601,7 +602,7 @@ static int translate_table(struct net *net, xt_entry_foreach(iter, entry0, newinfo->size) { if (i-- == 0) break; - cleanup_entry(iter); + cleanup_entry(iter, net); } return ret; } @@ -926,7 +927,7 @@ static int __do_replace(struct net *net, const char *name, /* Decrease module usage counts and free resource */ loc_cpu_old_entry = oldinfo->entries; xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) - cleanup_entry(iter); + cleanup_entry(iter, net); xt_free_table_info(oldinfo); if (copy_to_user(counters_ptr, counters, @@ -990,7 +991,7 @@ static int do_replace(struct net *net, const void __user *user, free_newinfo_untrans: xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) - cleanup_entry(iter); + cleanup_entry(iter, net); free_newinfo: xt_free_table_info(newinfo); return ret; @@ -1287,7 +1288,7 @@ static int compat_do_replace(struct net *net, void __user *user, free_newinfo_untrans: xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) - cleanup_entry(iter); + cleanup_entry(iter, net); free_newinfo: xt_free_table_info(newinfo); return ret; @@ -1514,7 +1515,7 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len return ret; } -static void __arpt_unregister_table(struct xt_table *table) +static void __arpt_unregister_table(struct net *net, struct xt_table *table) { struct xt_table_info *private; void *loc_cpu_entry; @@ -1526,7 +1527,7 @@ static void __arpt_unregister_table(struct xt_table *table) /* Decrease module usage counts and free resources */ loc_cpu_entry = private->entries; xt_entry_foreach(iter, loc_cpu_entry, private->size) - cleanup_entry(iter); + cleanup_entry(iter, net); if (private->number > private->initial_entries) module_put(table_owner); xt_free_table_info(private); @@ -1566,7 +1567,7 @@ int arpt_register_table(struct net *net, ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks)); if (ret != 0) { - __arpt_unregister_table(new_table); + __arpt_unregister_table(net, new_table); *res = NULL; } @@ -1581,7 +1582,7 @@ void arpt_unregister_table(struct net *net, struct xt_table *table, const struct nf_hook_ops *ops) { nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); - __arpt_unregister_table(table); + __arpt_unregister_table(net, table); } /* The built-in targets: standard (NULL) and error. */ -- GitLab From 2dc70c6ea87a0df09116b8b5739944f8525d48c7 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Jan 2020 18:23:58 +0100 Subject: [PATCH 0254/1055] NFC: pn533: fix bulk-message timeout commit a112adafcb47760feff959ee1ecd10b74d2c5467 upstream. The driver was doing a synchronous uninterruptible bulk-transfer without using a timeout. This could lead to the driver hanging on probe due to a malfunctioning (or malicious) device until the device is physically disconnected. While sleeping in probe the driver prevents other devices connected to the same hub from being added to (or removed from) the bus. An arbitrary limit of five seconds should be more than enough. Fixes: dbafc28955fa ("NFC: pn533: don't send USB data off of the stack") Signed-off-by: Johan Hovold Reviewed-by: Greg Kroah-Hartman Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- drivers/nfc/pn533/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/pn533/usb.c b/drivers/nfc/pn533/usb.c index fcb57d64d97e..a2c9b3f3bc23 100644 --- a/drivers/nfc/pn533/usb.c +++ b/drivers/nfc/pn533/usb.c @@ -403,7 +403,7 @@ static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy) cmd, sizeof(cmd), false); rc = usb_bulk_msg(phy->udev, phy->out_urb->pipe, buffer, sizeof(cmd), - &transferred, 0); + &transferred, 5000); kfree(buffer); if (rc || (transferred != sizeof(cmd))) { nfc_err(&phy->udev->dev, -- GitLab From 83bd51eb8f992b64711c2402dd9f78cbea35b946 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Thu, 28 Nov 2019 12:25:45 +0100 Subject: [PATCH 0255/1055] batman-adv: Fix DAT candidate selection on little endian systems commit 4cc4a1708903f404d2ca0dfde30e71e052c6cbc9 upstream. The distributed arp table is using a DHT to store and retrieve MAC address information for an IP address. This is done using unicast messages to selected peers. The potential peers are looked up using the IP address and the VID. While the IP address is always stored in big endian byte order, this is not the case of the VID. It can (depending on the host system) either be big endian or little endian. The host must therefore always convert it to big endian to ensure that all devices calculate the same peers for the same lookup data. Fixes: be1db4f6615b ("batman-adv: make the Distributed ARP Table vlan aware") Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich Signed-off-by: Greg Kroah-Hartman --- net/batman-adv/distributed-arp-table.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 8d1d0fdb157e..1519cbf70150 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -243,6 +243,7 @@ static u32 batadv_hash_dat(const void *data, u32 size) u32 hash = 0; const struct batadv_dat_entry *dat = data; const unsigned char *key; + __be16 vid; u32 i; key = (const unsigned char *)&dat->ip; @@ -252,7 +253,8 @@ static u32 batadv_hash_dat(const void *data, u32 size) hash ^= (hash >> 6); } - key = (const unsigned char *)&dat->vid; + vid = htons(dat->vid); + key = (__force const unsigned char *)&vid; for (i = 0; i < sizeof(dat->vid); i++) { hash += key[i]; hash += (hash << 10); -- GitLab From 93c81624bb12329445e76a88dbb45ac0ef55d152 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 14 Jan 2020 13:00:35 -0800 Subject: [PATCH 0256/1055] macvlan: use skb_reset_mac_header() in macvlan_queue_xmit() [ Upstream commit 1712b2fff8c682d145c7889d2290696647d82dab ] I missed the fact that macvlan_broadcast() can be used both in RX and TX. skb_eth_hdr() makes only sense in TX paths, so we can not use it blindly in macvlan_broadcast() Fixes: 96cc4b69581d ("macvlan: do not assume mac_header is set in macvlan_broadcast()") Signed-off-by: Eric Dumazet Reported-by: Jurgen Van Ham Tested-by: Matteo Croce Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/macvlan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 2b977655834c..ab539136d5bf 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -263,7 +263,7 @@ static void macvlan_broadcast(struct sk_buff *skb, struct net_device *src, enum macvlan_mode mode) { - const struct ethhdr *eth = skb_eth_hdr(skb); + const struct ethhdr *eth = eth_hdr(skb); const struct macvlan_dev *vlan; struct sk_buff *nskb; unsigned int i; @@ -515,10 +515,11 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev) const struct macvlan_dev *dest; if (vlan->mode == MACVLAN_MODE_BRIDGE) { - const struct ethhdr *eth = (void *)skb->data; + const struct ethhdr *eth = skb_eth_hdr(skb); /* send to other bridge ports directly */ if (is_multicast_ether_addr(eth->h_dest)) { + skb_reset_mac_header(skb); macvlan_broadcast(skb, port, dev, MACVLAN_MODE_BRIDGE); goto xmit_world; } -- GitLab From a1eb61dd2b1c4d3a3b23dd824ba71c877caba18c Mon Sep 17 00:00:00 2001 From: Mohammed Gamal Date: Tue, 14 Jan 2020 15:09:50 +0200 Subject: [PATCH 0257/1055] hv_netvsc: Fix memory leak when removing rndis device [ Upstream commit 536dc5df2808efbefc5acee334d3c4f701790ec0 ] kmemleak detects the following memory leak when hot removing a network device: unreferenced object 0xffff888083f63600 (size 256): comm "kworker/0:1", pid 12, jiffies 4294831717 (age 1113.676s) hex dump (first 32 bytes): 00 40 c7 33 80 88 ff ff 00 00 00 00 10 00 00 00 .@.3............ 00 00 00 00 ad 4e ad de ff ff ff ff 00 00 00 00 .....N.......... backtrace: [<00000000d4a8f5be>] rndis_filter_device_add+0x117/0x11c0 [hv_netvsc] [<000000009c02d75b>] netvsc_probe+0x5e7/0xbf0 [hv_netvsc] [<00000000ddafce23>] vmbus_probe+0x74/0x170 [hv_vmbus] [<00000000046e64f1>] really_probe+0x22f/0xb50 [<000000005cc35eb7>] driver_probe_device+0x25e/0x370 [<0000000043c642b2>] bus_for_each_drv+0x11f/0x1b0 [<000000005e3d09f0>] __device_attach+0x1c6/0x2f0 [<00000000a72c362f>] bus_probe_device+0x1a6/0x260 [<0000000008478399>] device_add+0x10a3/0x18e0 [<00000000cf07b48c>] vmbus_device_register+0xe7/0x1e0 [hv_vmbus] [<00000000d46cf032>] vmbus_add_channel_work+0x8ab/0x1770 [hv_vmbus] [<000000002c94bb64>] process_one_work+0x919/0x17d0 [<0000000096de6781>] worker_thread+0x87/0xb40 [<00000000fbe7397e>] kthread+0x333/0x3f0 [<000000004f844269>] ret_from_fork+0x3a/0x50 rndis_filter_device_add() allocates an instance of struct rndis_device which never gets deallocated as rndis_filter_device_remove() sets net_device->extension which points to the rndis_device struct to NULL, leaving the rndis_device dangling. Since net_device->extension is eventually freed in free_netvsc_device(), we refrain from setting it to NULL inside rndis_filter_device_remove() Signed-off-by: Mohammed Gamal Reviewed-by: Haiyang Zhang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/hyperv/rndis_filter.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index b19557c035f2..aa0bbffe4900 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1331,8 +1331,6 @@ void rndis_filter_device_remove(struct hv_device *dev, /* Halt and release the rndis device */ rndis_filter_halt_device(rndis_dev); - net_dev->extension = NULL; - netvsc_device_remove(dev); } -- GitLab From e9a80cf49026b21729eac485fbe3dad2728c75e0 Mon Sep 17 00:00:00 2001 From: Alexander Lobakin Date: Wed, 15 Jan 2020 11:56:52 +0300 Subject: [PATCH 0258/1055] net: dsa: tag_qca: fix doubled Tx statistics [ Upstream commit bd5874da57edd001b35cf28ae737779498c16a56 ] DSA subsystem takes care of netdev statistics since commit 4ed70ce9f01c ("net: dsa: Refactor transmit path to eliminate duplication"), so any accounting inside tagger callbacks is redundant and can lead to messing up the stats. This bug is present in Qualcomm tagger since day 0. Fixes: cafdc45c949b ("net-next: dsa: add Qualcomm tag RX/TX handler") Reviewed-by: Andrew Lunn Signed-off-by: Alexander Lobakin Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dsa/tag_qca.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c index b8c05f1cf47d..af3a12a36d88 100644 --- a/net/dsa/tag_qca.c +++ b/net/dsa/tag_qca.c @@ -41,9 +41,6 @@ static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev) struct dsa_slave_priv *p = netdev_priv(dev); u16 *phdr, hdr; - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - if (skb_cow_head(skb, 0) < 0) return NULL; -- GitLab From 56cffa965c195cf64f8c1f40ac8f3f897d59f08c Mon Sep 17 00:00:00 2001 From: Yonglong Liu Date: Thu, 16 Jan 2020 15:41:17 +0800 Subject: [PATCH 0259/1055] net: hns: fix soft lockup when there is not enough memory [ Upstream commit 49edd6a2c456150870ddcef5b7ed11b21d849e13 ] When there is not enough memory and napi_alloc_skb() return NULL, the HNS driver will print error message, and than try again, if the memory is not enough for a while, huge error message and the retry operation will cause soft lockup. When napi_alloc_skb() return NULL because of no memory, we can get a warn_alloc() call trace, so this patch deletes the error message. We already use polling mode to handle irq, but the retry operation will render the polling weight inactive, this patch just return budget when the rx is not completed to avoid dead loop. Fixes: 36eedfde1a36 ("net: hns: Optimize hns_nic_common_poll for better performance") Fixes: b5996f11ea54 ("net: add Hisilicon Network Subsystem basic ethernet support") Signed-off-by: Yonglong Liu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index b681c07b33fb..0733745f4be6 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -669,7 +669,6 @@ static int hns_nic_poll_rx_skb(struct hns_nic_ring_data *ring_data, skb = *out_skb = napi_alloc_skb(&ring_data->napi, HNS_RX_HEAD_SIZE); if (unlikely(!skb)) { - netdev_err(ndev, "alloc rx skb fail\n"); ring->stats.sw_err_cnt++; return -ENOMEM; } @@ -1180,7 +1179,6 @@ static int hns_nic_common_poll(struct napi_struct *napi, int budget) container_of(napi, struct hns_nic_ring_data, napi); struct hnae_ring *ring = ring_data->ring; -try_again: clean_complete += ring_data->poll_one( ring_data, budget - clean_complete, ring_data->ex_process); @@ -1190,7 +1188,7 @@ static int hns_nic_common_poll(struct napi_struct *napi, int budget) napi_complete(napi); ring->q->handle->dev->ops->toggle_ring_irq(ring, 0); } else { - goto try_again; + return budget; } } -- GitLab From 7ebdc211ed5c22389a5baa3e181dd99884154b30 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 13 Jan 2020 09:27:11 -0800 Subject: [PATCH 0260/1055] net: usb: lan78xx: limit size of local TSO packets [ Upstream commit f8d7408a4d7f60f8b2df0f81decdc882dd9c20dc ] lan78xx_tx_bh() makes sure to not exceed MAX_SINGLE_PACKET_SIZE bytes in the aggregated packets it builds, but does nothing to prevent large GSO packets being submitted. Pierre-Francois reported various hangs when/if TSO is enabled. For localy generated packets, we can use netif_set_gso_max_size() to limit the size of TSO packets. Note that forwarded packets could still hit the issue, so a complete fix might require implementing .ndo_features_check for this driver, forcing a software segmentation if the size of the TSO packet exceeds MAX_SINGLE_PACKET_SIZE. Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver") Signed-off-by: Eric Dumazet Reported-by: RENARD Pierre-Francois Tested-by: RENARD Pierre-Francois Cc: Stefan Wahren Cc: Woojung Huh Cc: Microchip Linux Driver Support Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/lan78xx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index c23f35dba718..ee7194a9e231 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -3612,6 +3612,7 @@ static int lan78xx_probe(struct usb_interface *intf, /* MTU range: 68 - 9000 */ netdev->max_mtu = MAX_SINGLE_PACKET_SIZE; + netif_set_gso_max_size(netdev, MAX_SINGLE_PACKET_SIZE - MAX_HEADER); dev->ep_blkin = (intf->cur_altsetting)->endpoint + 0; dev->ep_blkout = (intf->cur_altsetting)->endpoint + 1; -- GitLab From d14f54ff5ed255f0fae840501b1eb0be6993aced Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 14 Jan 2020 14:54:48 +0000 Subject: [PATCH 0261/1055] net/wan/fsl_ucc_hdlc: fix out of bounds write on array utdm_info [ Upstream commit ddf420390526ede3b9ff559ac89f58cb59d9db2f ] Array utdm_info is declared as an array of MAX_HDLC_NUM (4) elements however up to UCC_MAX_NUM (8) elements are potentially being written to it. Currently we have an array out-of-bounds write error on the last 4 elements. Fix this by making utdm_info UCC_MAX_NUM elements in size. Addresses-Coverity: ("Out-of-bounds write") Fixes: c19b6d246a35 ("drivers/net: support hdlc function for QE-UCC") Signed-off-by: Colin Ian King Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/wan/fsl_ucc_hdlc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 289dff262948..571a1ff8f81f 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -76,7 +76,7 @@ static struct ucc_tdm_info utdm_primary_info = { }, }; -static struct ucc_tdm_info utdm_info[MAX_HDLC_NUM]; +static struct ucc_tdm_info utdm_info[UCC_MAX_NUM]; static int uhdlc_init(struct ucc_hdlc_private *priv) { -- GitLab From a05776cb7264cd3515980d034f50b7ef110239a8 Mon Sep 17 00:00:00 2001 From: Vladis Dronov Date: Mon, 13 Jan 2020 14:00:09 +0100 Subject: [PATCH 0262/1055] ptp: free ptp device pin descriptors properly [ Upstream commit 75718584cb3c64e6269109d4d54f888ac5a5fd15 ] There is a bug in ptp_clock_unregister(), where ptp_cleanup_pin_groups() first frees ptp->pin_{,dev_}attr, but then posix_clock_unregister() needs them to destroy a related sysfs device. These functions can not be just swapped, as posix_clock_unregister() frees ptp which is needed in the ptp_cleanup_pin_groups(). Fix this by calling ptp_cleanup_pin_groups() in ptp_clock_release(), right before ptp is freed. This makes this patch fix an UAF bug in a patch which fixes an UAF bug. Reported-by: Antti Laakso Fixes: a33121e5487b ("ptp: fix the race between the release of ptp_clock and cdev") Link: https://lore.kernel.org/netdev/3d2bd09735dbdaf003585ca376b7c1e5b69a19bd.camel@intel.com/ Signed-off-by: Vladis Dronov Acked-by: Richard Cochran Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/ptp/ptp_clock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index b818f65480c1..e232233beb8f 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -179,6 +179,7 @@ static void ptp_clock_release(struct device *dev) { struct ptp_clock *ptp = container_of(dev, struct ptp_clock, dev); + ptp_cleanup_pin_groups(ptp); mutex_destroy(&ptp->tsevq_mux); mutex_destroy(&ptp->pincfg_mux); ida_simple_remove(&ptp_clocks_map, ptp->index); @@ -315,9 +316,8 @@ int ptp_clock_unregister(struct ptp_clock *ptp) if (ptp->pps_source) pps_unregister_source(ptp->pps_source); - ptp_cleanup_pin_groups(ptp); - posix_clock_unregister(&ptp->clock); + return 0; } EXPORT_SYMBOL(ptp_clock_unregister); -- GitLab From 8b7b68bd78b45e4e77b48cab2d40d769a5f67754 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 14 Jan 2020 09:27:29 +0100 Subject: [PATCH 0263/1055] r8152: add missing endpoint sanity check [ Upstream commit 86f3f4cd53707ceeec079b83205c8d3c756eca93 ] Add missing endpoint sanity check to probe in order to prevent a NULL-pointer dereference (or slab out-of-bounds access) when retrieving the interrupt-endpoint bInterval on ndo_open() in case a device lacks the expected endpoints. Fixes: 40a82917b1d3 ("net/usb/r8152: enable interrupt transfer") Cc: hayeswang Signed-off-by: Johan Hovold Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/r8152.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 6a86a03c5e95..0083c60f5cdf 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -5158,6 +5158,9 @@ static int rtl8152_probe(struct usb_interface *intf, return -ENODEV; } + if (intf->cur_altsetting->desc.bNumEndpoints < 3) + return -ENODEV; + usb_reset_device(udev); netdev = alloc_etherdev(sizeof(struct r8152)); if (!netdev) { -- GitLab From 43dfcc773511174d8b1650fd594d9e667e43a47d Mon Sep 17 00:00:00 2001 From: Pengcheng Yang Date: Tue, 14 Jan 2020 17:23:40 +0800 Subject: [PATCH 0264/1055] tcp: fix marked lost packets not being retransmitted [ Upstream commit e176b1ba476cf36f723cfcc7a9e57f3cb47dec70 ] When the packet pointed to by retransmit_skb_hint is unlinked by ACK, retransmit_skb_hint will be set to NULL in tcp_clean_rtx_queue(). If packet loss is detected at this time, retransmit_skb_hint will be set to point to the current packet loss in tcp_verify_retransmit_hint(), then the packets that were previously marked lost but not retransmitted due to the restriction of cwnd will be skipped and cannot be retransmitted. To fix this, when retransmit_skb_hint is NULL, retransmit_skb_hint can be reset only after all marked lost packets are retransmitted (retrans_out >= lost_out), otherwise we need to traverse from tcp_rtx_queue_head in tcp_xmit_retransmit_queue(). Packetdrill to demonstrate: // Disable RACK and set max_reordering to keep things simple 0 `sysctl -q net.ipv4.tcp_recovery=0` +0 `sysctl -q net.ipv4.tcp_max_reordering=3` // Establish a connection +0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0 bind(3, ..., ...) = 0 +0 listen(3, 1) = 0 +.1 < S 0:0(0) win 32792 +0 > S. 0:0(0) ack 1 <...> +.01 < . 1:1(0) ack 1 win 257 +0 accept(3, ..., ...) = 4 // Send 8 data segments +0 write(4, ..., 8000) = 8000 +0 > P. 1:8001(8000) ack 1 // Enter recovery and 1:3001 is marked lost +.01 < . 1:1(0) ack 1 win 257 +0 < . 1:1(0) ack 1 win 257 +0 < . 1:1(0) ack 1 win 257 // Retransmit 1:1001, now retransmit_skb_hint points to 1001:2001 +0 > . 1:1001(1000) ack 1 // 1001:2001 was ACKed causing retransmit_skb_hint to be set to NULL +.01 < . 1:1(0) ack 2001 win 257 // Now retransmit_skb_hint points to 4001:5001 which is now marked lost // BUG: 2001:3001 was not retransmitted +0 > . 2001:3001(1000) ack 1 Signed-off-by: Pengcheng Yang Acked-by: Neal Cardwell Tested-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d2b1c39c4223..29f3df4ddd1f 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -932,9 +932,10 @@ static void tcp_update_reordering(struct sock *sk, const int metric, /* This must be called before lost_out is incremented */ static void tcp_verify_retransmit_hint(struct tcp_sock *tp, struct sk_buff *skb) { - if (!tp->retransmit_skb_hint || - before(TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(tp->retransmit_skb_hint)->seq)) + if ((!tp->retransmit_skb_hint && tp->retrans_out >= tp->lost_out) || + (tp->retransmit_skb_hint && + before(TCP_SKB_CB(skb)->seq, + TCP_SKB_CB(tp->retransmit_skb_hint)->seq))) tp->retransmit_skb_hint = skb; } -- GitLab From 6adce8341393aa6bd7d51d23eb2c93aef91ea7cd Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 9 Dec 2019 13:14:44 -0700 Subject: [PATCH 0265/1055] xen/blkfront: Adjust indentation in xlvbd_alloc_gendisk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 589b72894f53124a39d1bb3c0cecaf9dcabac417 upstream. Clang warns: ../drivers/block/xen-blkfront.c:1117:4: warning: misleading indentation; statement is not part of the previous 'if' [-Wmisleading-indentation] nr_parts = PARTS_PER_DISK; ^ ../drivers/block/xen-blkfront.c:1115:3: note: previous statement is here if (err) ^ This is because there is a space at the beginning of this line; remove it so that the indentation is consistent according to the Linux kernel coding style and clang no longer warns. While we are here, the previous line has some trailing whitespace; clean that up as well. Fixes: c80a420995e7 ("xen-blkfront: handle Xen major numbers other than XENVBD") Link: https://github.com/ClangBuiltLinux/linux/issues/791 Signed-off-by: Nathan Chancellor Reviewed-by: Juergen Gross Acked-by: Roger Pau Monné Signed-off-by: Juergen Gross Signed-off-by: Greg Kroah-Hartman --- drivers/block/xen-blkfront.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 32ac5f551e55..e6887714fe0a 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1115,8 +1115,8 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity, if (!VDEV_IS_EXTENDED(info->vdevice)) { err = xen_translate_vdev(info->vdevice, &minor, &offset); if (err) - return err; - nr_parts = PARTS_PER_DISK; + return err; + nr_parts = PARTS_PER_DISK; } else { minor = BLKIF_MINOR_EXT(info->vdevice); nr_parts = PARTS_PER_EXT_DISK; -- GitLab From f5a62384b51cc1f37d7eae781283696557f56d10 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 1 Oct 2019 14:45:01 +0300 Subject: [PATCH 0266/1055] cw1200: Fix a signedness bug in cw1200_load_firmware() commit 4a50d454502f1401171ff061a5424583f91266db upstream. The "priv->hw_type" is an enum and in this context GCC will treat it as an unsigned int so the error handling will never trigger. Fixes: a910e4a94f69 ("cw1200: add driver for the ST-E CW1100 & CW1200 WLAN chipsets") Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/st/cw1200/fwio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/st/cw1200/fwio.c b/drivers/net/wireless/st/cw1200/fwio.c index 30e7646d04af..16be7fa82a23 100644 --- a/drivers/net/wireless/st/cw1200/fwio.c +++ b/drivers/net/wireless/st/cw1200/fwio.c @@ -323,12 +323,12 @@ int cw1200_load_firmware(struct cw1200_common *priv) goto out; } - priv->hw_type = cw1200_get_hw_type(val32, &major_revision); - if (priv->hw_type < 0) { + ret = cw1200_get_hw_type(val32, &major_revision); + if (ret < 0) { pr_err("Can't deduce hardware type.\n"); - ret = -ENOTSUPP; goto out; } + priv->hw_type = ret; /* Set DPLL Reg value, and read back to confirm writes work */ ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID, -- GitLab From bde97eaa4b3686910a066b024595e1ffac202b1a Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Mon, 9 Sep 2019 19:01:22 +0400 Subject: [PATCH 0267/1055] arm64: dts: meson-gxl-s905x-khadas-vim: fix gpio-keys-polled node commit d5f6fa904ecbadbb8e9fa6302b0fc165bec0559a upstream. Fix DTC warnings: arch/arm/dts/meson-gxl-s905x-khadas-vim.dtb: Warning (avoid_unnecessary_addr_size): /gpio-keys-polled: unnecessary #address-cells/#size-cells without "ranges" or child "reg" property Fixes: e15d2774b8c0 ("ARM64: dts: meson-gxl: add support for the Khadas VIM board") Signed-off-by: Christian Hewitt Reviewed-by: Kevin Hilman Signed-off-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts index fb5db5f33e8c..ce4a116382bf 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts @@ -33,11 +33,9 @@ gpio-keys-polled { compatible = "gpio-keys-polled"; - #address-cells = <1>; - #size-cells = <0>; poll-interval = <100>; - button@0 { + power-button { label = "power"; linux,code = ; gpios = <&gpio_ao GPIOAO_2 GPIO_ACTIVE_LOW>; -- GitLab From 162b3b1a0b10e5cefc4c8b83f766b54ab2e43b39 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 13 Jan 2020 12:53:59 +0100 Subject: [PATCH 0268/1055] cfg80211: check for set_wiphy_params commit 24953de0a5e31dcca7e82c8a3c79abc2dfe8fb6e upstream. Check if set_wiphy_params is assigned and return an error if not, some drivers (e.g. virt_wifi where syzbot reported it) don't have it. Reported-by: syzbot+e8a797964a4180eb57d5@syzkaller.appspotmail.com Reported-by: syzbot+34b582cf32c1db008f8e@syzkaller.appspotmail.com Signed-off-by: Johannes Berg Link: https://lore.kernel.org/r/20200113125358.ac07f276efff.Ibd85ee1b12e47b9efb00a2adc5cd3fac50da791a@changeid Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/wireless/rdev-ops.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 0c06240d25af..249919bdfc64 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -537,6 +537,10 @@ static inline int rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed) { int ret; + + if (!rdev->ops->set_wiphy_params) + return -EOPNOTSUPP; + trace_rdev_set_wiphy_params(&rdev->wiphy, changed); ret = rdev->ops->set_wiphy_params(&rdev->wiphy, changed); trace_rdev_return_int(&rdev->wiphy, ret); -- GitLab From f32935bcfd73851138595e25351f2139ded24fc7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 4 Dec 2019 20:56:19 -0800 Subject: [PATCH 0269/1055] tick/sched: Annotate lockless access to last_jiffies_update commit de95a991bb72e009f47e0c4bbc90fc5f594588d5 upstream. syzbot (KCSAN) reported a data-race in tick_do_update_jiffies64(): BUG: KCSAN: data-race in tick_do_update_jiffies64 / tick_do_update_jiffies64 write to 0xffffffff8603d008 of 8 bytes by interrupt on cpu 1: tick_do_update_jiffies64+0x100/0x250 kernel/time/tick-sched.c:73 tick_sched_do_timer+0xd4/0xe0 kernel/time/tick-sched.c:138 tick_sched_timer+0x43/0xe0 kernel/time/tick-sched.c:1292 __run_hrtimer kernel/time/hrtimer.c:1514 [inline] __hrtimer_run_queues+0x274/0x5f0 kernel/time/hrtimer.c:1576 hrtimer_interrupt+0x22a/0x480 kernel/time/hrtimer.c:1638 local_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1110 [inline] smp_apic_timer_interrupt+0xdc/0x280 arch/x86/kernel/apic/apic.c:1135 apic_timer_interrupt+0xf/0x20 arch/x86/entry/entry_64.S:830 arch_local_irq_restore arch/x86/include/asm/paravirt.h:756 [inline] kcsan_setup_watchpoint+0x1d4/0x460 kernel/kcsan/core.c:436 check_access kernel/kcsan/core.c:466 [inline] __tsan_read1 kernel/kcsan/core.c:593 [inline] __tsan_read1+0xc2/0x100 kernel/kcsan/core.c:593 kallsyms_expand_symbol.constprop.0+0x70/0x160 kernel/kallsyms.c:79 kallsyms_lookup_name+0x7f/0x120 kernel/kallsyms.c:170 insert_report_filterlist kernel/kcsan/debugfs.c:155 [inline] debugfs_write+0x14b/0x2d0 kernel/kcsan/debugfs.c:256 full_proxy_write+0xbd/0x100 fs/debugfs/file.c:225 __vfs_write+0x67/0xc0 fs/read_write.c:494 vfs_write fs/read_write.c:558 [inline] vfs_write+0x18a/0x390 fs/read_write.c:542 ksys_write+0xd5/0x1b0 fs/read_write.c:611 __do_sys_write fs/read_write.c:623 [inline] __se_sys_write fs/read_write.c:620 [inline] __x64_sys_write+0x4c/0x60 fs/read_write.c:620 do_syscall_64+0xcc/0x370 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x44/0xa9 read to 0xffffffff8603d008 of 8 bytes by task 0 on cpu 0: tick_do_update_jiffies64+0x2b/0x250 kernel/time/tick-sched.c:62 tick_nohz_update_jiffies kernel/time/tick-sched.c:505 [inline] tick_nohz_irq_enter kernel/time/tick-sched.c:1257 [inline] tick_irq_enter+0x139/0x1c0 kernel/time/tick-sched.c:1274 irq_enter+0x4f/0x60 kernel/softirq.c:354 entering_irq arch/x86/include/asm/apic.h:517 [inline] entering_ack_irq arch/x86/include/asm/apic.h:523 [inline] smp_apic_timer_interrupt+0x55/0x280 arch/x86/kernel/apic/apic.c:1133 apic_timer_interrupt+0xf/0x20 arch/x86/entry/entry_64.S:830 native_safe_halt+0xe/0x10 arch/x86/include/asm/irqflags.h:60 arch_cpu_idle+0xa/0x10 arch/x86/kernel/process.c:571 default_idle_call+0x1e/0x40 kernel/sched/idle.c:94 cpuidle_idle_call kernel/sched/idle.c:154 [inline] do_idle+0x1af/0x280 kernel/sched/idle.c:263 cpu_startup_entry+0x1b/0x20 kernel/sched/idle.c:355 rest_init+0xec/0xf6 init/main.c:452 arch_call_rest_init+0x17/0x37 start_kernel+0x838/0x85e init/main.c:786 x86_64_start_reservations+0x29/0x2b arch/x86/kernel/head64.c:490 x86_64_start_kernel+0x72/0x76 arch/x86/kernel/head64.c:471 secondary_startup_64+0xa4/0xb0 arch/x86/kernel/head_64.S:241 Reported by Kernel Concurrency Sanitizer on: CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.4.0-rc7+ #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Use READ_ONCE() and WRITE_ONCE() to annotate this expected race. Reported-by: syzbot Signed-off-by: Eric Dumazet Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/r/20191205045619.204946-1-edumazet@google.com Signed-off-by: Greg Kroah-Hartman --- kernel/time/tick-sched.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index a8fa0a896b78..3c7b400512eb 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -60,8 +60,9 @@ static void tick_do_update_jiffies64(ktime_t now) /* * Do a quick check without holding jiffies_lock: + * The READ_ONCE() pairs with two updates done later in this function. */ - delta = ktime_sub(now, last_jiffies_update); + delta = ktime_sub(now, READ_ONCE(last_jiffies_update)); if (delta < tick_period) return; @@ -72,8 +73,9 @@ static void tick_do_update_jiffies64(ktime_t now) if (delta >= tick_period) { delta = ktime_sub(delta, tick_period); - last_jiffies_update = ktime_add(last_jiffies_update, - tick_period); + /* Pairs with the lockless read in this function. */ + WRITE_ONCE(last_jiffies_update, + ktime_add(last_jiffies_update, tick_period)); /* Slow path for long timeouts */ if (unlikely(delta >= tick_period)) { @@ -81,8 +83,10 @@ static void tick_do_update_jiffies64(ktime_t now) ticks = ktime_divns(delta, incr); - last_jiffies_update = ktime_add_ns(last_jiffies_update, - incr * ticks); + /* Pairs with the lockless read in this function. */ + WRITE_ONCE(last_jiffies_update, + ktime_add_ns(last_jiffies_update, + incr * ticks)); } do_timer(++ticks); -- GitLab From 4f2b5f109b247d5afe50d28c93efba9ec8f61be5 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 28 Nov 2019 15:33:57 +0000 Subject: [PATCH 0270/1055] Revert "arm64: dts: juno: add dma-ranges property" commit 54fb3fe0f211d4729a2551cf9497bd612189af9d upstream. This reverts commit 193d00a2b35ee3353813b4006a18131122087205. Commit 951d48855d86 ("of: Make of_dma_get_range() work on bus nodes") reworked the logic such that of_dma_get_range() works correctly starting from a bus node containing "dma-ranges". Since on Juno we don't have a SoC level bus node and "dma-ranges" is present only in the root node, we get the following error: OF: translation of DMA address(0) to CPU address failed node(/sram@2e000000) OF: translation of DMA address(0) to CPU address failed node(/uart@7ff80000) ... OF: translation of DMA address(0) to CPU address failed node(/mhu@2b1f0000) OF: translation of DMA address(0) to CPU address failed node(/iommu@2b600000) OF: translation of DMA address(0) to CPU address failed node(/iommu@2b600000) OF: translation of DMA address(0) to CPU address failed node(/iommu@2b600000) So let's fix it by dropping the "dma-ranges" property for now. This should be fine since it doesn't represent any kind of device-visible restriction; it was only there for completeness, and we've since given in to the assumption that missing "dma-ranges" implies a 1:1 mapping anyway. We can add it later with a proper SoC bus node and moving all the devices that belong there along with the "dma-ranges" if required. Fixes: 193d00a2b35e ("arm64: dts: juno: add dma-ranges property") Cc: Rob Herring Cc: Liviu Dudau Cc: Lorenzo Pieralisi Acked-by: Robin Murphy Signed-off-by: Sudeep Holla Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/arm/juno-base.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi index f165f04db0c9..13ee8ffa9bbf 100644 --- a/arch/arm64/boot/dts/arm/juno-base.dtsi +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -5,7 +5,6 @@ /* * Devices shared by all Juno boards */ - dma-ranges = <0 0 0 0 0x100 0>; memtimer: timer@2a810000 { compatible = "arm,armv7-timer-mem"; -- GitLab From f6c6d170f947638e45166efc3e13e97a70067460 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Wed, 15 Jan 2020 13:00:59 -0500 Subject: [PATCH 0271/1055] reiserfs: fix handling of -EOPNOTSUPP in reiserfs_for_each_xattr commit 394440d469413fa9b74f88a11f144d76017221f2 upstream. Commit 60e4cf67a58 (reiserfs: fix extended attributes on the root directory) introduced a regression open_xa_root started returning -EOPNOTSUPP but it was not handled properly in reiserfs_for_each_xattr. When the reiserfs module is built without CONFIG_REISERFS_FS_XATTR, deleting an inode would result in a warning and chowning an inode would also result in a warning and then fail to complete. With CONFIG_REISERFS_FS_XATTR enabled, the xattr root would always be present for read-write operations. This commit handles -EOPNOSUPP in the same way -ENODATA is handled. Fixes: 60e4cf67a582 ("reiserfs: fix extended attributes on the root directory") CC: stable@vger.kernel.org # Commit 60e4cf67a58 was picked up by stable Link: https://lore.kernel.org/r/20200115180059.6935-1-jeffm@suse.com Reported-by: Michael Brunnbauer Signed-off-by: Jeff Mahoney Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/reiserfs/xattr.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 29a0c0969e91..28f6daf371d3 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -319,8 +319,12 @@ static int reiserfs_for_each_xattr(struct inode *inode, out_dir: dput(dir); out: - /* -ENODATA isn't an error */ - if (err == -ENODATA) + /* + * -ENODATA: this object doesn't have any xattrs + * -EOPNOTSUPP: this file system doesn't have xattrs enabled on disk. + * Neither are errors + */ + if (err == -ENODATA || err == -EOPNOTSUPP) err = 0; return err; } -- GitLab From bf94a6aa2aace00d656389d44375a124892a77ed Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 22 Oct 2019 13:23:24 +0300 Subject: [PATCH 0272/1055] scsi: esas2r: unlock on error in esas2r_nvram_read_direct() commit 906ca6353ac09696c1bf0892513c8edffff5e0a6 upstream. This error path is missing an unlock. Fixes: 26780d9e12ed ("[SCSI] esas2r: ATTO Technology ExpressSAS 6G SAS/SATA RAID Adapter Driver") Link: https://lore.kernel.org/r/20191022102324.GA27540@mwanda Signed-off-by: Dan Carpenter Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/esas2r/esas2r_flash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/esas2r/esas2r_flash.c b/drivers/scsi/esas2r/esas2r_flash.c index 7bd376d95ed5..b02ac389e6c6 100644 --- a/drivers/scsi/esas2r/esas2r_flash.c +++ b/drivers/scsi/esas2r/esas2r_flash.c @@ -1197,6 +1197,7 @@ bool esas2r_nvram_read_direct(struct esas2r_adapter *a) if (!esas2r_read_flash_block(a, a->nvram, FLS_OFFSET_NVR, sizeof(struct esas2r_sas_nvram))) { esas2r_hdebug("NVRAM read failed, using defaults"); + up(&a->nvram_semaphore); return false; } -- GitLab From f88c50ceca6d4cc777b3f6e0d49c4cdcfc7b67f6 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Tue, 5 Nov 2019 17:25:27 +0800 Subject: [PATCH 0273/1055] scsi: qla4xxx: fix double free bug commit 3fe3d2428b62822b7b030577cd612790bdd8c941 upstream. The variable init_fw_cb is released twice, resulting in a double free bug. The call to the function dma_free_coherent() before goto is removed to get rid of potential double free. Fixes: 2a49a78ed3c8 ("[SCSI] qla4xxx: added IPv6 support.") Link: https://lore.kernel.org/r/1572945927-27796-1-git-send-email-bianpan2016@163.com Signed-off-by: Pan Bian Acked-by: Manish Rangankar Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla4xxx/ql4_mbx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 1da04f323d38..c402fc583da3 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -641,9 +641,6 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) != QLA_SUCCESS) { - dma_free_coherent(&ha->pdev->dev, - sizeof(struct addr_ctrl_blk), - init_fw_cb, init_fw_cb_dma); goto exit_init_fw_cb; } -- GitLab From 3bf34ef5202275b5515a5756b59e10094b4965fe Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Wed, 6 Nov 2019 20:32:21 +0800 Subject: [PATCH 0274/1055] scsi: bnx2i: fix potential use after free commit 29d28f2b8d3736ac61c28ef7e20fda63795b74d9 upstream. The member hba->pcidev may be used after its reference is dropped. Move the put function to where it is never used to avoid potential use after free issues. Fixes: a77171806515 ("[SCSI] bnx2i: Removed the reference to the netdev->base_addr") Link: https://lore.kernel.org/r/1573043541-19126-1-git-send-email-bianpan2016@163.com Signed-off-by: Pan Bian Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/bnx2i/bnx2i_iscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 03c104b47f31..b832bd0ce202 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -915,12 +915,12 @@ void bnx2i_free_hba(struct bnx2i_hba *hba) INIT_LIST_HEAD(&hba->ep_ofld_list); INIT_LIST_HEAD(&hba->ep_active_list); INIT_LIST_HEAD(&hba->ep_destroy_list); - pci_dev_put(hba->pcidev); if (hba->regview) { pci_iounmap(hba->pcidev, hba->regview); hba->regview = NULL; } + pci_dev_put(hba->pcidev); bnx2i_free_mp_bdt(hba); bnx2i_release_free_cid_que(hba); iscsi_host_free(shost); -- GitLab From 3cb816cf0e2409d669be267a998fce3cf0e5690b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 7 Nov 2019 13:55:25 -0800 Subject: [PATCH 0275/1055] scsi: target: core: Fix a pr_debug() argument commit c941e0d172605731de9b4628bd4146d35cf2e7d6 upstream. Print the string for which conversion failed instead of printing the function name twice. Fixes: 2650d71e244f ("target: move transport ID handling to the core") Cc: Christoph Hellwig Link: https://lore.kernel.org/r/20191107215525.64415-1-bvanassche@acm.org Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_fabric_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index 508da345b73f..95aa47ac4dcd 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -131,7 +131,7 @@ static int srp_get_pr_transport_id( memset(buf + 8, 0, leading_zero_bytes); rc = hex2bin(buf + 8 + leading_zero_bytes, p, count); if (rc < 0) { - pr_debug("hex2bin failed for %s: %d\n", __func__, rc); + pr_debug("hex2bin failed for %s: %d\n", p, rc); return rc; } -- GitLab From ba0ef168a2635cb1c80b30c185ddf06366223e11 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Thu, 21 Nov 2019 13:40:47 +0800 Subject: [PATCH 0276/1055] scsi: qla2xxx: Fix qla2x00_request_irqs() for MSI commit 45dc8f2d9c94ed74a5e31e63e9136a19a7e16081 upstream. Commit 4fa183455988 ("scsi: qla2xxx: Utilize pci_alloc_irq_vectors/ pci_free_irq_vectors calls.") use pci_alloc_irq_vectors() to replace pci_enable_msi() but it didn't handle the return value correctly. This bug make qla2x00 always fail to setup MSI if MSI-X fail, so fix it. BTW, improve the log message of return value in qla2x00_request_irqs() to avoid confusion. Fixes: 4fa183455988 ("scsi: qla2xxx: Utilize pci_alloc_irq_vectors/pci_free_irq_vectors calls.") Cc: Michael Hernandez Link: https://lore.kernel.org/r/1574314847-14280-1-git-send-email-chenhc@lemote.com Signed-off-by: Huacai Chen Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_isr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 7f2da56274bd..648916a9082c 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3519,7 +3519,7 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) skip_msix: ql_log(ql_log_info, vha, 0x0037, - "Falling back-to MSI mode -%d.\n", ret); + "Falling back-to MSI mode -- ret=%d.\n", ret); if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) && !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha) && @@ -3527,13 +3527,13 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) goto skip_msi; ret = pci_alloc_irq_vectors(ha->pdev, 1, 1, PCI_IRQ_MSI); - if (!ret) { + if (ret > 0) { ql_dbg(ql_dbg_init, vha, 0x0038, "MSI: Enabled.\n"); ha->flags.msi_enabled = 1; } else ql_log(ql_log_warn, vha, 0x0039, - "Falling back-to INTa mode -- %d.\n", ret); + "Falling back-to INTa mode -- ret=%d.\n", ret); skip_msi: /* Skip INTx on ISP82xx. */ -- GitLab From 12b61fb73c7c02ba89b722d95a25619473684ff8 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 22 Nov 2019 22:19:22 +0000 Subject: [PATCH 0277/1055] scsi: qla2xxx: fix rports not being mark as lost in sync fabric scan commit d341e9a8f2cffe4000c610225c629f62c7489c74 upstream. In qla2x00_find_all_fabric_devs(), fcport->flags & FCF_LOGIN_NEEDED is a necessary condition for logging into new rports, but not for dropping lost ones. Fixes: 726b85487067 ("qla2xxx: Add framework for async fabric discovery") Link: https://lore.kernel.org/r/20191122221912.20100-2-martin.wilck@suse.com Tested-by: David Bond Signed-off-by: Martin Wilck Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index bd2421863510..a66f7cec797c 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -5145,8 +5145,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) break; - if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 || - (fcport->flags & FCF_LOGIN_NEEDED) == 0) + if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) continue; if (fcport->scan_state == QLA_FCPORT_SCAN) { @@ -5171,7 +5170,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) } } - if (fcport->scan_state == QLA_FCPORT_FOUND) + if (fcport->scan_state == QLA_FCPORT_FOUND && + (fcport->flags & FCF_LOGIN_NEEDED) != 0) qla24xx_fcport_handle_login(vha, fcport); } return (rval); -- GitLab From 1958113a576a0d9d88f267f64fb2167dfb649d0e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 1 Nov 2019 14:14:47 -0700 Subject: [PATCH 0278/1055] scsi: core: scsi_trace: Use get_unaligned_be*() commit b1335f5b0486f61fb66b123b40f8e7a98e49605d upstream. This patch fixes an unintended sign extension on left shifts. From Colin King: "Shifting a u8 left will cause the value to be promoted to an integer. If the top bit of the u8 is set then the following conversion to an u64 will sign extend the value causing the upper 32 bits to be set in the result." Fix this by using get_unaligned_be*() instead. Fixes: bf8162354233 ("[SCSI] add scsi trace core functions and put trace points") Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Douglas Gilbert Link: https://lore.kernel.org/r/20191101211447.187151-1-bvanassche@acm.org Reported-by: Colin Ian King Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_trace.c | 113 +++++++++++--------------------------- 1 file changed, 33 insertions(+), 80 deletions(-) diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c index 617a60737590..22472d140ef7 100644 --- a/drivers/scsi/scsi_trace.c +++ b/drivers/scsi/scsi_trace.c @@ -21,7 +21,7 @@ #include #define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f) -#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9]) +#define SERVICE_ACTION32(cdb) (get_unaligned_be16(&cdb[8])) static const char * scsi_trace_misc(struct trace_seq *, unsigned char *, int); @@ -51,17 +51,12 @@ static const char * scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - sector_t lba = 0, txlen = 0; + u32 lba, txlen; - lba |= (cdb[2] << 24); - lba |= (cdb[3] << 16); - lba |= (cdb[4] << 8); - lba |= cdb[5]; - txlen |= (cdb[7] << 8); - txlen |= cdb[8]; + lba = get_unaligned_be32(&cdb[2]); + txlen = get_unaligned_be16(&cdb[7]); - trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", - (unsigned long long)lba, (unsigned long long)txlen, + trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen, cdb[1] >> 5); if (cdb[0] == WRITE_SAME) @@ -76,19 +71,12 @@ static const char * scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - sector_t lba = 0, txlen = 0; - - lba |= (cdb[2] << 24); - lba |= (cdb[3] << 16); - lba |= (cdb[4] << 8); - lba |= cdb[5]; - txlen |= (cdb[6] << 24); - txlen |= (cdb[7] << 16); - txlen |= (cdb[8] << 8); - txlen |= cdb[9]; - - trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", - (unsigned long long)lba, (unsigned long long)txlen, + u32 lba, txlen; + + lba = get_unaligned_be32(&cdb[2]); + txlen = get_unaligned_be32(&cdb[6]); + + trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen, cdb[1] >> 5); trace_seq_putc(p, 0); @@ -99,23 +87,13 @@ static const char * scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - sector_t lba = 0, txlen = 0; - - lba |= ((u64)cdb[2] << 56); - lba |= ((u64)cdb[3] << 48); - lba |= ((u64)cdb[4] << 40); - lba |= ((u64)cdb[5] << 32); - lba |= (cdb[6] << 24); - lba |= (cdb[7] << 16); - lba |= (cdb[8] << 8); - lba |= cdb[9]; - txlen |= (cdb[10] << 24); - txlen |= (cdb[11] << 16); - txlen |= (cdb[12] << 8); - txlen |= cdb[13]; - - trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", - (unsigned long long)lba, (unsigned long long)txlen, + u64 lba; + u32 txlen; + + lba = get_unaligned_be64(&cdb[2]); + txlen = get_unaligned_be32(&cdb[10]); + + trace_seq_printf(p, "lba=%llu txlen=%u protect=%u", lba, txlen, cdb[1] >> 5); if (cdb[0] == WRITE_SAME_16) @@ -130,8 +108,8 @@ static const char * scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p), *cmd; - sector_t lba = 0, txlen = 0; - u32 ei_lbrt = 0; + u64 lba; + u32 ei_lbrt, txlen; switch (SERVICE_ACTION32(cdb)) { case READ_32: @@ -151,26 +129,12 @@ scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) goto out; } - lba |= ((u64)cdb[12] << 56); - lba |= ((u64)cdb[13] << 48); - lba |= ((u64)cdb[14] << 40); - lba |= ((u64)cdb[15] << 32); - lba |= (cdb[16] << 24); - lba |= (cdb[17] << 16); - lba |= (cdb[18] << 8); - lba |= cdb[19]; - ei_lbrt |= (cdb[20] << 24); - ei_lbrt |= (cdb[21] << 16); - ei_lbrt |= (cdb[22] << 8); - ei_lbrt |= cdb[23]; - txlen |= (cdb[28] << 24); - txlen |= (cdb[29] << 16); - txlen |= (cdb[30] << 8); - txlen |= cdb[31]; - - trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u", - cmd, (unsigned long long)lba, - (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt); + lba = get_unaligned_be64(&cdb[12]); + ei_lbrt = get_unaligned_be32(&cdb[20]); + txlen = get_unaligned_be32(&cdb[28]); + + trace_seq_printf(p, "%s_32 lba=%llu txlen=%u protect=%u ei_lbrt=%u", + cmd, lba, txlen, cdb[10] >> 5, ei_lbrt); if (SERVICE_ACTION32(cdb) == WRITE_SAME_32) trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1); @@ -185,7 +149,7 @@ static const char * scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - unsigned int regions = cdb[7] << 8 | cdb[8]; + unsigned int regions = get_unaligned_be16(&cdb[7]); trace_seq_printf(p, "regions=%u", (regions - 8) / 16); trace_seq_putc(p, 0); @@ -197,8 +161,8 @@ static const char * scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p), *cmd; - sector_t lba = 0; - u32 alloc_len = 0; + u64 lba; + u32 alloc_len; switch (SERVICE_ACTION16(cdb)) { case SAI_READ_CAPACITY_16: @@ -212,21 +176,10 @@ scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) goto out; } - lba |= ((u64)cdb[2] << 56); - lba |= ((u64)cdb[3] << 48); - lba |= ((u64)cdb[4] << 40); - lba |= ((u64)cdb[5] << 32); - lba |= (cdb[6] << 24); - lba |= (cdb[7] << 16); - lba |= (cdb[8] << 8); - lba |= cdb[9]; - alloc_len |= (cdb[10] << 24); - alloc_len |= (cdb[11] << 16); - alloc_len |= (cdb[12] << 8); - alloc_len |= cdb[13]; - - trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, - (unsigned long long)lba, alloc_len); + lba = get_unaligned_be64(&cdb[2]); + alloc_len = get_unaligned_be32(&cdb[10]); + + trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, lba, alloc_len); out: trace_seq_putc(p, 0); -- GitLab From 376bbcf2718ee48cc020771b0d3057ad6a27eb93 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 25 Oct 2019 17:46:25 +0900 Subject: [PATCH 0279/1055] perf probe: Fix wrong address verification commit 07d369857808b7e8e471bbbbb0074a6718f89b31 upstream. Since there are some DIE which has only ranges instead of the combination of entrypc/highpc, address verification must use dwarf_haspc() instead of dwarf_entrypc/dwarf_highpc. Also, the ranges only DIE will have a partial code in different section (e.g. unlikely code will be in text.unlikely as "FUNC.cold" symbol). In that case, we can not use dwarf_entrypc() or die_entrypc(), because the offset from original DIE can be a minus value. Instead, this simply gets the symbol and offset from symtab. Without this patch; # perf probe -D clear_tasks_mm_cpumask:1 Failed to get entry address of clear_tasks_mm_cpumask Error: Failed to add events. And with this patch: # perf probe -D clear_tasks_mm_cpumask:1 p:probe/clear_tasks_mm_cpumask clear_tasks_mm_cpumask+0 p:probe/clear_tasks_mm_cpumask_1 clear_tasks_mm_cpumask+5 p:probe/clear_tasks_mm_cpumask_2 clear_tasks_mm_cpumask+8 p:probe/clear_tasks_mm_cpumask_3 clear_tasks_mm_cpumask+16 p:probe/clear_tasks_mm_cpumask_4 clear_tasks_mm_cpumask+82 Committer testing: I managed to reproduce the above: [root@quaco ~]# perf probe -D clear_tasks_mm_cpumask:1 p:probe/clear_tasks_mm_cpumask _text+919968 p:probe/clear_tasks_mm_cpumask_1 _text+919973 p:probe/clear_tasks_mm_cpumask_2 _text+919976 [root@quaco ~]# But then when trying to actually put the probe in place, it fails if I use :0 as the offset: [root@quaco ~]# perf probe -L clear_tasks_mm_cpumask | head -5 0 void clear_tasks_mm_cpumask(int cpu) 1 { 2 struct task_struct *p; [root@quaco ~]# perf probe clear_tasks_mm_cpumask:0 Probe point 'clear_tasks_mm_cpumask' not found. Error: Failed to add events. [root@quaco The next patch is needed to fix this case. Fixes: 576b523721b7 ("perf probe: Fix probing symbols with optimization suffix") Reported-by: Arnaldo Carvalho de Melo Tested-by: Arnaldo Carvalho de Melo Signed-off-by: Masami Hiramatsu Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lore.kernel.org/lkml/157199318513.8075.10463906803299647907.stgit@devnote2 Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/probe-finder.c | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 30a5e92b67bd..893193bd28c1 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -615,38 +615,26 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, const char *function, struct probe_trace_point *tp) { - Dwarf_Addr eaddr, highaddr; + Dwarf_Addr eaddr; GElf_Sym sym; const char *symbol; /* Verify the address is correct */ - if (dwarf_entrypc(sp_die, &eaddr) != 0) { - pr_warning("Failed to get entry address of %s\n", - dwarf_diename(sp_die)); - return -ENOENT; - } - if (dwarf_highpc(sp_die, &highaddr) != 0) { - pr_warning("Failed to get end address of %s\n", - dwarf_diename(sp_die)); - return -ENOENT; - } - if (paddr > highaddr) { - pr_warning("Offset specified is greater than size of %s\n", + if (!dwarf_haspc(sp_die, paddr)) { + pr_warning("Specified offset is out of %s\n", dwarf_diename(sp_die)); return -EINVAL; } - symbol = dwarf_diename(sp_die); + /* Try to get actual symbol name from symtab */ + symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); if (!symbol) { - /* Try to get the symbol name from symtab */ - symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); - if (!symbol) { - pr_warning("Failed to find symbol at 0x%lx\n", - (unsigned long)paddr); - return -ENOENT; - } - eaddr = sym.st_value; + pr_warning("Failed to find symbol at 0x%lx\n", + (unsigned long)paddr); + return -ENOENT; } + eaddr = sym.st_value; + tp->offset = (unsigned long)(paddr - eaddr); tp->address = (unsigned long)paddr; tp->symbol = strdup(symbol); -- GitLab From 9513f5a492b9e766eaac9aec0e573d070ba62af0 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 6 Nov 2019 18:31:25 +0100 Subject: [PATCH 0280/1055] regulator: ab8500: Remove SYSCLKREQ from enum ab8505_regulator_id commit 458ea3ad033fc86e291712ce50cbe60c3428cf30 upstream. Those regulators are not actually supported by the AB8500 regulator driver. There is no ab8500_regulator_info for them and no entry in ab8505_regulator_match. As such, they cannot be registered successfully, and looking them up in ab8505_regulator_match causes an out-of-bounds array read. Fixes: 547f384f33db ("regulator: ab8500: add support for ab8505") Cc: Linus Walleij Signed-off-by: Stephan Gerhold Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20191106173125.14496-2-stephan@gerhold.net Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- include/linux/regulator/ab8500.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index 260c4aa1d976..3f6b8b9ef49d 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -43,8 +43,6 @@ enum ab8505_regulator_id { AB8505_LDO_ANAMIC2, AB8505_LDO_AUX8, AB8505_LDO_ANA, - AB8505_SYSCLKREQ_2, - AB8505_SYSCLKREQ_4, AB8505_NUM_REGULATORS, }; -- GitLab From 8bac50406cca10a219aa899243d49c57ddaf7c5b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 23 Jan 2020 08:20:37 +0100 Subject: [PATCH 0281/1055] Linux 4.14.167 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7c62b4078c1b..3e8eaabf2bcb 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 166 +SUBLEVEL = 167 EXTRAVERSION = NAME = Petit Gorille -- GitLab From 6fc3e71c91ef7030e70e4e5dad135841f32b9e4b Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Mon, 14 Oct 2019 14:11:57 -0700 Subject: [PATCH 0282/1055] UPSTREAM: mm/slub.c: init_on_free=1 should wipe freelist ptr for bulk allocations Upstream commit 0f181f9fbea8bc7ea2f7e13ae7f8c256b39e254c. slab_alloc_node() already zeroed out the freelist pointer if init_on_free was on. Thibaut Sautereau noticed that the same needs to be done for kmem_cache_alloc_bulk(), which performs the allocations separately. kmem_cache_alloc_bulk() is currently used in two places in the kernel, so this change is unlikely to have a major performance impact. SLAB doesn't require a similar change, as auto-initialization makes the allocator store the freelist pointers off-slab. Link: http://lkml.kernel.org/r/20191007091605.30530-1-glider@google.com Fixes: 6471384af2a6 ("mm: security: introduce init_on_alloc=1 and init_on_free=1 boot options") Signed-off-by: Alexander Potapenko Reported-by: Thibaut Sautereau Reported-by: Kees Cook Cc: Christoph Lameter Cc: Laura Abbott Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Bug: 138435492 Test: Boot an ARM64 mobile device with and without init_on_alloc=1 Change-Id: I05281c27d830867567d47d6a52faec7dc55e82fa Signed-off-by: Alexander Potapenko --- mm/slub.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 6f4d7d869a07..f9957084042a 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2691,6 +2691,17 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, return p; } +/* + * If the object has been wiped upon free, make sure it's fully initialized by + * zeroing out freelist pointer. + */ +static __always_inline void maybe_wipe_obj_freeptr(struct kmem_cache *s, + void *obj) +{ + if (unlikely(slab_want_init_on_free(s)) && obj) + memset((void *)((char *)obj + s->offset), 0, sizeof(void *)); +} + /* * Inlined fastpath so that allocation functions (kmalloc, kmem_cache_alloc) * have the fastpath folded into their functions. So no function call @@ -2779,12 +2790,8 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s, prefetch_freepointer(s, next_object); stat(s, ALLOC_FASTPATH); } - /* - * If the object has been wiped upon free, make sure it's fully - * initialized by zeroing out freelist pointer. - */ - if (unlikely(slab_want_init_on_free(s)) && object) - memset(object + s->offset, 0, sizeof(void *)); + + maybe_wipe_obj_freeptr(s, object); if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object) memset(object, 0, s->object_size); @@ -3199,10 +3206,13 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, goto error; c = this_cpu_ptr(s->cpu_slab); + maybe_wipe_obj_freeptr(s, p[i]); + continue; /* goto for-loop */ } c->freelist = get_freepointer(s, object); p[i] = object; + maybe_wipe_obj_freeptr(s, p[i]); } c->tid = next_tid(c->tid); local_irq_enable(); -- GitLab From 1871e5516480b7959f8570c7c105516ad39fa5d9 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Fri, 15 Nov 2019 17:34:50 -0800 Subject: [PATCH 0283/1055] UPSTREAM: mm: slub: really fix slab walking for init_on_free Upstream commit aea4df4c53f754cc229edde6c5465e481311cc49. Commit 1b7e816fc80e ("mm: slub: Fix slab walking for init_on_free") fixed one problem with the slab walking but missed a key detail: When walking the list, the head and tail pointers need to be updated since we end up reversing the list as a result. Without doing this, bulk free is broken. One way this is exposed is a NULL pointer with slub_debug=F: ============================================================================= BUG skbuff_head_cache (Tainted: G T): Object already free ----------------------------------------------------------------------------- INFO: Slab 0x000000000d2d2f8f objects=16 used=3 fp=0x0000000064309071 flags=0x3fff00000000201 BUG: kernel NULL pointer dereference, address: 0000000000000000 Oops: 0000 [#1] PREEMPT SMP PTI RIP: 0010:print_trailer+0x70/0x1d5 Call Trace: free_debug_processing.cold.37+0xc9/0x149 __slab_free+0x22a/0x3d0 kmem_cache_free_bulk+0x415/0x420 __kfree_skb_flush+0x30/0x40 net_rx_action+0x2dd/0x480 __do_softirq+0xf0/0x246 irq_exit+0x93/0xb0 do_IRQ+0xa0/0x110 common_interrupt+0xf/0xf Given we're now almost identical to the existing debugging code which correctly walks the list, combine with that. Link: https://lkml.kernel.org/r/20191104170303.GA50361@gandi.net Link: http://lkml.kernel.org/r/20191106222208.26815-1-labbott@redhat.com Fixes: 1b7e816fc80e ("mm: slub: Fix slab walking for init_on_free") Signed-off-by: Laura Abbott Reported-by: Thibaut Sautereau Acked-by: David Rientjes Tested-by: Alexander Potapenko Acked-by: Alexander Potapenko Cc: Kees Cook Cc: "David S. Miller" Cc: Vlastimil Babka Cc: Cc: Christoph Lameter Cc: Pekka Enberg Cc: Joonsoo Kim Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Bug: 138435492 Test: Boot an ARM64 mobile device with and without init_on_alloc=1 Change-Id: I33bbdadfe85ed73a70ba9edbd708105492a1b08a Signed-off-by: Alexander Potapenko --- mm/slub.c | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index f9957084042a..22704e373480 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1416,12 +1416,15 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, void *old_tail = *tail ? *tail : *head; int rsize; - if (slab_want_init_on_free(s)) { - void *p = NULL; + /* Head and tail of the reconstructed freelist */ + *head = NULL; + *tail = NULL; - do { - object = next; - next = get_freepointer(s, object); + do { + object = next; + next = get_freepointer(s, object); + + if (slab_want_init_on_free(s)) { /* * Clear the object and the metadata, but don't touch * the redzone. @@ -1431,29 +1434,8 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, : 0; memset((char *)object + s->inuse, 0, s->size - s->inuse - rsize); - set_freepointer(s, object, p); - p = object; - } while (object != old_tail); - } - -/* - * Compiler cannot detect this function can be removed if slab_free_hook() - * evaluates to nothing. Thus, catch all relevant config debug options here. - */ -#if defined(CONFIG_LOCKDEP) || \ - defined(CONFIG_DEBUG_KMEMLEAK) || \ - defined(CONFIG_DEBUG_OBJECTS_FREE) || \ - defined(CONFIG_KASAN) - next = *head; - - /* Head and tail of the reconstructed freelist */ - *head = NULL; - *tail = NULL; - - do { - object = next; - next = get_freepointer(s, object); + } /* If object's reuse doesn't have to be delayed */ if (!slab_free_hook(s, object)) { /* Move object to the new freelist */ @@ -1468,9 +1450,6 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, *tail = NULL; return *head != NULL; -#else - return true; -#endif } static void *setup_object(struct kmem_cache *s, struct page *page, -- GitLab From 6cef48327f062ddc4e9978454e1d99dcbf53f401 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Mon, 14 Oct 2019 14:12:00 -0700 Subject: [PATCH 0284/1055] UPSTREAM: lib/test_meminit: add a kmem_cache_alloc_bulk() test Upstream commit 03a9349ac0e095dea6ef8b5b7b14f9c23e5fabe6. Make sure allocations from kmem_cache_alloc_bulk() and kmem_cache_free_bulk() are properly initialized. Link: http://lkml.kernel.org/r/20191007091605.30530-2-glider@google.com Signed-off-by: Alexander Potapenko Cc: Kees Cook Cc: Christoph Lameter Cc: Laura Abbott Cc: Thibaut Sautereau Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Bug: 138435492 Test: Boot an ARM64 mobile device with and without init_on_alloc=1 Change-Id: I92476545a6212483136e58008736f333b0b36217 Signed-off-by: Alexander Potapenko --- lib/test_meminit.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/test_meminit.c b/lib/test_meminit.c index 9729f271d150..9742e5cb853a 100644 --- a/lib/test_meminit.c +++ b/lib/test_meminit.c @@ -297,6 +297,32 @@ static int __init do_kmem_cache_rcu_persistent(int size, int *total_failures) return 1; } +static int __init do_kmem_cache_size_bulk(int size, int *total_failures) +{ + struct kmem_cache *c; + int i, iter, maxiter = 1024; + int num, bytes; + bool fail = false; + void *objects[10]; + + c = kmem_cache_create("test_cache", size, size, 0, NULL); + for (iter = 0; (iter < maxiter) && !fail; iter++) { + num = kmem_cache_alloc_bulk(c, GFP_KERNEL, ARRAY_SIZE(objects), + objects); + for (i = 0; i < num; i++) { + bytes = count_nonzero_bytes(objects[i], size); + if (bytes) + fail = true; + fill_with_garbage(objects[i], size); + } + + if (num) + kmem_cache_free_bulk(c, num, objects); + } + *total_failures += fail; + return 1; +} + /* * Test kmem_cache allocation by creating caches of different sizes, with and * without constructors, with and without SLAB_TYPESAFE_BY_RCU. @@ -318,6 +344,7 @@ static int __init test_kmemcache(int *total_failures) num_tests += do_kmem_cache_size(size, ctor, rcu, zero, &failures); } + num_tests += do_kmem_cache_size_bulk(size, &failures); } REPORT_FAILURES_IN_FN(); *total_failures += failures; -- GitLab From 871760779918efb0ece64890d9a5e9b0fcbda57d Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Wed, 4 Dec 2019 16:51:53 -0800 Subject: [PATCH 0285/1055] UPSTREAM: lib/test_meminit.c: add bulk alloc/free tests Upstream commit dc5c5ad79f0cc2d8756d161dbdee7b370f35f5bb. kmem_cache_alloc_bulk/kmem_cache_free_bulk are used to make multiple allocations of the same size to avoid the overhead of multiple kmalloc/kfree calls. Extend the kmem_cache tests to make some calls to these APIs. Link: http://lkml.kernel.org/r/20191107191447.23058-1-labbott@redhat.com Signed-off-by: Laura Abbott Reviewed-by: Kees Cook Tested-by: Alexander Potapenko Cc: Laura Abbott Cc: Christoph Lameter Cc: Nick Desaulniers Cc: Kostya Serebryany Cc: Dmitry Vyukov Cc: Sandeep Patil Cc: Jann Horn Cc: Marco Elver Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Bug: 138435492 Test: Boot an ARM64 mobile device with and without init_on_alloc=1 Change-Id: Ic93b19613791f2d2b485457a9bbc0437279579bd Signed-off-by: Alexander Potapenko --- lib/test_meminit.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/test_meminit.c b/lib/test_meminit.c index 9742e5cb853a..e4f706a404b3 100644 --- a/lib/test_meminit.c +++ b/lib/test_meminit.c @@ -183,6 +183,9 @@ static bool __init check_buf(void *buf, int size, bool want_ctor, return fail; } +#define BULK_SIZE 100 +static void *bulk_array[BULK_SIZE]; + /* * Test kmem_cache with given parameters: * want_ctor - use a constructor; @@ -203,9 +206,24 @@ static int __init do_kmem_cache_size(size_t size, bool want_ctor, want_rcu ? SLAB_TYPESAFE_BY_RCU : 0, want_ctor ? test_ctor : NULL); for (iter = 0; iter < 10; iter++) { + /* Do a test of bulk allocations */ + if (!want_rcu && !want_ctor) { + int ret; + + ret = kmem_cache_alloc_bulk(c, alloc_mask, BULK_SIZE, bulk_array); + if (!ret) { + fail = true; + } else { + int i; + for (i = 0; i < ret; i++) + fail |= check_buf(bulk_array[i], size, want_ctor, want_rcu, want_zero); + kmem_cache_free_bulk(c, ret, bulk_array); + } + } + buf = kmem_cache_alloc(c, alloc_mask); /* Check that buf is zeroed, if it must be. */ - fail = check_buf(buf, size, want_ctor, want_rcu, want_zero); + fail |= check_buf(buf, size, want_ctor, want_rcu, want_zero); fill_with_garbage_skip(buf, size, want_ctor ? CTOR_BYTES : 0); if (!want_rcu) { -- GitLab From 1ed0039bde16a13c35feb3eb360d798dbc745106 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Wed, 22 Jan 2020 11:19:58 +0100 Subject: [PATCH 0286/1055] ANDROID: selinux: modify RTM_GETLINK permission Map the permission gating RTM_GETLINK messages to a new permission so that it can be distinguished from the other netlink route permissions in selinux policy. This is a temporary Android-only patch that will be deprecated in newer kernels once the long-term solution lands as discusssed on the mailing list [1]. The maintainer's recommended solution is more general, much more complex, and likely not suitable for backporting. This patch provides the minimal change needed for Android including the userspace settable trigger which ensures that the permission change is only applied to the newest version of Android which contains the changes needed for userpace compatibility. [1]: https://lore.kernel.org/selinux/20200116142653.61738-1-jeffv@google.com/ Bug: 141455849 Bug: 148218425 Test: CtsSelinuxTargetSdkCurrentTestCases Test: atest bionic-unit-tests-static Test: atest NetworkInterfaceTest Test: Connect to Wi-Fi network Test: Set up hotspot Test: Cast from device Test: Pair Bluetooth device Test: Call getifaddrs() directly from within an app. Test: Call NetworkInterface#getNetworkInterfaces() from within an app. Change-Id: I7b44ce60ad98f858c412722d41b9842f8577151f Signed-off-by: Jeff Vander Stoep --- security/selinux/include/classmap.h | 2 +- security/selinux/include/security.h | 9 +++++++++ security/selinux/nlmsgtab.c | 26 +++++++++++++++++++++++++- security/selinux/ss/policydb.c | 4 ++++ security/selinux/ss/policydb.h | 2 ++ security/selinux/ss/services.c | 3 +++ 6 files changed, 44 insertions(+), 2 deletions(-) diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 000effa857aa..34631690b5f9 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -115,7 +115,7 @@ struct security_class_mapping secclass_map[] = { { COMMON_IPC_PERMS, NULL } }, { "netlink_route_socket", { COMMON_SOCK_PERMS, - "nlmsg_read", "nlmsg_write", NULL } }, + "nlmsg_read", "nlmsg_write", "nlmsg_readpriv", NULL } }, { "netlink_tcpdiag_socket", { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", NULL } }, diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 0b3f3cc0c6a7..f64e33b23cd9 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -104,6 +104,7 @@ struct selinux_state { bool checkreqprot; bool initialized; bool policycap[__POLICYDB_CAPABILITY_MAX]; + bool android_netlink_route; struct selinux_avc *avc; struct selinux_ss *ss; }; @@ -176,6 +177,13 @@ static inline bool selinux_policycap_nnp_nosuid_transition(void) return state->policycap[POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION]; } +static inline bool selinux_android_nlroute_getlink(void) +{ + struct selinux_state *state = &selinux_state; + + return state->android_netlink_route; +} + int security_mls_enabled(struct selinux_state *state); int security_load_policy(struct selinux_state *state, void *data, size_t len); @@ -390,6 +398,7 @@ extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); extern void avtab_cache_init(void); extern void ebitmap_cache_init(void); extern void hashtab_cache_init(void); +extern void selinux_nlmsg_init(void); extern int security_sidtab_hash_stats(struct selinux_state *state, char *page); #endif /* _SELINUX_SECURITY_H_ */ diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 7b7433a1a34c..6a93edf01cfb 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -28,7 +28,7 @@ struct nlmsg_perm { u32 perm; }; -static const struct nlmsg_perm nlmsg_route_perms[] = +static struct nlmsg_perm nlmsg_route_perms[] = { { RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, { RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, @@ -195,3 +195,27 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) return err; } + +static void nlmsg_set_getlink_perm(u32 perm) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(nlmsg_route_perms); i++) { + if (nlmsg_route_perms[i].nlmsg_type == RTM_GETLINK) { + nlmsg_route_perms[i].perm = perm; + break; + } + } +} + +/** + * Use nlmsg_readpriv as the permission for RTM_GETLINK messages if the + * netlink_route_getlink policy capability is set. Otherwise use nlmsg_read. + */ +void selinux_nlmsg_init(void) +{ + if (selinux_android_nlroute_getlink()) + nlmsg_set_getlink_perm(NETLINK_ROUTE_SOCKET__NLMSG_READPRIV); + else + nlmsg_set_getlink_perm(NETLINK_ROUTE_SOCKET__NLMSG_READ); +} diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 57e608f8a20c..2472b2a66f70 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -2400,6 +2400,10 @@ int policydb_read(struct policydb *p, void *fp) p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); + if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_ANDROID_NETLINK_ROUTE)) { + p->android_netlink_route = 1; + } + if (p->policyvers >= POLICYDB_VERSION_POLCAP) { rc = ebitmap_read(&p->policycaps, fp); if (rc) diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 215f8f30ac5a..dbb0ed57ed8b 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -238,6 +238,7 @@ struct genfs { /* The policy database */ struct policydb { int mls_enabled; + int android_netlink_route; /* symbol tables */ struct symtab symtab[SYM_NUM]; @@ -324,6 +325,7 @@ extern int policydb_write(struct policydb *p, void *fp); #define PERM_SYMTAB_SIZE 32 #define POLICYDB_CONFIG_MLS 1 +#define POLICYDB_CONFIG_ANDROID_NETLINK_ROUTE (1 << 31) /* the config flags related to unknown classes/perms are bits 2 and 3 */ #define REJECT_UNKNOWN 0x00000002 diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index c21b0cfe0de3..98c418060032 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2107,6 +2107,9 @@ static void security_load_policycaps(struct selinux_state *state) pr_info("SELinux: unknown policy capability %u\n", i); } + + state->android_netlink_route = p->android_netlink_route; + selinux_nlmsg_init(); } static int security_preserve_bools(struct selinux_state *state, -- GitLab From 44a6aea9c219f55862776435b918c539855a9e69 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Thu, 23 Jan 2020 09:51:14 +0100 Subject: [PATCH 0287/1055] Revert "ANDROID: security,perf: Allow further restriction of perf_event_open" Unfork Android. This reverts commit 8e5e42d5ae20f0324170d01ccf374a1571e82d9b. Perf_event_paranoid=3 is no longer needed on Android. Access control of perf events is now done by selinux. See: https://patchwork.kernel.org/patch/11185793/ Bug: 120445712 Bug: 137092007 Signed-off-by: Jeff Vander Stoep Change-Id: Iba493424174b30baff460caaa25a54a472c87bd4 --- Documentation/sysctl/kernel.txt | 4 +--- arch/arm64/configs/cuttlefish_defconfig | 1 - arch/x86/configs/x86_64_cuttlefish_defconfig | 1 - include/linux/perf_event.h | 5 ----- kernel/events/core.c | 8 -------- security/Kconfig | 9 --------- 6 files changed, 1 insertion(+), 27 deletions(-) diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index b757d6eb365b..694968c7523c 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -653,8 +653,7 @@ allowed to execute. perf_event_paranoid: Controls use of the performance events system by unprivileged -users (without CAP_SYS_ADMIN). The default value is 3 if -CONFIG_SECURITY_PERF_EVENTS_RESTRICT is set, or 2 otherwise. +users (without CAP_SYS_ADMIN). The default value is 2. -1: Allow use of (almost) all events by all users Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK @@ -662,7 +661,6 @@ CONFIG_SECURITY_PERF_EVENTS_RESTRICT is set, or 2 otherwise. Disallow raw tracepoint access by users without CAP_SYS_ADMIN >=1: Disallow CPU event access by users without CAP_SYS_ADMIN >=2: Disallow kernel profiling by users without CAP_SYS_ADMIN ->=3: Disallow all event access by users without CAP_SYS_ADMIN ============================================================== diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index c2700608d034..fe9a24b182f2 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -455,7 +455,6 @@ CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y CONFIG_RCU_CPU_STALL_TIMEOUT=60 CONFIG_ENABLE_DEFAULT_TRACERS=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=65536 diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 0cee03ee5f2c..095a60dc538c 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -483,7 +483,6 @@ CONFIG_IO_DELAY_NONE=y CONFIG_DEBUG_BOOT_PARAMS=y CONFIG_OPTIMIZE_INLINING=y CONFIG_UNWINDER_FRAME_POINTER=y -CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_PATH=y diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 5d798eb5ac0a..ff924b5fd0b8 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1187,11 +1187,6 @@ int perf_event_max_stack_handler(struct ctl_table *table, int write, #define PERF_SECURITY_KERNEL 2 #define PERF_SECURITY_TRACEPOINT 3 -static inline bool perf_paranoid_any(void) -{ - return sysctl_perf_event_paranoid > 2; -} - static inline int perf_is_paranoid(void) { return sysctl_perf_event_paranoid > -1; diff --git a/kernel/events/core.c b/kernel/events/core.c index e24e2d558cbc..70d70c2db18a 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -397,13 +397,8 @@ static cpumask_var_t perf_online_mask; * 0 - disallow raw tracepoint access for unpriv * 1 - disallow cpu events for unpriv * 2 - disallow kernel profiling for unpriv - * 3 - disallow all unpriv perf event use */ -#ifdef CONFIG_SECURITY_PERF_EVENTS_RESTRICT -int sysctl_perf_event_paranoid __read_mostly = 3; -#else int sysctl_perf_event_paranoid __read_mostly = 2; -#endif /* Minimum for 512 kiB + 1 user control page */ int sysctl_perf_event_mlock __read_mostly = 512 + (PAGE_SIZE / 1024); /* 'free' kiB per user */ @@ -10054,9 +10049,6 @@ SYSCALL_DEFINE5(perf_event_open, if (flags & ~PERF_FLAG_ALL) return -EINVAL; - if (perf_paranoid_any() && !capable(CAP_SYS_ADMIN)) - return -EACCES; - /* Do we allow access to perf_event_open(2) ? */ err = security_perf_event_open(&attr, PERF_SECURITY_OPEN); if (err) diff --git a/security/Kconfig b/security/Kconfig index 8b6c5e9528e0..3a66cd8363c0 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -18,15 +18,6 @@ config SECURITY_DMESG_RESTRICT If you are unsure how to answer this question, answer N. -config SECURITY_PERF_EVENTS_RESTRICT - bool "Restrict unprivileged use of performance events" - depends on PERF_EVENTS - help - If you say Y here, the kernel.perf_event_paranoid sysctl - will be set to 3 by default, and no unprivileged use of the - perf_event_open syscall will be permitted unless it is - changed. - config SECURITY bool "Enable different security models" depends on SYSFS -- GitLab From f48fcae0ed4491875e6f98356ca5173dad3065ea Mon Sep 17 00:00:00 2001 From: Minchan Kim Date: Sat, 30 Nov 2019 17:58:29 -0800 Subject: [PATCH 0288/1055] UPSTREAM: mm/page_io.c: annotate refault stalls from swap_readpage If a block device supports rw_page operation, it doesn't submit bios so the annotation in submit_bio() for refault stall doesn't work. It happens with zram in android, especially swap read path which could consume CPU cycle for decompress. It is also a problem for zswap which uses frontswap. Annotate swap_readpage() to account the synchronous IO overhead to prevent underreport memory pressure. [akpm@linux-foundation.org: add comment, per Johannes] Link: http://lkml.kernel.org/r/20191010152134.38545-1-minchan@kernel.org Signed-off-by: Minchan Kim Acked-by: Johannes Weiner Reviewed-by: Shakeel Butt Cc: Seth Jennings Cc: Dan Streetman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit 937790699be9c8100e5358625e7dfa8b32bd33f2) Bug: 142418748 Signed-off-by: Suren Baghdasaryan Change-Id: I8a63030888996b6c0a3a9abe3f2d0eca0a0d765b --- mm/page_io.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/mm/page_io.c b/mm/page_io.c index 5d882de3fbfd..9f8fd8f42b0d 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -354,10 +355,19 @@ int swap_readpage(struct page *page, bool do_poll) struct swap_info_struct *sis = page_swap_info(page); blk_qc_t qc; struct gendisk *disk; + unsigned long pflags; VM_BUG_ON_PAGE(!PageSwapCache(page), page); VM_BUG_ON_PAGE(!PageLocked(page), page); VM_BUG_ON_PAGE(PageUptodate(page), page); + + /* + * Count submission time as memory stall. When the device is congested, + * or the submitting cgroup IO-throttled, submission can be a + * significant part of overall IO time. + */ + psi_memstall_enter(&pflags); + if (frontswap_load(page) == 0) { SetPageUptodate(page); unlock_page(page); @@ -371,7 +381,7 @@ int swap_readpage(struct page *page, bool do_poll) ret = mapping->a_ops->readpage(swap_file, page); if (!ret) count_vm_event(PSWPIN); - return ret; + goto out; } ret = bdev_read_page(sis->bdev, swap_page_sector(page), page); @@ -382,7 +392,7 @@ int swap_readpage(struct page *page, bool do_poll) } count_vm_event(PSWPIN); - return 0; + goto out; } ret = 0; @@ -415,6 +425,7 @@ int swap_readpage(struct page *page, bool do_poll) bio_put(bio); out: + psi_memstall_leave(&pflags); return ret; } -- GitLab From 5bbf2879a5bddbf4e8f8a18cabaae9ea5d6ec3b8 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Sun, 8 Dec 2019 12:43:44 -0800 Subject: [PATCH 0289/1055] FROMLIST: security: selinux: allow per-file labelling for binderfs This patch allows genfscon per-file labeling for binderfs. This is required to have separate permissions to allow access to binder, hwbinder and vndbinder devices which are relocating to binderfs. Acked-by: Jeff Vander Stoep Acked-by: Mark Salyzyn Signed-off-by: Hridya Valsaraju Bug: 136497735 (cherry picked from commit 7a4b51947475a7f67e2bd06c4a4c768e2e64a975 git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git master) Link: https://lore.kernel.org/patchwork/patch/1175776/ Change-Id: I105cc54b30ddd4120dc23a363bddc2f9d00e4dc4 --- security/selinux/hooks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 2595465dcd3b..134c7b5f8a0b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -870,6 +870,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, !strcmp(sb->s_type->name, "tracefs") || !strcmp(sb->s_type->name, "sysfs") || !strcmp(sb->s_type->name, "pstore") || + !strcmp(sb->s_type->name, "binder") || !strcmp(sb->s_type->name, "cgroup") || !strcmp(sb->s_type->name, "cgroup2")) sbsec->flags |= SE_SBGENFS; -- GitLab From b5bfb6b8912d1f198208c0b1f6d3ba46621fd714 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Fri, 6 Apr 2018 15:21:13 +1000 Subject: [PATCH 0290/1055] UPSTREAM: libnvdimm: Add of_node to region and bus descriptors We want to be able to cross reference the region and bus devices with the device tree node that they were spawned from. libNVDIMM handles creating the actual devices for these internally, so we need to pass in a pointer to the relevant node in the descriptor. Signed-off-by: Oliver O'Halloran Acked-by: Dan Williams Acked-by: Balbir Singh Signed-off-by: Dan Williams (cherry picked from commit 1ff19f487a7e55bf3cebc96ea2a9a38d66fb7db7) Bug: 146400078 Bug: 148297388 Change-Id: Id56dd9b51ab5bc79d89e79a7dc2e5dfb2a503bde Signed-off-by: Alistair Delva --- drivers/nvdimm/bus.c | 1 + drivers/nvdimm/region_devs.c | 1 + include/linux/libnvdimm.h | 3 +++ 3 files changed, 5 insertions(+) diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 2f1b54fab399..4587c9773560 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -358,6 +358,7 @@ struct nvdimm_bus *nvdimm_bus_register(struct device *parent, nvdimm_bus->dev.release = nvdimm_bus_release; nvdimm_bus->dev.groups = nd_desc->attr_groups; nvdimm_bus->dev.bus = &nvdimm_bus_type; + nvdimm_bus->dev.of_node = nd_desc->of_node; dev_set_name(&nvdimm_bus->dev, "ndbus%d", nvdimm_bus->id); rc = device_register(&nvdimm_bus->dev); if (rc) { diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 708043d20d0d..bd68b7b01d08 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -999,6 +999,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, dev->parent = &nvdimm_bus->dev; dev->type = dev_type; dev->groups = ndr_desc->attr_groups; + dev->of_node = ndr_desc->of_node; nd_region->ndr_size = resource_size(ndr_desc->res); nd_region->ndr_start = ndr_desc->res->start; nd_device_register(dev); diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 3eaad2fbf284..51edfc6394f0 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -53,12 +53,14 @@ typedef int (*ndctl_fn)(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc); +struct device_node; struct nvdimm_bus_descriptor { const struct attribute_group **attr_groups; unsigned long bus_dsm_mask; unsigned long cmd_mask; struct module *module; char *provider_name; + struct device_node *of_node; ndctl_fn ndctl; int (*flush_probe)(struct nvdimm_bus_descriptor *nd_desc); int (*clear_to_send)(struct nvdimm_bus_descriptor *nd_desc, @@ -100,6 +102,7 @@ struct nd_region_desc { int num_lanes; int numa_node; unsigned long flags; + struct device_node *of_node; }; struct device; -- GitLab From 3c91fbaf6c5e131a3d9b2c0e949e39c419c4efc1 Mon Sep 17 00:00:00 2001 From: Oliver O'Halloran Date: Fri, 6 Apr 2018 15:21:14 +1000 Subject: [PATCH 0291/1055] UPSTREAM: libnvdimm: Add device-tree based driver This patch adds peliminary device-tree bindings for persistent memory regions. The driver registers a libnvdimm bus for each pmem-region node and each address range under the node is converted to a region within that bus. Signed-off-by: Oliver O'Halloran Signed-off-by: Dan Williams (cherry picked from commit 7171976089528cb3d057a6fb288e7f8f89ab7f68) Bug: 146400078 Bug: 148297388 Change-Id: I1dc76c36adecd82c2e9a248c8012c7b31c146cd7 Signed-off-by: Alistair Delva --- MAINTAINERS | 7 +++ drivers/nvdimm/Kconfig | 10 ++++ drivers/nvdimm/Makefile | 1 + drivers/nvdimm/of_pmem.c | 119 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 drivers/nvdimm/of_pmem.c diff --git a/MAINTAINERS b/MAINTAINERS index 2cb45b54ed30..77c68f63e29f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7886,6 +7886,13 @@ Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ S: Supported F: drivers/nvdimm/pmem* +LIBNVDIMM: DEVICETREE BINDINGS +M: Oliver O'Halloran +L: linux-nvdimm@lists.01.org +Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ +S: Supported +F: drivers/nvdimm/of_pmem.c + LIBNVDIMM: NON-VOLATILE MEMORY DEVICE SUBSYSTEM M: Dan Williams L: linux-nvdimm@lists.01.org diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig index 5bdd499b5f4f..250471fa0fe6 100644 --- a/drivers/nvdimm/Kconfig +++ b/drivers/nvdimm/Kconfig @@ -102,4 +102,14 @@ config NVDIMM_DAX Select Y if unsure +config OF_PMEM + tristate "Device-tree support for persistent memory regions" + depends on OF + default LIBNVDIMM + help + Allows regions of persistent memory to be described in the + device-tree. + + Select Y if unsure. + endif diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile index 447e0e14f3b6..1192946e66af 100644 --- a/drivers/nvdimm/Makefile +++ b/drivers/nvdimm/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o obj-$(CONFIG_ND_BTT) += nd_btt.o obj-$(CONFIG_ND_BLK) += nd_blk.o obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o +obj-$(CONFIG_OF_PMEM) += of_pmem.o nd_pmem-y := pmem.o diff --git a/drivers/nvdimm/of_pmem.c b/drivers/nvdimm/of_pmem.c new file mode 100644 index 000000000000..85013bad35de --- /dev/null +++ b/drivers/nvdimm/of_pmem.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#define pr_fmt(fmt) "of_pmem: " fmt + +#include +#include +#include +#include +#include +#include + +static const struct attribute_group *region_attr_groups[] = { + &nd_region_attribute_group, + &nd_device_attribute_group, + NULL, +}; + +static const struct attribute_group *bus_attr_groups[] = { + &nvdimm_bus_attribute_group, + NULL, +}; + +struct of_pmem_private { + struct nvdimm_bus_descriptor bus_desc; + struct nvdimm_bus *bus; +}; + +static int of_pmem_region_probe(struct platform_device *pdev) +{ + struct of_pmem_private *priv; + struct device_node *np; + struct nvdimm_bus *bus; + bool is_volatile; + int i; + + np = dev_of_node(&pdev->dev); + if (!np) + return -ENXIO; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->bus_desc.attr_groups = bus_attr_groups; + priv->bus_desc.provider_name = "of_pmem"; + priv->bus_desc.module = THIS_MODULE; + priv->bus_desc.of_node = np; + + priv->bus = bus = nvdimm_bus_register(&pdev->dev, &priv->bus_desc); + if (!bus) { + kfree(priv); + return -ENODEV; + } + platform_set_drvdata(pdev, priv); + + is_volatile = !!of_find_property(np, "volatile", NULL); + dev_dbg(&pdev->dev, "Registering %s regions from %pOF\n", + is_volatile ? "volatile" : "non-volatile", np); + + for (i = 0; i < pdev->num_resources; i++) { + struct nd_region_desc ndr_desc; + struct nd_region *region; + + /* + * NB: libnvdimm copies the data from ndr_desc into it's own + * structures so passing a stack pointer is fine. + */ + memset(&ndr_desc, 0, sizeof(ndr_desc)); + ndr_desc.attr_groups = region_attr_groups; + ndr_desc.numa_node = of_node_to_nid(np); + ndr_desc.res = &pdev->resource[i]; + ndr_desc.of_node = np; + set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); + + if (is_volatile) + region = nvdimm_volatile_region_create(bus, &ndr_desc); + else + region = nvdimm_pmem_region_create(bus, &ndr_desc); + + if (!region) + dev_warn(&pdev->dev, "Unable to register region %pR from %pOF\n", + ndr_desc.res, np); + else + dev_dbg(&pdev->dev, "Registered region %pR from %pOF\n", + ndr_desc.res, np); + } + + return 0; +} + +static int of_pmem_region_remove(struct platform_device *pdev) +{ + struct of_pmem_private *priv = platform_get_drvdata(pdev); + + nvdimm_bus_unregister(priv->bus); + kfree(priv); + + return 0; +} + +static const struct of_device_id of_pmem_region_match[] = { + { .compatible = "pmem-region" }, + { }, +}; + +static struct platform_driver of_pmem_region_driver = { + .probe = of_pmem_region_probe, + .remove = of_pmem_region_remove, + .driver = { + .name = "of_pmem", + .owner = THIS_MODULE, + .of_match_table = of_pmem_region_match, + }, +}; + +module_platform_driver(of_pmem_region_driver); +MODULE_DEVICE_TABLE(of, of_pmem_region_match); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("IBM Corporation"); -- GitLab From 9ca89392289821befd5af5e9e99637a1ecd7cf02 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 16 Apr 2018 11:58:16 -0500 Subject: [PATCH 0292/1055] UPSTREAM: libnvdimm, of_pmem: use dev_to_node() instead of of_node_to_nid() Remove the direct dependency on of_node_to_nid() by using dev_to_node() instead. Any DT platform device will have its NUMA node id set when the device is created. With this, commit 291717b6fbdb ("libnvdimm, of_pmem: workaround OF_NUMA=n build error") can be reverted. Fixes: 717197608952 ("libnvdimm: Add device-tree based driver") Cc: Dan Williams Cc: Oliver O'Halloran Cc: linux-nvdimm@lists.01.org Signed-off-by: Rob Herring Signed-off-by: Dan Williams (cherry picked from commit df3f126482dba8e00cdbfc8fc44a05a5a35b1704) Bug: 146400078 Bug: 148297388 Change-Id: I87aed3d23c38a10b0f25e23cd438ade4f8073f28 Signed-off-by: Alistair Delva --- drivers/nvdimm/of_pmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvdimm/of_pmem.c b/drivers/nvdimm/of_pmem.c index 85013bad35de..0a701837dfc0 100644 --- a/drivers/nvdimm/of_pmem.c +++ b/drivers/nvdimm/of_pmem.c @@ -67,7 +67,7 @@ static int of_pmem_region_probe(struct platform_device *pdev) */ memset(&ndr_desc, 0, sizeof(ndr_desc)); ndr_desc.attr_groups = region_attr_groups; - ndr_desc.numa_node = of_node_to_nid(np); + ndr_desc.numa_node = dev_to_node(&pdev->dev); ndr_desc.res = &pdev->resource[i]; ndr_desc.of_node = np; set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); -- GitLab From afab16336a4d08b147f87cf85b06d0af6a31c2e5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 26 Feb 2019 01:42:53 +0000 Subject: [PATCH 0293/1055] UPSTREAM: libnvdimm/of_pmem: Fix platform_no_drv_owner.cocci warnings Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: YueHaibing Signed-off-by: Dan Williams (cherry picked from commit 316720b9c2341307b9a17103cdafa1ca9b2fb872) Bug: 146400078 Bug: 148297388 Change-Id: I16e7543bcb786e20e96ea4250a809bb3b7f1ec32 Signed-off-by: Alistair Delva --- drivers/nvdimm/of_pmem.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/nvdimm/of_pmem.c b/drivers/nvdimm/of_pmem.c index 0a701837dfc0..11b9821eba85 100644 --- a/drivers/nvdimm/of_pmem.c +++ b/drivers/nvdimm/of_pmem.c @@ -108,7 +108,6 @@ static struct platform_driver of_pmem_region_driver = { .remove = of_pmem_region_remove, .driver = { .name = "of_pmem", - .owner = THIS_MODULE, .of_match_table = of_pmem_region_match, }, }; -- GitLab From 28899aa1830df4283c7d8cef324abaad60109852 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Wed, 7 Aug 2019 09:30:29 +0530 Subject: [PATCH 0294/1055] UPSTREAM: libnvdimm/of_pmem: Provide a unique name for bus provider ndctl binaries, v66 and older, mistakenly require the ndbus to have unique names. If not while enumerating the bus in userspace it drops bus with similar names. This results in us not listing devices beneath the bus. Signed-off-by: Aneesh Kumar K.V Tested-by: Vaibhav Jain Link: https://lore.kernel.org/r/20190807040029.11344-1-aneesh.kumar@linux.ibm.com Signed-off-by: Dan Williams (cherry picked from commit 49bddc73d15c25a68e4294d76fc74519fda984cd) Bug: 146400078 Bug: 148297388 Change-Id: Ieda4557bbda63e554e2eda6b87d7ba2a6e149e3b Signed-off-by: Alistair Delva --- drivers/nvdimm/of_pmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvdimm/of_pmem.c b/drivers/nvdimm/of_pmem.c index 11b9821eba85..6e5cbfd8cb13 100644 --- a/drivers/nvdimm/of_pmem.c +++ b/drivers/nvdimm/of_pmem.c @@ -42,7 +42,7 @@ static int of_pmem_region_probe(struct platform_device *pdev) return -ENOMEM; priv->bus_desc.attr_groups = bus_attr_groups; - priv->bus_desc.provider_name = "of_pmem"; + priv->bus_desc.provider_name = kstrdup(pdev->name, GFP_KERNEL); priv->bus_desc.module = THIS_MODULE; priv->bus_desc.of_node = np; -- GitLab From 75875b04b1aeec995e2121d874e4bf62040a717b Mon Sep 17 00:00:00 2001 From: Pankaj Gupta Date: Fri, 5 Jul 2019 19:33:22 +0530 Subject: [PATCH 0295/1055] BACKPORT: libnvdimm: nd_region flush callback support This patch adds functionality to perform flush from guest to host over VIRTIO. We are registering a callback based on 'nd_region' type. virtio_pmem driver requires this special flush function. For rest of the region types we are registering existing flush function. Report error returned by host fsync failure to userspace. Signed-off-by: Pankaj Gupta Signed-off-by: Dan Williams (cherry picked from commit c5d4355d10d414a96ca870b731756b89d068d57a) [adelva: backport around some nvdimm refactors in >4.14] Bug: 146400078 Bug: 148297388 Change-Id: Icf6ff5327b3c74455a4d53d2d37ac7fef7fbda85 Signed-off-by: Alistair Delva --- drivers/acpi/nfit/core.c | 4 ++-- drivers/nvdimm/claim.c | 6 ++++-- drivers/nvdimm/nd.h | 1 + drivers/nvdimm/pmem.c | 13 ++++++++----- drivers/nvdimm/region_devs.c | 26 ++++++++++++++++++++++++-- include/linux/libnvdimm.h | 9 ++++++++- 6 files changed, 47 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 05fb821c2558..7e91575496b6 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1980,7 +1980,7 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw, offset = to_interleave_offset(offset, mmio); writeq(cmd, mmio->addr.base + offset); - nvdimm_flush(nfit_blk->nd_region); + nvdimm_flush(nfit_blk->nd_region, NULL); if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH) readq(mmio->addr.base + offset); @@ -2029,7 +2029,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, } if (rw) - nvdimm_flush(nfit_blk->nd_region); + nvdimm_flush(nfit_blk->nd_region, NULL); rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0; return rc; diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index b2fc29b8279b..32f2aaf62f27 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c @@ -263,7 +263,7 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns, struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev); unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512); sector_t sector = offset >> 9; - int rc = 0; + int rc = 0, ret = 0; if (unlikely(!size)) return 0; @@ -299,7 +299,9 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns, } memcpy_flushcache(nsio->addr + offset, buf, size); - nvdimm_flush(to_nd_region(ndns->dev.parent)); + ret = nvdimm_flush(to_nd_region(ndns->dev.parent), NULL); + if (ret) + rc = ret; return rc; } diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index e3f060f0b83e..b79a8d0f9b48 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -170,6 +170,7 @@ struct nd_region { struct badblocks bb; struct nd_interleave_set *nd_set; struct nd_percpu_lane __percpu *lane; + int (*flush)(struct nd_region *nd_region, struct bio *bio); struct nd_mapping mapping[0]; }; diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 80f8bbf83742..76934fadca97 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -169,6 +169,7 @@ static blk_status_t pmem_do_bvec(struct pmem_device *pmem, struct page *page, static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio) { + int ret = 0; blk_status_t rc = 0; bool do_acct; unsigned long start; @@ -178,7 +179,7 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio) struct nd_region *nd_region = to_region(pmem); if (bio->bi_opf & REQ_FLUSH) - nvdimm_flush(nd_region); + ret = nvdimm_flush(nd_region, bio); do_acct = nd_iostat_start(bio, &start); bio_for_each_segment(bvec, bio, iter) { @@ -194,7 +195,10 @@ static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio) nd_iostat_end(bio, start); if (bio->bi_opf & REQ_FUA) - nvdimm_flush(nd_region); + ret = nvdimm_flush(nd_region, bio); + + if (ret) + bio->bi_status = errno_to_blk_status(ret); bio_endio(bio); return BLK_QC_T_NONE; @@ -415,7 +419,6 @@ static int pmem_attach_disk(struct device *dev, } dax_write_cache(dax_dev, wbc); pmem->dax_dev = dax_dev; - gendev = disk_to_dev(disk); gendev->groups = pmem_attribute_groups; @@ -473,14 +476,14 @@ static int nd_pmem_remove(struct device *dev) sysfs_put(pmem->bb_state); pmem->bb_state = NULL; } - nvdimm_flush(to_nd_region(dev->parent)); + nvdimm_flush(to_nd_region(dev->parent), NULL); return 0; } static void nd_pmem_shutdown(struct device *dev) { - nvdimm_flush(to_nd_region(dev->parent)); + nvdimm_flush(to_nd_region(dev->parent), NULL); } static void nd_pmem_notify(struct device *dev, enum nvdimm_event event) diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index bd68b7b01d08..c0e6a6d235de 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -282,7 +282,9 @@ static ssize_t deep_flush_store(struct device *dev, struct device_attribute *att return rc; if (!flush) return -EINVAL; - nvdimm_flush(nd_region); + rc = nvdimm_flush(nd_region, NULL); + if (rc) + return rc; return len; } @@ -1002,6 +1004,11 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, dev->of_node = ndr_desc->of_node; nd_region->ndr_size = resource_size(ndr_desc->res); nd_region->ndr_start = ndr_desc->res->start; + if (ndr_desc->flush) + nd_region->flush = ndr_desc->flush; + else + nd_region->flush = NULL; + nd_device_register(dev); return nd_region; @@ -1042,11 +1049,24 @@ struct nd_region *nvdimm_volatile_region_create(struct nvdimm_bus *nvdimm_bus, } EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create); +int nvdimm_flush(struct nd_region *nd_region, struct bio *bio) +{ + int rc = 0; + + if (!nd_region->flush) + rc = generic_nvdimm_flush(nd_region); + else { + if (nd_region->flush(nd_region, bio)) + rc = -EIO; + } + + return rc; +} /** * nvdimm_flush - flush any posted write queues between the cpu and pmem media * @nd_region: blk or interleaved pmem region */ -void nvdimm_flush(struct nd_region *nd_region) +int generic_nvdimm_flush(struct nd_region *nd_region) { struct nd_region_data *ndrd = dev_get_drvdata(&nd_region->dev); int i, idx; @@ -1070,6 +1090,8 @@ void nvdimm_flush(struct nd_region *nd_region) if (ndrd_get_flush_wpq(ndrd, i, 0)) writeq(1, ndrd_get_flush_wpq(ndrd, i, idx)); wmb(); + + return 0; } EXPORT_SYMBOL_GPL(nvdimm_flush); diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 51edfc6394f0..84284e3353ed 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -18,6 +18,7 @@ #include #include #include +#include enum { /* when a dimm supports both PMEM and BLK access a label is required */ @@ -36,6 +37,9 @@ enum { /* region flag indicating to direct-map persistent memory by default */ ND_REGION_PAGEMAP = 0, + /* Platform provides asynchronous flush mechanism */ + ND_REGION_ASYNC = 3, + /* mark newly adjusted resources as requiring a label update */ DPA_RESOURCE_ADJUSTED = 1 << 0, }; @@ -92,6 +96,7 @@ struct nd_mapping_desc { int position; }; +struct nd_region; struct nd_region_desc { struct resource *res; struct nd_mapping_desc *mapping; @@ -103,6 +108,7 @@ struct nd_region_desc { int numa_node; unsigned long flags; struct device_node *of_node; + int (*flush)(struct nd_region *nd_region, struct bio *bio); }; struct device; @@ -174,7 +180,8 @@ unsigned long nd_blk_memremap_flags(struct nd_blk_region *ndbr); unsigned int nd_region_acquire_lane(struct nd_region *nd_region); void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane); u64 nd_fletcher64(void *addr, size_t len, bool le); -void nvdimm_flush(struct nd_region *nd_region); +int nvdimm_flush(struct nd_region *nd_region, struct bio *bio); +int generic_nvdimm_flush(struct nd_region *nd_region); int nvdimm_has_flush(struct nd_region *nd_region); int nvdimm_has_cache(struct nd_region *nd_region); -- GitLab From e2bc3b41bd16c48f198ac7dc7a552b6b2245e469 Mon Sep 17 00:00:00 2001 From: Pankaj Gupta Date: Fri, 5 Jul 2019 19:33:23 +0530 Subject: [PATCH 0296/1055] UPSTREAM: virtio-pmem: Add virtio pmem driver This patch adds virtio-pmem driver for KVM guest. Guest reads the persistent memory range information from Qemu over VIRTIO and registers it on nvdimm_bus. It also creates a nd_region object with the persistent memory range information so that existing 'nvdimm/pmem' driver can reserve this into system memory map. This way 'virtio-pmem' driver uses existing functionality of pmem driver to register persistent memory compatible for DAX capable filesystems. This also provides function to perform guest flush over VIRTIO from 'pmem' driver when userspace performs flush on DAX memory range. Signed-off-by: Pankaj Gupta Reviewed-by: Yuval Shaia Acked-by: Michael S. Tsirkin Acked-by: Jakub Staron Tested-by: Jakub Staron Reviewed-by: Cornelia Huck Signed-off-by: Dan Williams (cherry picked from commit 6e84200c0a2994b991259d19450eee561029bf70) Bug: 146400078 Bug: 148297388 Change-Id: Ie3457fe184f29984d181bc0afa9267e2567a2caf Signed-off-by: Alistair Delva --- drivers/nvdimm/Makefile | 1 + drivers/nvdimm/nd_virtio.c | 125 +++++++++++++++++++++++++++++++ drivers/nvdimm/virtio_pmem.c | 122 ++++++++++++++++++++++++++++++ drivers/nvdimm/virtio_pmem.h | 55 ++++++++++++++ drivers/virtio/Kconfig | 11 +++ include/uapi/linux/virtio_ids.h | 1 + include/uapi/linux/virtio_pmem.h | 34 +++++++++ 7 files changed, 349 insertions(+) create mode 100644 drivers/nvdimm/nd_virtio.c create mode 100644 drivers/nvdimm/virtio_pmem.c create mode 100644 drivers/nvdimm/virtio_pmem.h create mode 100644 include/uapi/linux/virtio_pmem.h diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile index 1192946e66af..5b4f3d50b83c 100644 --- a/drivers/nvdimm/Makefile +++ b/drivers/nvdimm/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_ND_BTT) += nd_btt.o obj-$(CONFIG_ND_BLK) += nd_blk.o obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o obj-$(CONFIG_OF_PMEM) += of_pmem.o +obj-$(CONFIG_VIRTIO_PMEM) += virtio_pmem.o nd_virtio.o nd_pmem-y := pmem.o diff --git a/drivers/nvdimm/nd_virtio.c b/drivers/nvdimm/nd_virtio.c new file mode 100644 index 000000000000..8645275c08c2 --- /dev/null +++ b/drivers/nvdimm/nd_virtio.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * virtio_pmem.c: Virtio pmem Driver + * + * Discovers persistent memory range information + * from host and provides a virtio based flushing + * interface. + */ +#include "virtio_pmem.h" +#include "nd.h" + + /* The interrupt handler */ +void virtio_pmem_host_ack(struct virtqueue *vq) +{ + struct virtio_pmem *vpmem = vq->vdev->priv; + struct virtio_pmem_request *req_data, *req_buf; + unsigned long flags; + unsigned int len; + + spin_lock_irqsave(&vpmem->pmem_lock, flags); + while ((req_data = virtqueue_get_buf(vq, &len)) != NULL) { + req_data->done = true; + wake_up(&req_data->host_acked); + + if (!list_empty(&vpmem->req_list)) { + req_buf = list_first_entry(&vpmem->req_list, + struct virtio_pmem_request, list); + req_buf->wq_buf_avail = true; + wake_up(&req_buf->wq_buf); + list_del(&req_buf->list); + } + } + spin_unlock_irqrestore(&vpmem->pmem_lock, flags); +} +EXPORT_SYMBOL_GPL(virtio_pmem_host_ack); + + /* The request submission function */ +static int virtio_pmem_flush(struct nd_region *nd_region) +{ + struct virtio_device *vdev = nd_region->provider_data; + struct virtio_pmem *vpmem = vdev->priv; + struct virtio_pmem_request *req_data; + struct scatterlist *sgs[2], sg, ret; + unsigned long flags; + int err, err1; + + might_sleep(); + req_data = kmalloc(sizeof(*req_data), GFP_KERNEL); + if (!req_data) + return -ENOMEM; + + req_data->done = false; + init_waitqueue_head(&req_data->host_acked); + init_waitqueue_head(&req_data->wq_buf); + INIT_LIST_HEAD(&req_data->list); + req_data->req.type = cpu_to_virtio32(vdev, VIRTIO_PMEM_REQ_TYPE_FLUSH); + sg_init_one(&sg, &req_data->req, sizeof(req_data->req)); + sgs[0] = &sg; + sg_init_one(&ret, &req_data->resp.ret, sizeof(req_data->resp)); + sgs[1] = &ret; + + spin_lock_irqsave(&vpmem->pmem_lock, flags); + /* + * If virtqueue_add_sgs returns -ENOSPC then req_vq virtual + * queue does not have free descriptor. We add the request + * to req_list and wait for host_ack to wake us up when free + * slots are available. + */ + while ((err = virtqueue_add_sgs(vpmem->req_vq, sgs, 1, 1, req_data, + GFP_ATOMIC)) == -ENOSPC) { + + dev_info(&vdev->dev, "failed to send command to virtio pmem device, no free slots in the virtqueue\n"); + req_data->wq_buf_avail = false; + list_add_tail(&req_data->list, &vpmem->req_list); + spin_unlock_irqrestore(&vpmem->pmem_lock, flags); + + /* A host response results in "host_ack" getting called */ + wait_event(req_data->wq_buf, req_data->wq_buf_avail); + spin_lock_irqsave(&vpmem->pmem_lock, flags); + } + err1 = virtqueue_kick(vpmem->req_vq); + spin_unlock_irqrestore(&vpmem->pmem_lock, flags); + /* + * virtqueue_add_sgs failed with error different than -ENOSPC, we can't + * do anything about that. + */ + if (err || !err1) { + dev_info(&vdev->dev, "failed to send command to virtio pmem device\n"); + err = -EIO; + } else { + /* A host repsonse results in "host_ack" getting called */ + wait_event(req_data->host_acked, req_data->done); + err = virtio32_to_cpu(vdev, req_data->resp.ret); + } + + kfree(req_data); + return err; +}; + +/* The asynchronous flush callback function */ +int async_pmem_flush(struct nd_region *nd_region, struct bio *bio) +{ + /* + * Create child bio for asynchronous flush and chain with + * parent bio. Otherwise directly call nd_region flush. + */ + if (bio && bio->bi_iter.bi_sector != -1) { + struct bio *child = bio_alloc(GFP_ATOMIC, 0); + + if (!child) + return -ENOMEM; + bio_copy_dev(child, bio); + child->bi_opf = REQ_PREFLUSH; + child->bi_iter.bi_sector = -1; + bio_chain(child, bio); + submit_bio(child); + return 0; + } + if (virtio_pmem_flush(nd_region)) + return -EIO; + + return 0; +}; +EXPORT_SYMBOL_GPL(async_pmem_flush); +MODULE_LICENSE("GPL"); diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c new file mode 100644 index 000000000000..5e3d07b47e0c --- /dev/null +++ b/drivers/nvdimm/virtio_pmem.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * virtio_pmem.c: Virtio pmem Driver + * + * Discovers persistent memory range information + * from host and registers the virtual pmem device + * with libnvdimm core. + */ +#include "virtio_pmem.h" +#include "nd.h" + +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + + /* Initialize virt queue */ +static int init_vq(struct virtio_pmem *vpmem) +{ + /* single vq */ + vpmem->req_vq = virtio_find_single_vq(vpmem->vdev, + virtio_pmem_host_ack, "flush_queue"); + if (IS_ERR(vpmem->req_vq)) + return PTR_ERR(vpmem->req_vq); + + spin_lock_init(&vpmem->pmem_lock); + INIT_LIST_HEAD(&vpmem->req_list); + + return 0; +}; + +static int virtio_pmem_probe(struct virtio_device *vdev) +{ + struct nd_region_desc ndr_desc = {}; + int nid = dev_to_node(&vdev->dev); + struct nd_region *nd_region; + struct virtio_pmem *vpmem; + struct resource res; + int err = 0; + + if (!vdev->config->get) { + dev_err(&vdev->dev, "%s failure: config access disabled\n", + __func__); + return -EINVAL; + } + + vpmem = devm_kzalloc(&vdev->dev, sizeof(*vpmem), GFP_KERNEL); + if (!vpmem) { + err = -ENOMEM; + goto out_err; + } + + vpmem->vdev = vdev; + vdev->priv = vpmem; + err = init_vq(vpmem); + if (err) { + dev_err(&vdev->dev, "failed to initialize virtio pmem vq's\n"); + goto out_err; + } + + virtio_cread(vpmem->vdev, struct virtio_pmem_config, + start, &vpmem->start); + virtio_cread(vpmem->vdev, struct virtio_pmem_config, + size, &vpmem->size); + + res.start = vpmem->start; + res.end = vpmem->start + vpmem->size - 1; + vpmem->nd_desc.provider_name = "virtio-pmem"; + vpmem->nd_desc.module = THIS_MODULE; + + vpmem->nvdimm_bus = nvdimm_bus_register(&vdev->dev, + &vpmem->nd_desc); + if (!vpmem->nvdimm_bus) { + dev_err(&vdev->dev, "failed to register device with nvdimm_bus\n"); + err = -ENXIO; + goto out_vq; + } + + dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus); + + ndr_desc.res = &res; + ndr_desc.numa_node = nid; + ndr_desc.flush = async_pmem_flush; + set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); + set_bit(ND_REGION_ASYNC, &ndr_desc.flags); + nd_region = nvdimm_pmem_region_create(vpmem->nvdimm_bus, &ndr_desc); + if (!nd_region) { + dev_err(&vdev->dev, "failed to create nvdimm region\n"); + err = -ENXIO; + goto out_nd; + } + nd_region->provider_data = dev_to_virtio(nd_region->dev.parent->parent); + return 0; +out_nd: + nvdimm_bus_unregister(vpmem->nvdimm_bus); +out_vq: + vdev->config->del_vqs(vdev); +out_err: + return err; +} + +static void virtio_pmem_remove(struct virtio_device *vdev) +{ + struct nvdimm_bus *nvdimm_bus = dev_get_drvdata(&vdev->dev); + + nvdimm_bus_unregister(nvdimm_bus); + vdev->config->del_vqs(vdev); + vdev->config->reset(vdev); +} + +static struct virtio_driver virtio_pmem_driver = { + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .id_table = id_table, + .probe = virtio_pmem_probe, + .remove = virtio_pmem_remove, +}; + +module_virtio_driver(virtio_pmem_driver); +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("Virtio pmem driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h new file mode 100644 index 000000000000..0dddefe594c4 --- /dev/null +++ b/drivers/nvdimm/virtio_pmem.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * virtio_pmem.h: virtio pmem Driver + * + * Discovers persistent memory range information + * from host and provides a virtio based flushing + * interface. + **/ + +#ifndef _LINUX_VIRTIO_PMEM_H +#define _LINUX_VIRTIO_PMEM_H + +#include +#include +#include +#include + +struct virtio_pmem_request { + struct virtio_pmem_req req; + struct virtio_pmem_resp resp; + + /* Wait queue to process deferred work after ack from host */ + wait_queue_head_t host_acked; + bool done; + + /* Wait queue to process deferred work after virt queue buffer avail */ + wait_queue_head_t wq_buf; + bool wq_buf_avail; + struct list_head list; +}; + +struct virtio_pmem { + struct virtio_device *vdev; + + /* Virtio pmem request queue */ + struct virtqueue *req_vq; + + /* nvdimm bus registers virtio pmem device */ + struct nvdimm_bus *nvdimm_bus; + struct nvdimm_bus_descriptor nd_desc; + + /* List to store deferred work if virtqueue is full */ + struct list_head req_list; + + /* Synchronize virtqueue data */ + spinlock_t pmem_lock; + + /* Memory region information */ + __u64 start; + __u64 size; +}; + +void virtio_pmem_host_ack(struct virtqueue *vq); +int async_pmem_flush(struct nd_region *nd_region, struct bio *bio); +#endif diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index cff773f15b7e..89bc931de8df 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -38,6 +38,17 @@ config VIRTIO_PCI_LEGACY If unsure, say Y. +config VIRTIO_PMEM + tristate "Support for virtio pmem driver" + depends on VIRTIO + depends on LIBNVDIMM + help + This driver provides access to virtio-pmem devices, storage devices + that are mapped into the physical address space - similar to NVDIMMs + - with a virtio-based flushing interface. + + If unsure, say Y. + config VIRTIO_BALLOON tristate "Virtio balloon driver" depends on VIRTIO diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h index 6d5c3b2d4f4d..32b2f94d1f58 100644 --- a/include/uapi/linux/virtio_ids.h +++ b/include/uapi/linux/virtio_ids.h @@ -43,5 +43,6 @@ #define VIRTIO_ID_INPUT 18 /* virtio input */ #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ #define VIRTIO_ID_CRYPTO 20 /* virtio crypto */ +#define VIRTIO_ID_PMEM 27 /* virtio pmem */ #endif /* _LINUX_VIRTIO_IDS_H */ diff --git a/include/uapi/linux/virtio_pmem.h b/include/uapi/linux/virtio_pmem.h new file mode 100644 index 000000000000..efcd72f2d20d --- /dev/null +++ b/include/uapi/linux/virtio_pmem.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Definitions for virtio-pmem devices. + * + * Copyright (C) 2019 Red Hat, Inc. + * + * Author(s): Pankaj Gupta + */ + +#ifndef _UAPI_LINUX_VIRTIO_PMEM_H +#define _UAPI_LINUX_VIRTIO_PMEM_H + +#include +#include +#include + +struct virtio_pmem_config { + __u64 start; + __u64 size; +}; + +#define VIRTIO_PMEM_REQ_TYPE_FLUSH 0 + +struct virtio_pmem_resp { + /* Host return status corresponding to flush request */ + __u32 ret; +}; + +struct virtio_pmem_req { + /* command type */ + __u32 type; +}; + +#endif -- GitLab From 7a6c152e34bcb88832909888a837731be7489aaa Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Fri, 24 Jan 2020 14:08:53 -0800 Subject: [PATCH 0297/1055] ANDROID: cuttlefish_defconfig: enable NVDIMM/PMEM options Options needed for the virtual platform and physical platforms via DT to define PMEM regions for resume-on-reboot feature Bug: 146400078 Change-Id: Icaffbd3a7425ac3d9914378fb356d32f9393eec0 Signed-off-by: Kenny Root --- arch/arm64/configs/cuttlefish_defconfig | 4 ++++ arch/x86/configs/x86_64_cuttlefish_defconfig | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index fe9a24b182f2..22f93af4ec6e 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -403,6 +403,7 @@ CONFIG_RTC_DRV_PL030=y CONFIG_RTC_DRV_PL031=y CONFIG_VIRTIO_PCI=y # CONFIG_VIRTIO_PCI_LEGACY is not set +CONFIG_VIRTIO_PMEM=y CONFIG_VIRTIO_BALLOON=y CONFIG_VIRTIO_INPUT=y CONFIG_VIRTIO_MMIO=y @@ -418,6 +419,9 @@ CONFIG_MAILBOX=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_LIBNVDIMM=y +# CONFIG_ND_BLK is not set +# CONFIG_BTT is not set CONFIG_ARM_SCPI_PROTOCOL=y # CONFIG_ARM_SCPI_POWER_DOMAIN is not set CONFIG_EXT4_FS=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 095a60dc538c..10e69e97bc8f 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -419,6 +419,7 @@ CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_TEST=y CONFIG_SW_SYNC=y CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_PMEM=y CONFIG_VIRTIO_BALLOON=y CONFIG_VIRTIO_INPUT=y CONFIG_VIRTIO_MMIO=y @@ -432,6 +433,9 @@ CONFIG_ION_SYSTEM_HEAP=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_LIBNVDIMM=y +# CONFIG_ND_BLK is not set +# CONFIG_BTT is not set # CONFIG_FIRMWARE_MEMMAP is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y -- GitLab From ebf4322ff50d20790f3fb77c1a9ef817a5c318bc Mon Sep 17 00:00:00 2001 From: Ram Muthiah Date: Mon, 25 Nov 2019 14:19:33 -0800 Subject: [PATCH 0298/1055] ANDROID: cuttlefish_defconfig: enable CONFIG_IKHEADERS as m Change-Id: I584b09e1565a1453567e692fdff9e92790b4a29e Signed-off-by: Ram Muthiah Bug: 143710295 Test: Treehugger --- 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 22f93af4ec6e..d0a8c06670c1 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -9,6 +9,7 @@ CONFIG_TASK_IO_ACCOUNTING=y CONFIG_PSI=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=m CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_RT_GROUP_SCHED=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 10e69e97bc8f..022325173f80 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -12,6 +12,7 @@ CONFIG_TASK_IO_ACCOUNTING=y CONFIG_PSI=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=m CONFIG_CGROUPS=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -- GitLab From 0dc39d68bf2715a87705826efb0d032ee5a7018d Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 27 Dec 2019 14:37:40 +0100 Subject: [PATCH 0299/1055] FROMGIT: ext4: Add EXT4_IOC_FSGETXATTR/EXT4_IOC_FSSETXATTR to compat_ioctl. These are backed by 'struct fsxattr' which has the same size on all architectures. Signed-off-by: Martijn Coenen Link: https://lore.kernel.org/patchwork/patch/1172430/ Signed-off-by: Martijn Coenen (cherry picked from commit a54d8d34d2354f3a2a9dda00d9dd6666a50c486b git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git dev) Change-Id: Ie7a047b94415ef7c19fa534f47741ebd79dcc909 --- fs/ext4/ioctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 3ba07ccb24d2..f852d90a1562 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -1247,6 +1247,8 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case FS_IOC_GETFSMAP: case FS_IOC_ENABLE_VERITY: case FS_IOC_MEASURE_VERITY: + case EXT4_IOC_FSGETXATTR: + case EXT4_IOC_FSSETXATTR: break; default: return -ENOIOCTLCMD; -- GitLab From e71ab588b09178efc05c401db29b6c8f426b9917 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 23 Oct 2019 17:00:45 -0700 Subject: [PATCH 0300/1055] xfs: Sanity check flags of Q_XQUOTARM call commit 3dd4d40b420846dd35869ccc8f8627feef2cff32 upstream. Flags passed to Q_XQUOTARM were not sanity checked for invalid values. Fix that. Fixes: 9da93f9b7cdf ("xfs: fix Q_XQUOTARM ioctl") Reported-by: Yang Xu Signed-off-by: Jan Kara Reviewed-by: Eric Sandeen Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_quotaops.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c index a65108594a07..21bc6d2d23ca 100644 --- a/fs/xfs/xfs_quotaops.c +++ b/fs/xfs/xfs_quotaops.c @@ -214,6 +214,9 @@ xfs_fs_rm_xquota( if (XFS_IS_QUOTA_ON(mp)) return -EINVAL; + if (uflags & ~(FS_USER_QUOTA | FS_GROUP_QUOTA | FS_PROJ_QUOTA)) + return -EINVAL; + if (uflags & FS_USER_QUOTA) flags |= XFS_DQ_USER; if (uflags & FS_GROUP_QUOTA) -- GitLab From 137875d425bb04eb6fbf98f50fdae0a592dee96b Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 4 Sep 2019 08:56:25 +0300 Subject: [PATCH 0301/1055] mfd: intel-lpss: Add default I2C device properties for Gemini Lake commit 3f31bc67e4dc6a555341dffefe328ddd58e8b431 upstream. It turned out Intel Gemini Lake doesn't use the same I2C timing parameters as Broxton. I got confirmation from the Windows team that Gemini Lake systems should use updated timing parameters that differ from those used in Broxton based systems. Fixes: f80e78aa11ad ("mfd: intel-lpss: Add Intel Gemini Lake PCI IDs") Tested-by: Chris Chiu Signed-off-by: Jarkko Nikula Acked-by: Andy Shevchenko Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/intel-lpss-pci.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 2b7e8eeaa59e..0504761516f7 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -126,6 +126,18 @@ static const struct intel_lpss_platform_info apl_i2c_info = { .properties = apl_i2c_properties, }; +static struct property_entry glk_i2c_properties[] = { + PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 313), + PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171), + PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 290), + { }, +}; + +static const struct intel_lpss_platform_info glk_i2c_info = { + .clk_rate = 133000000, + .properties = glk_i2c_properties, +}; + static const struct intel_lpss_platform_info cnl_i2c_info = { .clk_rate = 216000000, .properties = spt_i2c_properties, @@ -165,14 +177,14 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x1ac6), (kernel_ulong_t)&bxt_info }, { PCI_VDEVICE(INTEL, 0x1aee), (kernel_ulong_t)&bxt_uart_info }, /* GLK */ - { PCI_VDEVICE(INTEL, 0x31ac), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31ae), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31b0), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31b2), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31b4), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31b6), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31b8), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x31ba), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31ac), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31ae), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b0), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b2), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b4), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b6), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31b8), (kernel_ulong_t)&glk_i2c_info }, + { PCI_VDEVICE(INTEL, 0x31ba), (kernel_ulong_t)&glk_i2c_info }, { PCI_VDEVICE(INTEL, 0x31bc), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x31be), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x31c0), (kernel_ulong_t)&bxt_uart_info }, -- GitLab From 7e4108de535ce81a68eb7418ad92ce4b87eb5e61 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 4 Dec 2019 11:50:15 +0000 Subject: [PATCH 0302/1055] powerpc/archrandom: fix arch_get_random_seed_int() commit b6afd1234cf93aa0d71b4be4788c47534905f0be upstream. Commit 01c9348c7620ec65 powerpc: Use hardware RNG for arch_get_random_seed_* not arch_get_random_* updated arch_get_random_[int|long]() to be NOPs, and moved the hardware RNG backing to arch_get_random_seed_[int|long]() instead. However, it failed to take into account that arch_get_random_int() was implemented in terms of arch_get_random_long(), and so we ended up with a version of the former that is essentially a NOP as well. Fix this by calling arch_get_random_seed_long() from arch_get_random_seed_int() instead. Fixes: 01c9348c7620ec65 ("powerpc: Use hardware RNG for arch_get_random_seed_* not arch_get_random_*") Signed-off-by: Ard Biesheuvel Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20191204115015.18015-1-ardb@kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/archrandom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/archrandom.h b/arch/powerpc/include/asm/archrandom.h index 9c63b596e6ce..a09595f00cab 100644 --- a/arch/powerpc/include/asm/archrandom.h +++ b/arch/powerpc/include/asm/archrandom.h @@ -28,7 +28,7 @@ static inline int arch_get_random_seed_int(unsigned int *v) unsigned long val; int rc; - rc = arch_get_random_long(&val); + rc = arch_get_random_seed_long(&val); if (rc) *v = val; -- GitLab From 3d6331c0f5b4b2b40e109ab6df11c3a880eda3be Mon Sep 17 00:00:00 2001 From: Tung Nguyen Date: Thu, 28 Nov 2019 10:10:07 +0700 Subject: [PATCH 0303/1055] tipc: fix wrong timeout input for tipc_wait_for_cond() commit 12db3c8083fcab4270866a88191933f2d9f24f89 upstream. In function __tipc_shutdown(), the timeout value passed to tipc_wait_for_cond() is not jiffies. This commit fixes it by converting that value from milliseconds to jiffies. Fixes: 365ad353c256 ("tipc: reduce risk of user starvation during link congestion") Signed-off-by: Tung Nguyen Acked-by: Jon Maloy Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/tipc/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 21929ba196eb..d9ec6335c7dc 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -487,7 +487,7 @@ static void __tipc_shutdown(struct socket *sock, int error) struct sock *sk = sock->sk; struct tipc_sock *tsk = tipc_sk(sk); struct net *net = sock_net(sk); - long timeout = CONN_TIMEOUT_DEFAULT; + long timeout = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT); u32 dnode = tsk_peer_node(tsk); struct sk_buff *skb; -- GitLab From ea6e0910c76008e4db710d9f02b743714daad611 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 21 Sep 2019 10:44:01 +0200 Subject: [PATCH 0304/1055] mt7601u: fix bbp version check in mt7601u_wait_bbp_ready commit 15e14f76f85f4f0eab3b8146e1cd3c58ce272823 upstream. Fix bbp ready check in mt7601u_wait_bbp_ready. The issue is reported by coverity with the following error: Logical vs. bitwise operator The expression's value does not depend on the operands; inadvertent use of the wrong operator is a likely logic error. Addresses-Coverity-ID: 1309441 ("Logical vs. bitwise operator") Fixes: c869f77d6abb ("add mt7601u driver") Acked-by: Jakub Kicinski Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mediatek/mt7601u/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt7601u/phy.c b/drivers/net/wireless/mediatek/mt7601u/phy.c index ca09a5d4305e..71a47459bf8a 100644 --- a/drivers/net/wireless/mediatek/mt7601u/phy.c +++ b/drivers/net/wireless/mediatek/mt7601u/phy.c @@ -221,7 +221,7 @@ int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev) do { val = mt7601u_bbp_rr(dev, MT_BBP_REG_VERSION); - if (val && ~val) + if (val && val != 0xff) break; } while (--i); -- GitLab From 90225af01dc97d907e9e44e694fba55212bb228e Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Thu, 14 Nov 2019 13:58:49 +0100 Subject: [PATCH 0305/1055] crypto: sun4i-ss - fix big endian issues commit d1d787bcebfe122a5bd443ae565696661e2e9656 upstream. When testing BigEndian kernel, the sun4i-ss was failling all crypto tests. This patch fix endian issues with it. Fixes: 6298e948215f ("crypto: sunxi-ss - Add Allwinner Security System crypto accelerator") Signed-off-by: Corentin Labbe Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/sunxi-ss/sun4i-ss-hash.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c index 1a724263761b..2d178e013535 100644 --- a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c +++ b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c @@ -179,7 +179,7 @@ static int sun4i_hash(struct ahash_request *areq) */ unsigned int i = 0, end, fill, min_fill, nwait, nbw = 0, j = 0, todo; unsigned int in_i = 0; - u32 spaces, rx_cnt = SS_RX_DEFAULT, bf[32] = {0}, wb = 0, v, ivmode = 0; + u32 spaces, rx_cnt = SS_RX_DEFAULT, bf[32] = {0}, v, ivmode = 0; struct sun4i_req_ctx *op = ahash_request_ctx(areq); struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); struct sun4i_tfm_ctx *tfmctx = crypto_ahash_ctx(tfm); @@ -188,6 +188,7 @@ static int sun4i_hash(struct ahash_request *areq) struct sg_mapping_iter mi; int in_r, err = 0; size_t copied = 0; + __le32 wb = 0; dev_dbg(ss->dev, "%s %s bc=%llu len=%u mode=%x wl=%u h0=%0x", __func__, crypto_tfm_alg_name(areq->base.tfm), @@ -399,7 +400,7 @@ static int sun4i_hash(struct ahash_request *areq) nbw = op->len - 4 * nwait; if (nbw) { - wb = *(u32 *)(op->buf + nwait * 4); + wb = cpu_to_le32(*(u32 *)(op->buf + nwait * 4)); wb &= GENMASK((nbw * 8) - 1, 0); op->byte_count += nbw; @@ -408,7 +409,7 @@ static int sun4i_hash(struct ahash_request *areq) /* write the remaining bytes of the nbw buffer */ wb |= ((1 << 7) << (nbw * 8)); - bf[j++] = wb; + bf[j++] = le32_to_cpu(wb); /* * number of space to pad to obtain 64o minus 8(size) minus 4 (final 1) @@ -427,13 +428,13 @@ static int sun4i_hash(struct ahash_request *areq) /* write the length of data */ if (op->mode == SS_OP_SHA1) { - __be64 bits = cpu_to_be64(op->byte_count << 3); - bf[j++] = lower_32_bits(bits); - bf[j++] = upper_32_bits(bits); + __be64 *bits = (__be64 *)&bf[j]; + *bits = cpu_to_be64(op->byte_count << 3); + j += 2; } else { - __le64 bits = op->byte_count << 3; - bf[j++] = lower_32_bits(bits); - bf[j++] = upper_32_bits(bits); + __le64 *bits = (__le64 *)&bf[j]; + *bits = cpu_to_le64(op->byte_count << 3); + j += 2; } writesl(ss->base + SS_RXFIFO, bf, j); @@ -475,7 +476,7 @@ static int sun4i_hash(struct ahash_request *areq) } } else { for (i = 0; i < 4; i++) { - v = readl(ss->base + SS_MD0 + i * 4); + v = cpu_to_le32(readl(ss->base + SS_MD0 + i * 4)); memcpy(areq->result + i * 4, &v, 4); } } -- GitLab From 204ad0b43e88bee9b46b1ac5e8c65d1bdf3da35b Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Mon, 6 Aug 2018 08:19:09 +0200 Subject: [PATCH 0306/1055] drm/sti: do not remove the drm_bridge that was never added [ Upstream commit 66e31a72dc38543b2d9d1ce267dc78ba9beebcfd ] Removing the drm_bridge_remove call should avoid a NULL dereference during list processing in drm_bridge_remove if the error path is ever taken. The more natural approach would perhaps be to add a drm_bridge_add, but there are several other bridges that never call drm_bridge_add. Just removing the drm_bridge_remove is the easier fix. Fixes: 84601dbdea36 ("drm: sti: rework init sequence") Acked-by: Daniel Vetter Signed-off-by: Peter Rosin Signed-off-by: Benjamin Gaignard Link: https://patchwork.freedesktop.org/patch/msgid/20180806061910.29914-2-peda@axentia.se Signed-off-by: Sasha Levin --- drivers/gpu/drm/sti/sti_hda.c | 1 - drivers/gpu/drm/sti/sti_hdmi.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index cf65e32b5090..0399bb18d387 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -721,7 +721,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) return 0; err_sysfs: - drm_bridge_remove(bridge); return -EINVAL; } diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 30f02d2fdd03..bbb195a92e93 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -1314,7 +1314,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) return 0; err_sysfs: - drm_bridge_remove(bridge); hdmi->drm_connector = NULL; return -EINVAL; } -- GitLab From 81f7d38650d13e431464e4935d188900bbd2ce5b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 4 Jul 2018 12:42:50 +0300 Subject: [PATCH 0307/1055] drm/virtio: fix bounds check in virtio_gpu_cmd_get_capset() [ Upstream commit 09c4b49457434fa74749ad6194ef28464d9f5df9 ] This doesn't affect runtime because in the current code "idx" is always valid. First, we read from "vgdev->capsets[idx].max_size" before checking whether "idx" is within bounds. And secondly the bounds check is off by one so we could end up reading one element beyond the end of the vgdev->capsets[] array. Fixes: 62fb7a5e1096 ("virtio-gpu: add 3d/virgl support") Signed-off-by: Dan Carpenter Link: http://patchwork.freedesktop.org/patch/msgid/20180704094250.m7sgvvzg3dhcvv3h@kili.mountain Signed-off-by: Gerd Hoffmann Signed-off-by: Sasha Levin --- drivers/gpu/drm/virtio/virtgpu_vq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 21c2de81f3e3..a3be65e689fd 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -648,11 +648,11 @@ int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev, { struct virtio_gpu_get_capset *cmd_p; struct virtio_gpu_vbuffer *vbuf; - int max_size = vgdev->capsets[idx].max_size; + int max_size; struct virtio_gpu_drv_cap_cache *cache_ent; void *resp_buf; - if (idx > vgdev->num_capsets) + if (idx >= vgdev->num_capsets) return -EINVAL; if (version > vgdev->capsets[idx].max_version) @@ -662,6 +662,7 @@ int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev, if (!cache_ent) return -ENOMEM; + max_size = vgdev->capsets[idx].max_size; cache_ent->caps_cache = kmalloc(max_size, GFP_KERNEL); if (!cache_ent->caps_cache) { kfree(cache_ent); -- GitLab From 961e9f394d4ce5ec9518bd2c04469da5d2d9d3b3 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Tue, 11 Sep 2018 16:18:36 +0200 Subject: [PATCH 0308/1055] ALSA: hda: fix unused variable warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 5b03006d5c58ddd31caf542eef4d0269bcf265b3 ] When CONFIG_X86=n function azx_snoop doesn't use the variable chip it only returns true. sound/pci/hda/hda_intel.c: In function ‘dma_alloc_pages’: sound/pci/hda/hda_intel.c:2002:14: warning: unused variable ‘chip’ [-Wunused-variable] struct azx *chip = bus_to_azx(bus); ^~~~ Create a inline function of azx_snoop. Fixes: a41d122449be ("ALSA: hda - Embed bus into controller object") Signed-off-by: Anders Roxell Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/pci/hda/hda_controller.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 8a9dd4767b1e..63cc10604afc 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -176,11 +176,10 @@ struct azx { #define azx_bus(chip) (&(chip)->bus.core) #define bus_to_azx(_bus) container_of(_bus, struct azx, bus.core) -#ifdef CONFIG_X86 -#define azx_snoop(chip) ((chip)->snoop) -#else -#define azx_snoop(chip) true -#endif +static inline bool azx_snoop(struct azx *chip) +{ + return !IS_ENABLED(CONFIG_X86) || chip->snoop; +} /* * macros for easy use -- GitLab From 49f3e22df7169a098a13384b51a2caabbd77604c Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Thu, 13 Sep 2018 18:12:09 +0200 Subject: [PATCH 0309/1055] apparmor: don't try to replace stale label in ptrace access check [ Upstream commit 1f8266ff58840d698a1e96d2274189de1bdf7969 ] As a comment above begin_current_label_crit_section() explains, begin_current_label_crit_section() must run in sleepable context because when label_is_stale() is true, aa_replace_current_label() runs, which uses prepare_creds(), which can sleep. Until now, the ptrace access check (which runs with a task lock held) violated this rule. Also add a might_sleep() assertion to begin_current_label_crit_section(), because asserts are less likely to be ignored than comments. Fixes: b2d09ae449ced ("apparmor: move ptrace checks to using labels") Signed-off-by: Jann Horn Signed-off-by: John Johansen Signed-off-by: Sasha Levin --- security/apparmor/include/context.h | 2 ++ security/apparmor/lsm.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index 6ae07e9aaa17..812cdec9dd3b 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -191,6 +191,8 @@ static inline struct aa_label *begin_current_label_crit_section(void) { struct aa_label *label = aa_current_raw_label(); + might_sleep(); + if (label_is_stale(label)) { label = aa_get_newest_label(label); if (aa_replace_current_label(label) == 0) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 1346ee5be04f..4f08023101f3 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -108,12 +108,12 @@ static int apparmor_ptrace_access_check(struct task_struct *child, struct aa_label *tracer, *tracee; int error; - tracer = begin_current_label_crit_section(); + tracer = __begin_current_label_crit_section(); tracee = aa_get_task_label(child); error = aa_may_ptrace(tracer, tracee, mode == PTRACE_MODE_READ ? AA_PTRACE_READ : AA_PTRACE_TRACE); aa_put_label(tracee); - end_current_label_crit_section(tracer); + __end_current_label_crit_section(tracer); return error; } -- GitLab From 7f4a33710523bb7be8b2d5c3c64ee737b957021f Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Tue, 28 Aug 2018 10:22:58 -0700 Subject: [PATCH 0310/1055] PCI: iproc: Remove PAXC slot check to allow VF support [ Upstream commit 4da6b4480766e5bc9c4d7bc14bf1d0939a1a5fa7 ] Fix previous incorrect logic that limits PAXC slot number to zero only. In order for SRIOV/VF to work, we need to allow the slot number to be greater than zero. Fixes: 46560388c476c ("PCI: iproc: Allow multiple devices except on PAXC") Signed-off-by: Jitendra Bhivare Signed-off-by: Ray Jui Signed-off-by: Lorenzo Pieralisi Reviewed-by: Andy Gospodarek Signed-off-by: Sasha Levin --- drivers/pci/host/pcie-iproc.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index c0ecc9f35667..8f8dac0155d6 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -573,14 +573,6 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct iproc_pcie *pcie, return (pcie->base + offset); } - /* - * PAXC is connected to an internally emulated EP within the SoC. It - * allows only one device. - */ - if (pcie->ep_is_internal) - if (slot > 0) - return NULL; - return iproc_pcie_map_ep_cfg_reg(pcie, busno, slot, fn, where); } -- GitLab From 0442e745fbbc4678fbd341ebe9876b4041d7fd12 Mon Sep 17 00:00:00 2001 From: John Garry Date: Sat, 22 Sep 2018 01:25:26 +0800 Subject: [PATCH 0311/1055] drm/hisilicon: hibmc: Don't overwrite fb helper surface depth [ Upstream commit 0ff9f49646353ce31312411e7e7bd2281492a40e ] Currently the driver overwrites the surface depth provided by the fb helper to give an invalid bpp/surface depth combination. This has been exposed by commit 70109354fed2 ("drm: Reject unknown legacy bpp and depth for drm_mode_addfb ioctl"), which now causes the driver to fail to probe. Fix by not overwriting the surface depth. Fixes: d1667b86795a ("drm/hisilicon/hibmc: Add support for frame buffer") Signed-off-by: John Garry Reviewed-by: Xinliang Liu Signed-off-by: Xinliang Liu Signed-off-by: Sasha Levin --- drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c index 8bd29075ae4e..edcca1761500 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c @@ -71,7 +71,6 @@ static int hibmc_drm_fb_create(struct drm_fb_helper *helper, DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n", sizes->surface_width, sizes->surface_height, sizes->surface_bpp); - sizes->surface_depth = 32; bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); -- GitLab From 19f75f6e5d3df311c0845c88cb60143f1621febd Mon Sep 17 00:00:00 2001 From: Zhu Yanjun Date: Sun, 30 Sep 2018 01:57:42 -0400 Subject: [PATCH 0312/1055] IB/rxe: replace kvfree with vfree [ Upstream commit 721ad7e643f7002efa398838693f90284ea216d1 ] The buf is allocated by vmalloc_user in the function rxe_queue_init. So it is better to free it by vfree. Fixes: 8700e3e7c485 ("Soft RoCE driver") Reviewed-by: Leon Romanovsky Signed-off-by: Zhu Yanjun Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/sw/rxe/rxe_cq.c | 4 ++-- drivers/infiniband/sw/rxe/rxe_qp.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_cq.c b/drivers/infiniband/sw/rxe/rxe_cq.c index c4aabf78dc90..f6e036ded046 100644 --- a/drivers/infiniband/sw/rxe/rxe_cq.c +++ b/drivers/infiniband/sw/rxe/rxe_cq.c @@ -30,7 +30,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - +#include #include "rxe.h" #include "rxe_loc.h" #include "rxe_queue.h" @@ -97,7 +97,7 @@ int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe, err = do_mmap_info(rxe, udata, false, context, cq->queue->buf, cq->queue->buf_size, &cq->queue->ip); if (err) { - kvfree(cq->queue->buf); + vfree(cq->queue->buf); kfree(cq->queue); return err; } diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c index aeea994b04c4..25055a68a2c0 100644 --- a/drivers/infiniband/sw/rxe/rxe_qp.c +++ b/drivers/infiniband/sw/rxe/rxe_qp.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "rxe.h" #include "rxe_loc.h" @@ -255,7 +256,7 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp, qp->sq.queue->buf_size, &qp->sq.queue->ip); if (err) { - kvfree(qp->sq.queue->buf); + vfree(qp->sq.queue->buf); kfree(qp->sq.queue); return err; } @@ -308,7 +309,7 @@ static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp, qp->rq.queue->buf_size, &qp->rq.queue->ip); if (err) { - kvfree(qp->rq.queue->buf); + vfree(qp->rq.queue->buf); kfree(qp->rq.queue); return err; } -- GitLab From 805d9b456cea5b0c09e2a2cab291bd6291f8ed85 Mon Sep 17 00:00:00 2001 From: Alex Estrin Date: Wed, 26 Sep 2018 10:56:03 -0700 Subject: [PATCH 0313/1055] IB/hfi1: Add mtu check for operational data VLs [ Upstream commit eb50130964e8c1379f37c3d3bab33a411ec62e98 ] Since Virtual Lanes BCT credits and MTU are set through separate MADs, we have to ensure both are valid, and data VLs are ready for transmission before we allow port transition to Armed state. Fixes: 5e2d6764a729 ("IB/hfi1: Verify port data VLs credits on transition to Armed") Reviewed-by: Mike Marciniszyn Reviewed-by: Michael J. Ruhl Signed-off-by: Alex Estrin Signed-off-by: Dennis Dalessandro Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/hw/hfi1/chip.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 9f78bb07744c..4a0b7c003477 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -10552,12 +10552,29 @@ void set_link_down_reason(struct hfi1_pportdata *ppd, u8 lcl_reason, } } -/* - * Verify if BCT for data VLs is non-zero. +/** + * data_vls_operational() - Verify if data VL BCT credits and MTU + * are both set. + * @ppd: pointer to hfi1_pportdata structure + * + * Return: true - Ok, false -otherwise. */ static inline bool data_vls_operational(struct hfi1_pportdata *ppd) { - return !!ppd->actual_vls_operational; + int i; + u64 reg; + + if (!ppd->actual_vls_operational) + return false; + + for (i = 0; i < ppd->vls_supported; i++) { + reg = read_csr(ppd->dd, SEND_CM_CREDIT_VL + (8 * i)); + if ((reg && !ppd->dd->vld[i].mtu) || + (!reg && ppd->dd->vld[i].mtu)) + return false; + } + + return true; } /* @@ -10662,7 +10679,8 @@ int set_link_state(struct hfi1_pportdata *ppd, u32 state) if (!data_vls_operational(ppd)) { dd_dev_err(dd, - "%s: data VLs not operational\n", __func__); + "%s: Invalid data VL credits or mtu\n", + __func__); ret = -EINVAL; break; } -- GitLab From 48eba57c43a1ee1810a257152c89cf7dfa812d56 Mon Sep 17 00:00:00 2001 From: Nicolas Huaman Date: Thu, 4 Oct 2018 16:42:05 +0200 Subject: [PATCH 0314/1055] ALSA: usb-audio: update quirk for B&W PX to remove microphone [ Upstream commit c369c8db15d51fa175d2ba85928f79d16af6b562 ] A quirk in snd-usb-audio was added to automate setting sample rate to 4800k and remove the previously exposed nonfunctional microphone for the Bowers & Wilkins PX: commit 240a8af929c7c57dcde28682725b29cf8474e8e5 https://lore.kernel.org/patchwork/patch/919689/ However the headphones where updated shortly after that to remove the unintentional microphone functionality. I guess because of this the headphones now crash when connecting them via USB while the quirk is active. Dmesg: snd-usb-audio: probe of 2-3:1.0 failed with error -22 usb 2-3: 2:1: cannot get min/max values for control 2 (id 2) This patch removes the microfone and allows the headphones to connect and work out of the box. It is based on the current mainline kernel and successfully applied an tested on my machine (4.18.10.arch1-1). Fixes: 240a8af929c7 ("ALSA: usb-audio: Add a quirck for B&W PX headphones") Signed-off-by: Nicolas Huaman Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/usb/quirks-table.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index d32727c74a16..c892b4d1e733 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3293,19 +3293,14 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), .ifnum = 0, .type = QUIRK_AUDIO_STANDARD_MIXER, }, - /* Capture */ - { - .ifnum = 1, - .type = QUIRK_IGNORE_INTERFACE, - }, /* Playback */ { - .ifnum = 2, + .ifnum = 1, .type = QUIRK_AUDIO_FIXED_ENDPOINT, .data = &(const struct audioformat) { .formats = SNDRV_PCM_FMTBIT_S16_LE, .channels = 2, - .iface = 2, + .iface = 1, .altsetting = 1, .altset_idx = 1, .attributes = UAC_EP_CS_ATTR_FILL_MAX | -- GitLab From 27db95dfd2045e39226feba0610f67063f8f6e82 Mon Sep 17 00:00:00 2001 From: "Spencer E. Olson" Date: Wed, 3 Oct 2018 14:54:16 -0600 Subject: [PATCH 0315/1055] staging: comedi: ni_mio_common: protect register write overflow [ Upstream commit 1cbca5852d6c16e85a21487a15d211195aacd4a1 ] Fixes two problems introduced as early as commit 03aef4b6dc12 ("Staging: comedi: add ni_mio_common code"): (1) Ensures that the last four bits of NISTC_RTSI_TRIGB_OUT_REG register is not unduly overwritten on e-series devices. On e-series devices, the first three of the last four bits are reserved. The last bit defines the output selection of the RGOUT0 pin, otherwise known as RTSI_Sub_Selection. For m-series devices, these last four bits are indeed used as the output selection of the RTSI7 pin (and the RTSI_Sub_Selection bit for the RGOUT0 pin is moved to the RTSI_Trig_Direction register. (2) Allows all 4 RTSI_BRD lines to be treated as valid sources for RTSI lines. This patch also cleans up the ni_get_rtsi_routing command for readability. Fixes: 03aef4b6dc12 ("Staging: comedi: add ni_mio_common code") Signed-off-by: Spencer E. Olson Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- .../staging/comedi/drivers/ni_mio_common.c | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 36361bdf934a..2f82dcb1fd06 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -4991,7 +4991,10 @@ static int ni_valid_rtsi_output_source(struct comedi_device *dev, case NI_RTSI_OUTPUT_G_SRC0: case NI_RTSI_OUTPUT_G_GATE0: case NI_RTSI_OUTPUT_RGOUT0: - case NI_RTSI_OUTPUT_RTSI_BRD_0: + case NI_RTSI_OUTPUT_RTSI_BRD(0): + case NI_RTSI_OUTPUT_RTSI_BRD(1): + case NI_RTSI_OUTPUT_RTSI_BRD(2): + case NI_RTSI_OUTPUT_RTSI_BRD(3): return 1; case NI_RTSI_OUTPUT_RTSI_OSC: return (devpriv->is_m_series) ? 1 : 0; @@ -5012,11 +5015,18 @@ static int ni_set_rtsi_routing(struct comedi_device *dev, devpriv->rtsi_trig_a_output_reg |= NISTC_RTSI_TRIG(chan, src); ni_stc_writew(dev, devpriv->rtsi_trig_a_output_reg, NISTC_RTSI_TRIGA_OUT_REG); - } else if (chan < 8) { + } else if (chan < NISTC_RTSI_TRIG_NUM_CHAN(devpriv->is_m_series)) { devpriv->rtsi_trig_b_output_reg &= ~NISTC_RTSI_TRIG_MASK(chan); devpriv->rtsi_trig_b_output_reg |= NISTC_RTSI_TRIG(chan, src); ni_stc_writew(dev, devpriv->rtsi_trig_b_output_reg, NISTC_RTSI_TRIGB_OUT_REG); + } else if (chan != NISTC_RTSI_TRIG_OLD_CLK_CHAN) { + /* probably should never reach this, since the + * ni_valid_rtsi_output_source above errors out if chan is too + * high + */ + dev_err(dev->class_dev, "%s: unknown rtsi channel\n", __func__); + return -EINVAL; } return 2; } @@ -5032,12 +5042,12 @@ static unsigned int ni_get_rtsi_routing(struct comedi_device *dev, } else if (chan < NISTC_RTSI_TRIG_NUM_CHAN(devpriv->is_m_series)) { return NISTC_RTSI_TRIG_TO_SRC(chan, devpriv->rtsi_trig_b_output_reg); - } else { - if (chan == NISTC_RTSI_TRIG_OLD_CLK_CHAN) - return NI_RTSI_OUTPUT_RTSI_OSC; - dev_err(dev->class_dev, "bug! should never get here?\n"); - return 0; + } else if (chan == NISTC_RTSI_TRIG_OLD_CLK_CHAN) { + return NI_RTSI_OUTPUT_RTSI_OSC; } + + dev_err(dev->class_dev, "%s: unknown rtsi channel\n", __func__); + return -EINVAL; } static int ni_rtsi_insn_config(struct comedi_device *dev, -- GitLab From bfd5e35ba3b4c33dd846d521fdf7933a52c8c543 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 12 Oct 2018 12:12:28 +0200 Subject: [PATCH 0316/1055] pwm: lpss: Release runtime-pm reference from the driver's remove callback [ Upstream commit 42885551cedb45961879d2fc3dc3c4dc545cc23e ] For each pwm output which gets enabled through pwm_lpss_apply(), we do a pm_runtime_get_sync(). This commit adds pm_runtime_put() calls to pwm_lpss_remove() to balance these when the driver gets removed with some of the outputs still enabled. Fixes: f080be27d7d9 ("pwm: lpss: Add support for runtime PM") Acked-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Thierry Reding Signed-off-by: Sasha Levin --- drivers/pwm/pwm-lpss.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 1e69c1c9ec09..7a4a6406cf69 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -216,6 +216,12 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe); int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) { + int i; + + for (i = 0; i < lpwm->info->npwm; i++) { + if (pwm_is_enabled(&lpwm->chip.pwms[i])) + pm_runtime_put(lpwm->chip.dev); + } return pwmchip_remove(&lpwm->chip); } EXPORT_SYMBOL_GPL(pwm_lpss_remove); -- GitLab From 5a5aee840210828e511cf45a94692d2854836361 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sun, 21 Oct 2018 18:34:46 +0200 Subject: [PATCH 0317/1055] drm/sun4i: hdmi: Fix double flag assignation [ Upstream commit 1e0ff648940e603cab6c52cf3723017d30d78f30 ] The is_double flag is a boolean currently assigned to the value of the d variable, that is either 1 or 2. It means that this is_double variable is always set to true, even though the initial intent was to have it set to true when d is 2. Fix this. Fixes: 9c5681011a0c ("drm/sun4i: Add HDMI support") Reported-by: Dan Carpenter Signed-off-by: Maxime Ripard Reviewed-by: Giulio Benetti Link: https://patchwork.freedesktop.org/patch/msgid/20181021163446.29135-2-maxime.ripard@bootlin.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c index 5cf2527bffc8..d7a8fea94557 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_tmds_clk.c @@ -50,7 +50,7 @@ static unsigned long sun4i_tmds_calc_divider(unsigned long rate, (rate - tmp_rate) < (rate - best_rate)) { best_rate = tmp_rate; best_m = m; - is_double = d; + is_double = (d == 2) ? true : false; } } } -- GitLab From b92c7db5c89f62989cdd5049b7f4a9b83082324f Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 31 Oct 2018 09:56:42 +0000 Subject: [PATCH 0318/1055] mlxsw: reg: QEEC: Add minimum shaper fields [ Upstream commit 8b931821aa04823e2e5df0ae93937baabbd23286 ] Add QEEC.mise (minimum shaper enable) and QEEC.min_shaper_rate to enable configuration of minimum shaper. Increase the QEEC length to 0x20 as well: that's the length that the register has had for a long time now, but with the configurations that mlxsw typically exercises, the firmware tolerated 0x1C-sized packets. With mise=true however, FW rejects packets unless they have the full required length. Fixes: b9b7cee40579 ("mlxsw: reg: Add QoS ETS Element Configuration register") Signed-off-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 8ab7a4f98a07..e7974ba06432 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -2452,7 +2452,7 @@ static inline void mlxsw_reg_qtct_pack(char *payload, u8 local_port, * Configures the ETS elements. */ #define MLXSW_REG_QEEC_ID 0x400D -#define MLXSW_REG_QEEC_LEN 0x1C +#define MLXSW_REG_QEEC_LEN 0x20 MLXSW_REG_DEFINE(qeec, MLXSW_REG_QEEC_ID, MLXSW_REG_QEEC_LEN); @@ -2494,6 +2494,15 @@ MLXSW_ITEM32(reg, qeec, element_index, 0x04, 0, 8); */ MLXSW_ITEM32(reg, qeec, next_element_index, 0x08, 0, 8); +/* reg_qeec_mise + * Min shaper configuration enable. Enables configuration of the min + * shaper on this ETS element + * 0 - Disable + * 1 - Enable + * Access: RW + */ +MLXSW_ITEM32(reg, qeec, mise, 0x0C, 31, 1); + enum { MLXSW_REG_QEEC_BYTES_MODE, MLXSW_REG_QEEC_PACKETS_MODE, @@ -2510,6 +2519,17 @@ enum { */ MLXSW_ITEM32(reg, qeec, pb, 0x0C, 28, 1); +/* The smallest permitted min shaper rate. */ +#define MLXSW_REG_QEEC_MIS_MIN 200000 /* Kbps */ + +/* reg_qeec_min_shaper_rate + * Min shaper information rate. + * For CPU port, can only be configured for port hierarchy. + * When in bytes mode, value is specified in units of 1000bps. + * Access: RW + */ +MLXSW_ITEM32(reg, qeec, min_shaper_rate, 0x0C, 0, 28); + /* reg_qeec_mase * Max shaper configuration enable. Enables configuration of the max * shaper on this ETS element. -- GitLab From e3708b8b2762296d7dde4fcac127c5bfffc3b8e5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 27 Aug 2018 17:13:06 -0500 Subject: [PATCH 0319/1055] NTB: ntb_hw_idt: replace IS_ERR_OR_NULL with regular NULL checks [ Upstream commit 1b7619828d0c341612f58683e73f279c37e70bbc ] Both devm_kcalloc() and devm_kzalloc() return NULL on error. They never return error pointers. The use of IS_ERR_OR_NULL is currently applied to the wrong context. Fix this by replacing IS_ERR_OR_NULL with regular NULL checks. Fixes: bf2a952d31d2 ("NTB: Add IDT 89HPESxNTx PCIe-switches support") Signed-off-by: Gustavo A. R. Silva Signed-off-by: Jon Mason Signed-off-by: Sasha Levin --- drivers/ntb/hw/idt/ntb_hw_idt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/ntb/hw/idt/ntb_hw_idt.c b/drivers/ntb/hw/idt/ntb_hw_idt.c index d44d7ef38fe8..b68e2cad74cc 100644 --- a/drivers/ntb/hw/idt/ntb_hw_idt.c +++ b/drivers/ntb/hw/idt/ntb_hw_idt.c @@ -1105,9 +1105,9 @@ static struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port, } /* Allocate memory for memory window descriptors */ - ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt, - sizeof(*ret_mws), GFP_KERNEL); - if (IS_ERR_OR_NULL(ret_mws)) + ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt, sizeof(*ret_mws), + GFP_KERNEL); + if (!ret_mws) return ERR_PTR(-ENOMEM); /* Copy the info of detected memory windows */ @@ -2393,7 +2393,7 @@ static struct idt_ntb_dev *idt_create_dev(struct pci_dev *pdev, /* Allocate memory for the IDT PCIe-device descriptor */ ndev = devm_kzalloc(&pdev->dev, sizeof(*ndev), GFP_KERNEL); - if (IS_ERR_OR_NULL(ndev)) { + if (!ndev) { dev_err(&pdev->dev, "Memory allocation failed for descriptor"); return ERR_PTR(-ENOMEM); } -- GitLab From 8a0c3bc2cf9e08a6abed982fdeba0e8aca48fbe6 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 27 Oct 2018 15:49:26 +0100 Subject: [PATCH 0320/1055] pcrypt: use format specifier in kobject_add [ Upstream commit b1e3874c75ab15288f573b3532e507c37e8e7656 ] Passing string 'name' as the format specifier is potentially hazardous because name could (although very unlikely to) have a format specifier embedded in it causing issues when parsing the non-existent arguments to these. Follow best practice by using the "%s" format string for the string 'name'. Cleans up clang warning: crypto/pcrypt.c:397:40: warning: format string is not a string literal (potentially insecure) [-Wformat-security] Fixes: a3fb1e330dd2 ("pcrypt: Added sysfs interface to pcrypt") Signed-off-by: Colin Ian King Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- crypto/pcrypt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index f8ec3d4ba4a8..a5718c0a3dc4 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c @@ -394,7 +394,7 @@ static int pcrypt_sysfs_add(struct padata_instance *pinst, const char *name) int ret; pinst->kobj.kset = pcrypt_kset; - ret = kobject_add(&pinst->kobj, NULL, name); + ret = kobject_add(&pinst->kobj, NULL, "%s", name); if (!ret) kobject_uevent(&pinst->kobj, KOBJ_ADD); -- GitLab From b6e209a13a61b65848e214319e3348e5e23346cb Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 19 Nov 2018 11:32:41 +0800 Subject: [PATCH 0321/1055] exportfs: fix 'passing zero to ERR_PTR()' warning [ Upstream commit 909e22e05353a783c526829427e9a8de122fba9c ] Fix a static code checker warning: fs/exportfs/expfs.c:171 reconnect_one() warn: passing zero to 'ERR_PTR' The error path for lookup_one_len_unlocked failure should set err to PTR_ERR. Fixes: bbf7a8a3562f ("exportfs: move most of reconnect_path to helper function") Signed-off-by: YueHaibing Signed-off-by: Al Viro Signed-off-by: Sasha Levin --- fs/exportfs/expfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index a561ae17cf43..c08960040dd0 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c @@ -147,6 +147,7 @@ static struct dentry *reconnect_one(struct vfsmount *mnt, tmp = lookup_one_len_unlocked(nbuf, parent, strlen(nbuf)); if (IS_ERR(tmp)) { dprintk("%s: lookup failed: %d\n", __func__, PTR_ERR(tmp)); + err = PTR_ERR(tmp); goto out_err; } if (tmp != dentry) { -- GitLab From fc27e03fc4769daeeb17947f99001eb94221922c Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Tue, 13 Nov 2018 17:46:14 -0500 Subject: [PATCH 0322/1055] drm/dp_mst: Skip validating ports during destruction, just ref [ Upstream commit c54c7374ff44de5e609506aca7c0deae4703b6d1 ] Jerry Zuo pointed out a rather obscure hotplugging issue that it seems I accidentally introduced into DRM two years ago. Pretend we have a topology like this: |- DP-1: mst_primary |- DP-4: active display |- DP-5: disconnected |- DP-6: active hub |- DP-7: active display |- DP-8: disconnected |- DP-9: disconnected If we unplug DP-6, the topology starting at DP-7 will be destroyed but it's payloads will live on in DP-1's VCPI allocations and thus require removal. However, this removal currently fails because drm_dp_update_payload_part1() will (rightly so) try to validate the port before accessing it, fail then abort. If we keep going, eventually we run the MST hub out of bandwidth and all new allocations will start to fail (or in my case; all new displays just start flickering a ton). We could just teach drm_dp_update_payload_part1() not to drop the port ref in this case, but then we also need to teach drm_dp_destroy_payload_step1() to do the same thing, then hope no one ever adds anything to the that requires a validated port reference in drm_dp_destroy_connector_work(). Kind of sketchy. So let's go with a more clever solution: any port that drm_dp_destroy_connector_work() interacts with is guaranteed to still exist in memory until we say so. While said port might not be valid we don't really care: that's the whole reason we're destroying it in the first place! So, teach drm_dp_get_validated_port_ref() to use the all mighty current_work() function to avoid attempting to validate ports from the context of mgr->destroy_connector_work. I can't see any situation where this wouldn't be safe, and this avoids having to play whack-a-mole in the future of trying to work around port validation. Signed-off-by: Lyude Paul Fixes: 263efde31f97 ("drm/dp/mst: Get validated port ref in drm_dp_update_payload_part1()") Reported-by: Jerry Zuo Cc: Jerry Zuo Cc: Harry Wentland Cc: # v4.6+ Reviewed-by: Dave Airlie Link: https://patchwork.freedesktop.org/patch/msgid/20181113224613.28809-1-lyude@redhat.com Signed-off-by: Sean Paul Signed-off-by: Sasha Levin --- drivers/gpu/drm/drm_dp_mst_topology.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index c8c83f84aced..9d94c306c8ca 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -982,9 +982,20 @@ static struct drm_dp_mst_port *drm_dp_mst_get_port_ref_locked(struct drm_dp_mst_ static struct drm_dp_mst_port *drm_dp_get_validated_port_ref(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port) { struct drm_dp_mst_port *rport = NULL; + mutex_lock(&mgr->lock); - if (mgr->mst_primary) - rport = drm_dp_mst_get_port_ref_locked(mgr->mst_primary, port); + /* + * Port may or may not be 'valid' but we don't care about that when + * destroying the port and we are guaranteed that the port pointer + * will be valid until we've finished + */ + if (current_work() == &mgr->destroy_connector_work) { + kref_get(&port->kref); + rport = port; + } else if (mgr->mst_primary) { + rport = drm_dp_mst_get_port_ref_locked(mgr->mst_primary, + port); + } mutex_unlock(&mgr->lock); return rport; } -- GitLab From 9b1cee5e5f1fb7d9938066acd36f8be60e017742 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 28 Nov 2018 09:02:41 +0000 Subject: [PATCH 0323/1055] net: phy: Fix not to call phy_resume() if PHY is not attached [ Upstream commit ef1b5bf506b1f0ee3edc98533e1f3ecb105eb46a ] This patch fixes an issue that mdio_bus_phy_resume() doesn't call phy_resume() if the PHY is not attached. Fixes: 803dd9c77ac3 ("net: phy: avoid suspending twice a PHY") Signed-off-by: Yoshihiro Shimoda Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/phy/phy_device.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index a98c227a4c2e..99dae55cd334 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -76,7 +76,7 @@ static LIST_HEAD(phy_fixup_list); static DEFINE_MUTEX(phy_fixup_lock); #ifdef CONFIG_PM -static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) +static bool mdio_bus_phy_may_suspend(struct phy_device *phydev, bool suspend) { struct device_driver *drv = phydev->mdio.dev.driver; struct phy_driver *phydrv = to_phy_driver(drv); @@ -88,10 +88,11 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev) /* PHY not attached? May suspend if the PHY has not already been * suspended as part of a prior call to phy_disconnect() -> * phy_detach() -> phy_suspend() because the parent netdev might be the - * MDIO bus driver and clock gated at this point. + * MDIO bus driver and clock gated at this point. Also may resume if + * PHY is not attached. */ if (!netdev) - return !phydev->suspended; + return suspend ? !phydev->suspended : phydev->suspended; /* Don't suspend PHY if the attached netdev parent may wakeup. * The parent may point to a PCI device, as in tg3 driver. @@ -121,7 +122,7 @@ static int mdio_bus_phy_suspend(struct device *dev) if (phydev->attached_dev && phydev->adjust_link) phy_stop_machine(phydev); - if (!mdio_bus_phy_may_suspend(phydev)) + if (!mdio_bus_phy_may_suspend(phydev, true)) return 0; return phy_suspend(phydev); @@ -132,7 +133,7 @@ static int mdio_bus_phy_resume(struct device *dev) struct phy_device *phydev = to_phy_device(dev); int ret; - if (!mdio_bus_phy_may_suspend(phydev)) + if (!mdio_bus_phy_may_suspend(phydev, false)) goto no_resume; ret = phy_resume(phydev); -- GitLab From c7c34c31038087b6ba47c193f38a055d3adcd71d Mon Sep 17 00:00:00 2001 From: Yuval Shaia Date: Sun, 9 Dec 2018 15:53:49 +0200 Subject: [PATCH 0324/1055] IB/rxe: Fix incorrect cache cleanup in error flow [ Upstream commit 6db21d8986e14e2e86573a3b055b05296188bd2c ] Array iterator stays at the same slot, fix it. Fixes: 8700e3e7c485 ("Soft RoCE driver") Signed-off-by: Yuval Shaia Reviewed-by: Bart Van Assche Reviewed-by: Zhu Yanjun Reviewed-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/sw/rxe/rxe_pool.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_pool.c b/drivers/infiniband/sw/rxe/rxe_pool.c index b4a8acc7bb7d..0e2425f28233 100644 --- a/drivers/infiniband/sw/rxe/rxe_pool.c +++ b/drivers/infiniband/sw/rxe/rxe_pool.c @@ -112,6 +112,18 @@ static inline struct kmem_cache *pool_cache(struct rxe_pool *pool) return rxe_type_info[pool->type].cache; } +static void rxe_cache_clean(size_t cnt) +{ + int i; + struct rxe_type_info *type; + + for (i = 0; i < cnt; i++) { + type = &rxe_type_info[i]; + kmem_cache_destroy(type->cache); + type->cache = NULL; + } +} + int rxe_cache_init(void) { int err; @@ -136,24 +148,14 @@ int rxe_cache_init(void) return 0; err1: - while (--i >= 0) { - kmem_cache_destroy(type->cache); - type->cache = NULL; - } + rxe_cache_clean(i); return err; } void rxe_cache_exit(void) { - int i; - struct rxe_type_info *type; - - for (i = 0; i < RXE_NUM_TYPES; i++) { - type = &rxe_type_info[i]; - kmem_cache_destroy(type->cache); - type->cache = NULL; - } + rxe_cache_clean(RXE_NUM_TYPES); } static int rxe_pool_init_index(struct rxe_pool *pool, u32 max, u32 min) -- GitLab From 0c52e16253a5d6d810696a647107ea55909708f2 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Thu, 6 Dec 2018 19:28:51 +0100 Subject: [PATCH 0325/1055] staging: bcm2835-camera: Abort probe if there is no camera [ Upstream commit 7566f39dfdc11f8a97d5810c6e6295a88f97ef91 ] Abort the probing of the camera driver in case there isn't a camera actually connected to the Raspberry Pi. This solution also avoids a NULL ptr dereference of mmal instance on driver unload. Fixes: 7b3ad5abf027 ("staging: Import the BCM2835 MMAL-based V4L2 camera driver.") Signed-off-by: Stefan Wahren Reviewed-by: Nicolas Saenz Julienne Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- .../vc04_services/bcm2835-camera/bcm2835-camera.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c index 377da037f31c..b521752d9aa0 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c @@ -1849,6 +1849,12 @@ static int __init bm2835_mmal_init(void) num_cameras = get_num_cameras(instance, resolutions, MAX_BCM2835_CAMERAS); + + if (num_cameras < 1) { + ret = -ENODEV; + goto cleanup_mmal; + } + if (num_cameras > MAX_BCM2835_CAMERAS) num_cameras = MAX_BCM2835_CAMERAS; @@ -1948,6 +1954,9 @@ static int __init bm2835_mmal_init(void) pr_info("%s: error %d while loading driver\n", BM2835_MMAL_MODULE_NAME, ret); +cleanup_mmal: + vchiq_mmal_finalise(instance); + return ret; } -- GitLab From 336384d871a9797a620063158c3d80988ea0cc47 Mon Sep 17 00:00:00 2001 From: Kelvin Cao Date: Mon, 10 Dec 2018 17:12:20 +0800 Subject: [PATCH 0326/1055] switchtec: Remove immediate status check after submitting MRPC command [ Upstream commit 526180408b815aa7b96fd48bd23cdd33ef04e38e ] After submitting a Firmware Download MRPC command, Switchtec firmware will delay Management EP BAR MemRd TLP responses by more than 10ms. This is a firmware limitation. Delayed MemRd completions are a problem for systems with a low Completion Timeout (CTO). The current driver checks the MRPC status immediately after submitting an MRPC command, which results in a delayed MemRd completion that may cause a Completion Timeout. Remove the immediate status check and rely on the check after receiving an interrupt or timing out. This is only a software workaround to the READ issue and a proper fix of this should be done in firmware. Fixes: 080b47def5e5 ("MicroSemi Switchtec management interface driver") Signed-off-by: Kelvin Cao Signed-off-by: Wesley Sheng Signed-off-by: Bjorn Helgaas Reviewed-by: Logan Gunthorpe Signed-off-by: Sasha Levin --- drivers/pci/switch/switchtec.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/pci/switch/switchtec.c b/drivers/pci/switch/switchtec.c index 0941555b84a5..73dba2739849 100644 --- a/drivers/pci/switch/switchtec.c +++ b/drivers/pci/switch/switchtec.c @@ -399,10 +399,6 @@ static void mrpc_cmd_submit(struct switchtec_dev *stdev) stuser->data, stuser->data_len); iowrite32(stuser->cmd, &stdev->mmio_mrpc->cmd); - stuser->status = ioread32(&stdev->mmio_mrpc->status); - if (stuser->status != SWITCHTEC_MRPC_STATUS_INPROGRESS) - mrpc_complete_cmd(stdev); - schedule_delayed_work(&stdev->mrpc_timeout, msecs_to_jiffies(500)); } -- GitLab From da93a64fe66594d356097b09d590cfe188117222 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 12 Dec 2018 10:57:27 +0100 Subject: [PATCH 0327/1055] pinctrl: sh-pfc: r8a7740: Add missing REF125CK pin to gether_gmii group [ Upstream commit 1ebc589a7786f17f97b9e87b44e0fb4d0290d8f8 ] The gether_gmii_mux[] array contains the REF125CK pin mark, but the gether_gmii_pins[] array lacks the corresponding pin number. Fixes: bae11d30d0cafdc5 ("sh-pfc: r8a7740: Add GETHER pin groups and functions") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-r8a7740.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c index 35f436bcb849..d8077065636e 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c @@ -1982,7 +1982,7 @@ static const unsigned int gether_gmii_pins[] = { */ 185, 186, 187, 188, 189, 190, 191, 192, 174, 161, 204, 171, 170, 169, 168, 167, 166, 173, 172, 176, 184, 183, 203, - 205, 163, 206, 207, + 205, 163, 206, 207, 158, }; static const unsigned int gether_gmii_mux[] = { ET_ERXD0_MARK, ET_ERXD1_MARK, ET_ERXD2_MARK, ET_ERXD3_MARK, -- GitLab From da8432d949db61082b75154272e37dbafa29e4d7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 12 Dec 2018 11:00:27 +0100 Subject: [PATCH 0328/1055] pinctrl: sh-pfc: r8a7740: Add missing LCD0 marks to lcd0_data24_1 group [ Upstream commit 96bb2a6ab4eca10e5b6490b3f0738e9f7ec22c2b ] The lcd0_data24_1_pins[] array contains the LCD0 D1[2-5] pin numbers, but the lcd0_data24_1_mux[] array lacks the corresponding pin marks. Fixes: 06c7dd866da70f6c ("sh-pfc: r8a7740: Add LCDC0 and LCDC1 pin groups and functions") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-r8a7740.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c index d8077065636e..e9739dbcb356 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c @@ -2154,6 +2154,7 @@ static const unsigned int lcd0_data24_1_mux[] = { LCD0_D0_MARK, LCD0_D1_MARK, LCD0_D2_MARK, LCD0_D3_MARK, LCD0_D4_MARK, LCD0_D5_MARK, LCD0_D6_MARK, LCD0_D7_MARK, LCD0_D8_MARK, LCD0_D9_MARK, LCD0_D10_MARK, LCD0_D11_MARK, + LCD0_D12_MARK, LCD0_D13_MARK, LCD0_D14_MARK, LCD0_D15_MARK, LCD0_D16_MARK, LCD0_D17_MARK, LCD0_D18_PORT163_MARK, LCD0_D19_PORT162_MARK, LCD0_D20_PORT161_MARK, LCD0_D21_PORT158_MARK, LCD0_D22_PORT160_MARK, LCD0_D23_PORT159_MARK, -- GitLab From 550ba4ad0da3d94a0ee5a1016e23467f854ba603 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 12 Dec 2018 11:05:57 +0100 Subject: [PATCH 0329/1055] pinctrl: sh-pfc: r8a7791: Remove bogus ctrl marks from qspi_data4_b group [ Upstream commit 884fa25fb6e5e63ab970d612a628313bb68f37cc ] The qspi_data4_b_mux[] array contains pin marks for the clock and chip select pins. The qspi_data4_b_pins[] array rightfully does not contain the corresponding pin numbers, as the control pins are provided by a separate group (qspi_ctrl_b). Fixes: 2d0c386f135e4186 ("pinctrl: sh-pfc: r8a7791: Add QSPI pin groups") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-r8a7791.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index c01ef02d326b..8600ba82f59c 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -3220,8 +3220,7 @@ static const unsigned int qspi_data4_b_pins[] = { RCAR_GP_PIN(6, 4), }; static const unsigned int qspi_data4_b_mux[] = { - SPCLK_B_MARK, MOSI_IO0_B_MARK, MISO_IO1_B_MARK, - IO2_B_MARK, IO3_B_MARK, SSL_B_MARK, + MOSI_IO0_B_MARK, MISO_IO1_B_MARK, IO2_B_MARK, IO3_B_MARK, }; /* - SCIF0 ------------------------------------------------------------------ */ static const unsigned int scif0_data_pins[] = { -- GitLab From c6e7548315d703b5194f793c346c7fd93bd0d42f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 12 Dec 2018 11:12:20 +0100 Subject: [PATCH 0330/1055] pinctrl: sh-pfc: r8a7791: Remove bogus marks from vin1_b_data18 group [ Upstream commit 0d6256cb880166a4111bebce35790019e56b6e1b ] The vin1_b_data18_mux[] arrays contains pin marks for the 2 LSB bits of the color components. The vin1_b_data18_pins[] array rightfully does not include the corresponding pin numbers, as RGB18 is subset of RGB24, containing only the 6 MSB bits of each component. Fixes: 8e32c9671f84acd8 ("pinctrl: sh-pfc: r8a7791: Add VIN pins") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-r8a7791.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index 8600ba82f59c..d34982ea66bf 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -4348,17 +4348,14 @@ static const unsigned int vin1_b_data18_pins[] = { }; static const unsigned int vin1_b_data18_mux[] = { /* B */ - VI1_DATA0_B_MARK, VI1_DATA1_B_MARK, VI1_DATA2_B_MARK, VI1_DATA3_B_MARK, VI1_DATA4_B_MARK, VI1_DATA5_B_MARK, VI1_DATA6_B_MARK, VI1_DATA7_B_MARK, /* G */ - VI1_G0_B_MARK, VI1_G1_B_MARK, VI1_G2_B_MARK, VI1_G3_B_MARK, VI1_G4_B_MARK, VI1_G5_B_MARK, VI1_G6_B_MARK, VI1_G7_B_MARK, /* R */ - VI1_R0_B_MARK, VI1_R1_B_MARK, VI1_R2_B_MARK, VI1_R3_B_MARK, VI1_R4_B_MARK, VI1_R5_B_MARK, VI1_R6_B_MARK, VI1_R7_B_MARK, -- GitLab From 7dcf563d22795fef5d4a3476bed486fc1f013efe Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 12 Dec 2018 11:20:14 +0100 Subject: [PATCH 0331/1055] pinctrl: sh-pfc: sh73a0: Add missing TO pin to tpu4_to3 group [ Upstream commit 124cde98f856b6206b804acbdec3b7c80f8c3427 ] The tpu4_to3_mux[] array contains the TPU4TO3 pin mark, but the tpu4_to3_pins[] array lacks the corresponding pin number. Add the missing pin number, for non-GPIO pin F26. Fixes: 5da4eb049de803c7 ("sh-pfc: sh73a0: Add TPU pin groups and functions") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-sh73a0.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c index d25e6f674d0a..f8fbedb46585 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c @@ -3086,6 +3086,7 @@ static const unsigned int tpu4_to2_mux[] = { }; static const unsigned int tpu4_to3_pins[] = { /* TO */ + PIN_NUMBER(6, 26), }; static const unsigned int tpu4_to3_mux[] = { TPU4TO3_MARK, -- GitLab From 8c387ed6cc6d234d3c0eafa9ecadaaac6aa27b30 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 12 Dec 2018 14:21:16 +0100 Subject: [PATCH 0332/1055] pinctrl: sh-pfc: r8a7794: Remove bogus IPSR9 field [ Upstream commit 6a6c195d98a1a5e70faa87f594d7564af1dd1bed ] The Peripheral Function Select Register 9 contains 12 fields, but the variable field descriptor contains a 13th bogus field of 3 bits. Fixes: 43c4436e2f1890a7 ("pinctrl: sh-pfc: add R8A7794 PFC support") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-r8a7794.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c index a0ed220071f5..93bdd3e8fb67 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c @@ -4742,7 +4742,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { FN_AVB_MDC, FN_SSI_SDATA6_B, 0, 0, } }, { PINMUX_CFG_REG_VAR("IPSR9", 0xE6060044, 32, - 1, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3) { + 1, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3) { /* IP9_31 [1] */ 0, 0, /* IP9_30_28 [3] */ -- GitLab From 7fb9bf82e2a0e8271110498a029f8092bc2debc4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 12 Dec 2018 14:42:16 +0100 Subject: [PATCH 0333/1055] pinctrl: sh-pfc: sh7734: Add missing IPSR11 field [ Upstream commit 94482af7055e1ffa211c1135256b85590ebcac99 ] The Peripheral Function Select Register 11 contains 3 reserved bits and 15 variable-width fields, but the variable field descriptor does not contain the 3-bit field IP11[25:23]. Fixes: 856cb4bb337ee504 ("sh: Add support pinmux for SH7734") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-sh7734.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7734.c b/drivers/pinctrl/sh-pfc/pfc-sh7734.c index 3eccc9b3ca84..05ccb27f7781 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7734.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7734.c @@ -2237,7 +2237,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { FN_LCD_DATA15_B, 0, 0, 0 } }, { PINMUX_CFG_REG_VAR("IPSR11", 0xFFFC0048, 32, - 3, 1, 2, 2, 2, 3, 3, 1, 2, 3, 3, 1, 1, 1, 1) { + 3, 1, 2, 3, 2, 2, 3, 3, 1, 2, 3, 3, 1, 1, 1, 1) { /* IP11_31_29 [3] */ 0, 0, 0, 0, 0, 0, 0, 0, /* IP11_28 [1] */ -- GitLab From 5a442c5c032d6afcc26225ef5180b8ac4c85696e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 13 Dec 2018 13:59:42 +0100 Subject: [PATCH 0334/1055] pinctrl: sh-pfc: r8a77995: Remove bogus SEL_PWM[0-3]_3 configurations [ Upstream commit e28dc3f09c9d2555a9bd982f0847988591052226 ] While the SEL_PWM[0-3] fields in the Module Select Register 0 support 4 possible configurations per PWM pin, only the first 3 are valid. Replace the invalid and unused configurations for SEL_PWM[0-3]_3 by dummies. Fixes: 794a6711764658a1 ("pinctrl: sh-pfc: Initial R8A77995 PFC support") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-r8a77995.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c index 4f5ee1d7317d..36421df1b326 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a77995.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a77995.c @@ -391,10 +391,10 @@ FM(IP12_31_28) IP12_31_28 \ #define MOD_SEL0_27 FM(SEL_MSIOF3_0) FM(SEL_MSIOF3_1) #define MOD_SEL0_26 FM(SEL_HSCIF3_0) FM(SEL_HSCIF3_1) #define MOD_SEL0_25 FM(SEL_SCIF4_0) FM(SEL_SCIF4_1) -#define MOD_SEL0_24_23 FM(SEL_PWM0_0) FM(SEL_PWM0_1) FM(SEL_PWM0_2) FM(SEL_PWM0_3) -#define MOD_SEL0_22_21 FM(SEL_PWM1_0) FM(SEL_PWM1_1) FM(SEL_PWM1_2) FM(SEL_PWM1_3) -#define MOD_SEL0_20_19 FM(SEL_PWM2_0) FM(SEL_PWM2_1) FM(SEL_PWM2_2) FM(SEL_PWM2_3) -#define MOD_SEL0_18_17 FM(SEL_PWM3_0) FM(SEL_PWM3_1) FM(SEL_PWM3_2) FM(SEL_PWM3_3) +#define MOD_SEL0_24_23 FM(SEL_PWM0_0) FM(SEL_PWM0_1) FM(SEL_PWM0_2) F_(0, 0) +#define MOD_SEL0_22_21 FM(SEL_PWM1_0) FM(SEL_PWM1_1) FM(SEL_PWM1_2) F_(0, 0) +#define MOD_SEL0_20_19 FM(SEL_PWM2_0) FM(SEL_PWM2_1) FM(SEL_PWM2_2) F_(0, 0) +#define MOD_SEL0_18_17 FM(SEL_PWM3_0) FM(SEL_PWM3_1) FM(SEL_PWM3_2) F_(0, 0) #define MOD_SEL0_15 FM(SEL_IRQ_0_0) FM(SEL_IRQ_0_1) #define MOD_SEL0_14 FM(SEL_IRQ_1_0) FM(SEL_IRQ_1_1) #define MOD_SEL0_13 FM(SEL_IRQ_2_0) FM(SEL_IRQ_2_1) -- GitLab From d2e6f04f6ee3fe5e4f72eb1763f228c4a0c2c701 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 13 Dec 2018 14:27:56 +0100 Subject: [PATCH 0335/1055] pinctrl: sh-pfc: sh7269: Add missing PCIOR0 field [ Upstream commit 9540cbdfcd861caf67a6f0e4bb7f46d41c4aad86 ] The Port C I/O Register 0 contains 7 reserved bits, but the descriptor contains only dummy configuration values for 6 reserved bits, thus breaking the configuration of all subsequent fields in the register. Fix this by adding the two missing configuration values. Fixes: f5e811f2a43117b2 ("sh-pfc: Add sh7269 pinmux support") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-sh7269.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7269.c b/drivers/pinctrl/sh-pfc/pfc-sh7269.c index a50d22bef1f4..cfdb4fc177c3 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7269.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7269.c @@ -2119,7 +2119,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { }, { PINMUX_CFG_REG("PCIOR0", 0xfffe3852, 16, 1) { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PC8_IN, PC8_OUT, PC7_IN, PC7_OUT, PC6_IN, PC6_OUT, -- GitLab From 311550b992d4694a223a7f0c2a5aaeac00f4249d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 13 Dec 2018 14:32:34 +0100 Subject: [PATCH 0336/1055] pinctrl: sh-pfc: sh7734: Remove bogus IPSR10 value [ Upstream commit 4d374bacd7c9665179f9752a52d5d602c45d8190 ] The IP10[5:3] field in Peripheral Function Select Register 10 has a width of 3 bits, i.e. it allows programming one out of 8 different configurations. However, 9 values are provided instead of 8, overflowing into the subsequent field in the register, and thus breaking the configuration of the latter. Fix this by dropping a bogus zero value. Fixes: ac1ebc2190f575fc ("sh-pfc: Add sh7734 pinmux support") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-sh7734.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7734.c b/drivers/pinctrl/sh-pfc/pfc-sh7734.c index 05ccb27f7781..c691e5e9d9de 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh7734.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh7734.c @@ -2231,7 +2231,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { FN_LCD_CL1_B, 0, 0, /* IP10_5_3 [3] */ FN_SSI_WS23, FN_VI1_5_B, FN_TX1_D, FN_HSCK0_C, FN_FALE_B, - FN_LCD_DON_B, 0, 0, 0, + FN_LCD_DON_B, 0, 0, /* IP10_2_0 [3] */ FN_SSI_SCK23, FN_VI1_4_B, FN_RX1_D, FN_FCLE_B, FN_LCD_DATA15_B, 0, 0, 0 } -- GitLab From 43c3e957462b3f13dab55197bb3bcb9155b301b8 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Tue, 18 Dec 2018 13:16:02 +0000 Subject: [PATCH 0337/1055] vxlan: changelink: Fix handling of default remotes [ Upstream commit ce5e098f7a10b4bf8e948c12fa350320c5c3afad ] Default remotes are stored as FDB entries with an Ethernet address of 00:00:00:00:00:00. When a request is made to change a remote address of a VXLAN device, vxlan_changelink() first deletes the existing default remote, and then creates a new FDB entry. This works well as long as the list of default remotes matches exactly the configuration of a VXLAN remote address. Thus when the VXLAN device has a remote of X, there should be exactly one default remote FDB entry X. If the VXLAN device has no remote address, there should be no such entry. Besides using "ip link set", it is possible to manipulate the list of default remotes by using the "bridge fdb". It is therefore easy to break the above condition. Under such circumstances, the __vxlan_fdb_delete() call doesn't delete the FDB entry itself, but just one remote. The following vxlan_fdb_create() then creates a new FDB entry, leading to a situation where two entries exist for the address 00:00:00:00:00:00, each with a different subset of default remotes. An even more obvious breakage rooted in the same cause can be observed when a remote address is configured for a VXLAN device that did not have one before. In that case vxlan_changelink() doesn't remove any remote, and just creates a new FDB entry for the new address: $ ip link add name vx up type vxlan id 2000 dstport 4789 $ bridge fdb ap dev vx 00:00:00:00:00:00 dst 192.0.2.20 self permanent $ bridge fdb ap dev vx 00:00:00:00:00:00 dst 192.0.2.30 self permanent $ ip link set dev vx type vxlan remote 192.0.2.30 $ bridge fdb sh dev vx | grep 00:00:00:00:00:00 00:00:00:00:00:00 dst 192.0.2.30 self permanent <- new entry, 1 rdst 00:00:00:00:00:00 dst 192.0.2.20 self permanent <- orig. entry, 2 rdsts 00:00:00:00:00:00 dst 192.0.2.30 self permanent To fix this, instead of calling vxlan_fdb_create() directly, defer to vxlan_fdb_update(). That has logic to handle the duplicates properly. Additionally, it also handles notifications, so drop that call from changelink as well. Fixes: 0241b836732f ("vxlan: fix default fdb entry netlink notify ordering during netdev create") Signed-off-by: Petr Machata Acked-by: Roopa Prabhu Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/vxlan.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 5aa7d5091f4d..4d97a7b5fe3c 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -3494,7 +3494,6 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], struct vxlan_rdst *dst = &vxlan->default_dst; struct vxlan_rdst old_dst; struct vxlan_config conf; - struct vxlan_fdb *f = NULL; int err; err = vxlan_nl2conf(tb, data, @@ -3520,19 +3519,19 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[], old_dst.remote_ifindex, 0); if (!vxlan_addr_any(&dst->remote_ip)) { - err = vxlan_fdb_create(vxlan, all_zeros_mac, + err = vxlan_fdb_update(vxlan, all_zeros_mac, &dst->remote_ip, NUD_REACHABLE | NUD_PERMANENT, + NLM_F_APPEND | NLM_F_CREATE, vxlan->cfg.dst_port, dst->remote_vni, dst->remote_vni, dst->remote_ifindex, - NTF_SELF, &f); + NTF_SELF); if (err) { spin_unlock_bh(&vxlan->hash_lock); return err; } - vxlan_fdb_notify(vxlan, f, first_remote_rtnl(f), RTM_NEWNEIGH); } spin_unlock_bh(&vxlan->hash_lock); } -- GitLab From 15751bde70756fb2e84e6f9fb96c183fe4b31954 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Dec 2018 00:38:30 -0800 Subject: [PATCH 0338/1055] Input: nomadik-ske-keypad - fix a loop timeout test [ Upstream commit 4d8f727b83bcd6702c2d210330872c9122d2d360 ] The loop exits with "timeout" set to -1 not to 0. Fixes: 1158f0f16224 ("Input: add support for Nomadik SKE keypad controller") Signed-off-by: Dan Carpenter Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin --- drivers/input/keyboard/nomadik-ske-keypad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index 8567ee47761e..ae3b04557074 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -100,7 +100,7 @@ static int __init ske_keypad_chip_init(struct ske_keypad *keypad) while ((readl(keypad->reg_base + SKE_RIS) != 0x00000000) && timeout--) cpu_relax(); - if (!timeout) + if (timeout == -1) return -EINVAL; /* -- GitLab From 4483d0e723477f76b59fe0b8213fd35d6d0a9ecb Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:10:01 -0500 Subject: [PATCH 0339/1055] clk: highbank: fix refcount leak in hb_clk_init() [ Upstream commit 5eb8ba90958de1285120dae5d3a5d2b1a360b3b4 ] The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 26cae166cff9 ("ARM: highbank: remove custom .init_time hook") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/clk-highbank.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c index 727ed8e1bb72..8e4581004695 100644 --- a/drivers/clk/clk-highbank.c +++ b/drivers/clk/clk-highbank.c @@ -293,6 +293,7 @@ static __init struct clk *hb_clk_init(struct device_node *node, const struct clk /* Map system registers */ srnp = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs"); hb_clk->reg = of_iomap(srnp, 0); + of_node_put(srnp); BUG_ON(!hb_clk->reg); hb_clk->reg += reg; -- GitLab From 6c3e2bc4635e31b48147b34c7810c187e351b8d6 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:14:42 -0500 Subject: [PATCH 0340/1055] clk: qoriq: fix refcount leak in clockgen_init() [ Upstream commit 70af6c5b5270e8101f318c4b69cc98a726edfab9 ] The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 0dfc86b3173f ("clk: qoriq: Move chip-specific knowledge into driver") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/clk-qoriq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c index 1a292519d84f..999a90a16609 100644 --- a/drivers/clk/clk-qoriq.c +++ b/drivers/clk/clk-qoriq.c @@ -1382,6 +1382,7 @@ static void __init clockgen_init(struct device_node *np) pr_err("%s: Couldn't map %pOF regs\n", __func__, guts); } + of_node_put(guts); } } -- GitLab From 0e5dbea8fdaa1b4f64e00bac5ec5844c429f324d Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:29:02 -0500 Subject: [PATCH 0341/1055] clk: socfpga: fix refcount leak [ Upstream commit 7f9705beeb3759e69165e7aff588f6488ff6c1ac ] The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 5343325ff3dd ("clk: socfpga: add a clock driver for the Arria 10 platform") Fixes: a30d27ed739b ("clk: socfpga: fix clock driver for 3.15") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/socfpga/clk-pll-a10.c | 1 + drivers/clk/socfpga/clk-pll.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/clk/socfpga/clk-pll-a10.c b/drivers/clk/socfpga/clk-pll-a10.c index 35fabe1a32c3..269467e8e07e 100644 --- a/drivers/clk/socfpga/clk-pll-a10.c +++ b/drivers/clk/socfpga/clk-pll-a10.c @@ -95,6 +95,7 @@ static struct clk * __init __socfpga_pll_init(struct device_node *node, clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); clk_mgr_a10_base_addr = of_iomap(clkmgr_np, 0); + of_node_put(clkmgr_np); BUG_ON(!clk_mgr_a10_base_addr); pll_clk->hw.reg = clk_mgr_a10_base_addr + reg; diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c index c7f463172e4b..b4b44e9b5901 100644 --- a/drivers/clk/socfpga/clk-pll.c +++ b/drivers/clk/socfpga/clk-pll.c @@ -100,6 +100,7 @@ static __init struct clk *__socfpga_pll_init(struct device_node *node, clkmgr_np = of_find_compatible_node(NULL, NULL, "altr,clk-mgr"); clk_mgr_base_addr = of_iomap(clkmgr_np, 0); + of_node_put(clkmgr_np); BUG_ON(!clk_mgr_base_addr); pll_clk->hw.reg = clk_mgr_base_addr + reg; -- GitLab From 3e080a42d5011fd0a6bf1fdbbe4b7476ecaeb47c Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:32:15 -0500 Subject: [PATCH 0342/1055] clk: samsung: exynos4: fix refcount leak in exynos4_get_xom() [ Upstream commit cee82eb9532090cd1dc953e845d71f9b1445c84e ] The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: e062b571777f ("clk: exynos4: register clocks using common clock framework") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/samsung/clk-exynos4.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index d8d3cb67b402..3d3026221927 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -1240,6 +1240,7 @@ static unsigned long __init exynos4_get_xom(void) xom = readl(chipid_base + 8); iounmap(chipid_base); + of_node_put(np); } return xom; -- GitLab From f55851dbf0ee077452b79678d795943e5e1f5121 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:53:00 -0500 Subject: [PATCH 0343/1055] clk: imx6q: fix refcount leak in imx6q_clocks_init() [ Upstream commit c9ec1d8fef31b5fc9e90e99f9bd685db5caa7c5e ] The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 2acd1b6f889c ("ARM: i.MX6: implement clocks using common clock framework") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/imx/clk-imx6q.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index 8eb93eb2f857..e0547654cb7b 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -431,6 +431,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop"); anatop_base = base = of_iomap(np, 0); WARN_ON(!base); + of_node_put(np); /* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */ if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) { -- GitLab From b88284ee4364acac121148fed4649f2214fd1b94 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:55:10 -0500 Subject: [PATCH 0344/1055] clk: imx6sx: fix refcount leak in imx6sx_clocks_init() [ Upstream commit 1731e14fb30212dd8c1e9f8fc1af061e56498c55 ] The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: d55135689019 ("ARM: imx: add clock driver for imx6sx") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/imx/clk-imx6sx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c index e6d389e333d7..baa07553a0dd 100644 --- a/drivers/clk/imx/clk-imx6sx.c +++ b/drivers/clk/imx/clk-imx6sx.c @@ -164,6 +164,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop"); base = of_iomap(np, 0); WARN_ON(!base); + of_node_put(np); clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels)); -- GitLab From 006495b2ecd3c677cdfc54332b102e4165ce7e62 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:57:16 -0500 Subject: [PATCH 0345/1055] clk: imx7d: fix refcount leak in imx7d_clocks_init() [ Upstream commit 5f8c183a996b76bb09748073c856e4246fd4ce95 ] The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 8f6d8094b215 ("ARM: imx: add imx7d clk tree support") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/imx/clk-imx7d.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 0ac9b30c8b90..9f5e5b9d4a25 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -416,6 +416,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop"); base = of_iomap(np, 0); WARN_ON(!base); + of_node_put(np); clks[IMX7D_PLL_ARM_MAIN_SRC] = imx_clk_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel)); clks[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel)); -- GitLab From ddbaa5cac637e24b77f2a9b28507599cac6006f5 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:59:36 -0500 Subject: [PATCH 0346/1055] clk: vf610: fix refcount leak in vf610_clocks_init() [ Upstream commit 567177024e0313e4f0dcba7ba10c0732e50e655d ] The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Fixes: 1f2c5fd5f048 ("ARM: imx: add VF610 clock support") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/imx/clk-vf610.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c index 6dae54325a91..a334667c450a 100644 --- a/drivers/clk/imx/clk-vf610.c +++ b/drivers/clk/imx/clk-vf610.c @@ -203,6 +203,7 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) np = of_find_compatible_node(NULL, NULL, "fsl,vf610-anatop"); anatop_base = of_iomap(np, 0); BUG_ON(!anatop_base); + of_node_put(np); np = ccm_node; ccm_base = of_iomap(np, 0); -- GitLab From a924a933d8b493a1eda0c1aa4d5b864a3dd415c3 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:36:58 -0500 Subject: [PATCH 0347/1055] clk: armada-370: fix refcount leak in a370_clk_init() [ Upstream commit a3c24050bdf70c958a8d98c2823b66ea761e6a31 ] The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 07ad6836fa21 ("clk: mvebu: armada-370: maintain clock init order") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/mvebu/armada-370.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c index 2c7c1085f883..8fdfa97900cd 100644 --- a/drivers/clk/mvebu/armada-370.c +++ b/drivers/clk/mvebu/armada-370.c @@ -177,8 +177,10 @@ static void __init a370_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &a370_coreclks); - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, a370_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init); -- GitLab From 0843f4fac91a3c0a9249f378a97b53e8f325d2ad Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:40:19 -0500 Subject: [PATCH 0348/1055] clk: kirkwood: fix refcount leak in kirkwood_clk_init() [ Upstream commit e7beeab9c61591cd0e690d8733d534c3f4278ff8 ] The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 58d516ae95cb ("clk: mvebu: kirkwood: maintain clock init order") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/mvebu/kirkwood.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c index a2a8d614039d..890ebf623261 100644 --- a/drivers/clk/mvebu/kirkwood.c +++ b/drivers/clk/mvebu/kirkwood.c @@ -333,6 +333,8 @@ static void __init kirkwood_clk_init(struct device_node *np) if (cgnp) { mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc); kirkwood_clk_muxing_setup(cgnp, kirkwood_mux_desc); + + of_node_put(cgnp); } } CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock", -- GitLab From 3af85e1c58892fb137f9cf722bf5ef777f62fcaf Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:42:26 -0500 Subject: [PATCH 0349/1055] clk: armada-xp: fix refcount leak in axp_clk_init() [ Upstream commit db20a90a4b6745dad62753f8bd2f66afdd5abc84 ] The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 0a11a6ae9437 ("clk: mvebu: armada-xp: maintain clock init order") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/mvebu/armada-xp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c index 0ec44ae9a2a2..df529982adc9 100644 --- a/drivers/clk/mvebu/armada-xp.c +++ b/drivers/clk/mvebu/armada-xp.c @@ -228,7 +228,9 @@ static void __init axp_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &axp_coreclks); - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, axp_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init); -- GitLab From 938021a99d967a9310505d3b33b5fcb258cdd08c Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:48:05 -0500 Subject: [PATCH 0350/1055] clk: mv98dx3236: fix refcount leak in mv98dx3236_clk_init() [ Upstream commit 9b4eedf627045ae5ddcff60a484200cdd554c413 ] The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 337072604224 ("clk: mvebu: Expand mv98dx3236-core-clock support") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/mvebu/mv98dx3236.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/mvebu/mv98dx3236.c b/drivers/clk/mvebu/mv98dx3236.c index 6e203af73cac..c8a0d03d2cd6 100644 --- a/drivers/clk/mvebu/mv98dx3236.c +++ b/drivers/clk/mvebu/mv98dx3236.c @@ -174,7 +174,9 @@ static void __init mv98dx3236_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &mv98dx3236_core_clocks); - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, mv98dx3236_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(mv98dx3236_clk, "marvell,mv98dx3236-core-clock", mv98dx3236_clk_init); -- GitLab From c9585b6996e002e55ba9c5db257e8bcc60574443 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 26 Dec 2018 08:50:13 -0500 Subject: [PATCH 0351/1055] clk: dove: fix refcount leak in dove_clk_init() [ Upstream commit 8d726c5128298386b907963033be93407b0c4275 ] The of_find_compatible_node() returns a node pointer with refcount incremented, but there is the lack of use of the of_node_put() when done. Add the missing of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Gregory CLEMENT Fixes: 8f7fc5450b64 ("clk: mvebu: dove: maintain clock init order") Fixes: 63b8d92c793f ("clk: add Dove PLL divider support for GPU, VMeta and AXI clocks") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/mvebu/dove.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c index 59fad9546c84..5f258c9bb68b 100644 --- a/drivers/clk/mvebu/dove.c +++ b/drivers/clk/mvebu/dove.c @@ -190,10 +190,14 @@ static void __init dove_clk_init(struct device_node *np) mvebu_coreclk_setup(np, &dove_coreclks); - if (ddnp) + if (ddnp) { dove_divider_clk_init(ddnp); + of_node_put(ddnp); + } - if (cgnp) + if (cgnp) { mvebu_clk_gating_setup(cgnp, dove_gating_desc); + of_node_put(cgnp); + } } CLK_OF_DECLARE(dove_clk, "marvell,dove-core-clock", dove_clk_init); -- GitLab From 97f78f43c0fa18b80fd60a6c6f9fabc1a62faaf9 Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Sun, 30 Dec 2018 12:55:09 +0100 Subject: [PATCH 0352/1055] MIPS: BCM63XX: drop unused and broken DSP platform device [ Upstream commit 682fee802843b332f9c51ffc8e062de5ff773f2e ] Trying to register the DSP platform device results in a null pointer access: [ 0.124184] CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == 804e305c, ra == 804e6f20 [ 0.135208] Oops[#1]: [ 0.137514] CPU: 0 PID: 1 Comm: swapper Not tainted 4.14.87 ... [ 0.197117] epc : 804e305c bcm63xx_dsp_register+0x80/0xa4 [ 0.202838] ra : 804e6f20 board_register_devices+0x258/0x390 ... This happens because it tries to copy the passed platform data over the platform_device's unpopulated platform_data. Since this code has been broken since its submission, no driver was ever submitted for it, and apparently nobody was using it, just remove it instead of trying to fix it. Fixes: e7300d04bd08 ("MIPS: BCM63xx: Add support for the Broadcom BCM63xx family of SOCs.") Signed-off-by: Jonas Gorski Signed-off-by: Paul Burton Acked-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: Ralf Baechle Cc: James Hogan Signed-off-by: Sasha Levin --- arch/mips/bcm63xx/Makefile | 6 +- arch/mips/bcm63xx/boards/board_bcm963xx.c | 20 ------- arch/mips/bcm63xx/dev-dsp.c | 56 ------------------- .../asm/mach-bcm63xx/bcm63xx_dev_dsp.h | 14 ----- .../include/asm/mach-bcm63xx/board_bcm963xx.h | 5 -- 5 files changed, 3 insertions(+), 98 deletions(-) delete mode 100644 arch/mips/bcm63xx/dev-dsp.c delete mode 100644 arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_dsp.h diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile index c69f297fc1df..d89651e538f6 100644 --- a/arch/mips/bcm63xx/Makefile +++ b/arch/mips/bcm63xx/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += clk.o cpu.o cs.o gpio.o irq.o nvram.o prom.o reset.o \ - setup.o timer.o dev-dsp.o dev-enet.o dev-flash.o \ - dev-pcmcia.o dev-rng.o dev-spi.o dev-hsspi.o dev-uart.o \ - dev-wdt.o dev-usb-usbd.o + setup.o timer.o dev-enet.o dev-flash.o dev-pcmcia.o \ + dev-rng.o dev-spi.o dev-hsspi.o dev-uart.o dev-wdt.o \ + dev-usb-usbd.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-y += boards/ diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index b2097c0d2ed7..36ec3dc2c999 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -289,14 +288,6 @@ static struct board_info __initdata board_96348gw_10 = { .has_pccard = 1, .has_ehci0 = 1, - .has_dsp = 1, - .dsp = { - .gpio_rst = 6, - .gpio_int = 34, - .cs = 2, - .ext_irq = 2, - }, - .leds = { { .name = "adsl-fail", @@ -401,14 +392,6 @@ static struct board_info __initdata board_96348gw = { .has_ohci0 = 1, - .has_dsp = 1, - .dsp = { - .gpio_rst = 6, - .gpio_int = 34, - .ext_irq = 2, - .cs = 2, - }, - .leds = { { .name = "adsl-fail", @@ -898,9 +881,6 @@ int __init board_register_devices(void) if (board.has_usbd) bcm63xx_usbd_register(&board.usbd); - if (board.has_dsp) - bcm63xx_dsp_register(&board.dsp); - /* Generate MAC address for WLAN and register our SPROM, * do this after registering enet devices */ diff --git a/arch/mips/bcm63xx/dev-dsp.c b/arch/mips/bcm63xx/dev-dsp.c deleted file mode 100644 index 5bb5b154c9bd..000000000000 --- a/arch/mips/bcm63xx/dev-dsp.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Broadcom BCM63xx VoIP DSP registration - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2009 Florian Fainelli - */ - -#include -#include -#include - -#include -#include -#include -#include - -static struct resource voip_dsp_resources[] = { - { - .start = -1, /* filled at runtime */ - .end = -1, /* filled at runtime */ - .flags = IORESOURCE_MEM, - }, - { - .start = -1, /* filled at runtime */ - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device bcm63xx_voip_dsp_device = { - .name = "bcm63xx-voip-dsp", - .id = -1, - .num_resources = ARRAY_SIZE(voip_dsp_resources), - .resource = voip_dsp_resources, -}; - -int __init bcm63xx_dsp_register(const struct bcm63xx_dsp_platform_data *pd) -{ - struct bcm63xx_dsp_platform_data *dpd; - u32 val; - - /* Get the memory window */ - val = bcm_mpi_readl(MPI_CSBASE_REG(pd->cs - 1)); - val &= MPI_CSBASE_BASE_MASK; - voip_dsp_resources[0].start = val; - voip_dsp_resources[0].end = val + 0xFFFFFFF; - voip_dsp_resources[1].start = pd->ext_irq; - - /* copy given platform data */ - dpd = bcm63xx_voip_dsp_device.dev.platform_data; - memcpy(dpd, pd, sizeof (*pd)); - - return platform_device_register(&bcm63xx_voip_dsp_device); -} diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_dsp.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_dsp.h deleted file mode 100644 index 4e4970787371..000000000000 --- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_dsp.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __BCM63XX_DSP_H -#define __BCM63XX_DSP_H - -struct bcm63xx_dsp_platform_data { - unsigned gpio_rst; - unsigned gpio_int; - unsigned cs; - unsigned ext_irq; -}; - -int __init bcm63xx_dsp_register(const struct bcm63xx_dsp_platform_data *pd); - -#endif /* __BCM63XX_DSP_H */ diff --git a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h index 5e5b1bc4a324..830f53f28e3f 100644 --- a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h +++ b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h @@ -7,7 +7,6 @@ #include #include #include -#include /* * flash mapping @@ -31,7 +30,6 @@ struct board_info { unsigned int has_ohci0:1; unsigned int has_ehci0:1; unsigned int has_usbd:1; - unsigned int has_dsp:1; unsigned int has_uart0:1; unsigned int has_uart1:1; @@ -43,9 +41,6 @@ struct board_info { /* USB config */ struct bcm63xx_usbd_platform_data usbd; - /* DSP config */ - struct bcm63xx_dsp_platform_data dsp; - /* GPIO LEDs */ struct gpio_led leds[5]; -- GitLab From 4963f23081cc55c4e92269c8e0c13f85c63e9094 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Mon, 7 Jan 2019 17:27:54 +0200 Subject: [PATCH 0353/1055] IB/usnic: Fix out of bounds index check in query pkey [ Upstream commit 4959d5da5737dd804255c75b8cea0a2929ce279a ] The pkey table size is one element, index should be tested for > 0 instead of > 1. Fixes: e3cf00d0a87f ("IB/usnic: Add Cisco VIC low-level hardware driver") Signed-off-by: Gal Pressman Acked-by: Parvi Kaustubhi Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/hw/usnic/usnic_ib_verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c index fdfa25059723..2602c7375d58 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c @@ -423,7 +423,7 @@ struct net_device *usnic_get_netdev(struct ib_device *device, u8 port_num) int usnic_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) { - if (index > 1) + if (index > 0) return -EINVAL; *pkey = 0xffff; -- GitLab From 499cd1060357131a4348534f8cf35b8b4e0efb5f Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Mon, 7 Jan 2019 17:27:55 +0200 Subject: [PATCH 0354/1055] RDMA/ocrdma: Fix out of bounds index check in query pkey [ Upstream commit b188940796c7be31c1b8c25a9a0e0842c2e7a49e ] The pkey table size is one element, index should be tested for > 0 instead of > 1. Fixes: fe2caefcdf58 ("RDMA/ocrdma: Add driver for Emulex OneConnect IBoE RDMA adapter") Signed-off-by: Gal Pressman Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index 27d5e8d9f08d..7683d13dad3d 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -55,7 +55,7 @@ int ocrdma_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) { - if (index > 1) + if (index > 0) return -EINVAL; *pkey = 0xffff; -- GitLab From 346e59489df79cb0e1dd2647560b6e64a3c0bbb2 Mon Sep 17 00:00:00 2001 From: Gal Pressman Date: Mon, 7 Jan 2019 17:27:56 +0200 Subject: [PATCH 0355/1055] RDMA/qedr: Fix out of bounds index check in query pkey [ Upstream commit dbe30dae487e1a232158c24b432d45281c2805b7 ] The pkey table size is QEDR_ROCE_PKEY_TABLE_LEN, index should be tested for >= QEDR_ROCE_PKEY_TABLE_LEN instead of > QEDR_ROCE_PKEY_TABLE_LEN. Fixes: a7efd7773e31 ("qedr: Add support for PD,PKEY and CQ verbs") Signed-off-by: Gal Pressman Acked-by: Michal Kalderon Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/hw/qedr/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 656e7c1a4449..8bfe9073da78 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -63,7 +63,7 @@ static inline int qedr_ib_copy_to_udata(struct ib_udata *udata, void *src, int qedr_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) { - if (index > QEDR_ROCE_PKEY_TABLE_LEN) + if (index >= QEDR_ROCE_PKEY_TABLE_LEN) return -EINVAL; *pkey = QEDR_ROCE_PKEY_DEFAULT; -- GitLab From f5ed3f2b4b72f584e639863ecbac090c622f0ffc Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 17 Dec 2018 17:18:30 +0800 Subject: [PATCH 0356/1055] drm/shmob: Fix return value check in shmob_drm_probe [ Upstream commit 06c3bbd3c12737a50c2e981821b5585e1786e73d ] In case of error, the function devm_ioremap_resource() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Fixes: 8f1597c8f1a5 ("drm: shmobile: Perform initialization/cleanup at probe/remove time") Signed-off-by: YueHaibing Reviewed-by: Simon Horman Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Sasha Levin --- drivers/gpu/drm/shmobile/shmob_drm_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c index 592572554eb0..58d8a98c749b 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c @@ -233,8 +233,8 @@ static int shmob_drm_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); sdev->mmio = devm_ioremap_resource(&pdev->dev, res); - if (sdev->mmio == NULL) - return -ENOMEM; + if (IS_ERR(sdev->mmio)) + return PTR_ERR(sdev->mmio); ret = shmob_drm_setup_clocks(sdev, pdata->clk_source); if (ret < 0) -- GitLab From 91eebda6ad45d30fc46c910c090272693a8ef99d Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 14 Dec 2018 12:01:02 +0100 Subject: [PATCH 0357/1055] arm64: dts: apq8016-sbc: Increase load on l11 for SDCARD [ Upstream commit af61bef513ba179559e56908b8c465e587bc3890 ] In the same way as for msm8974-hammerhead, l11 load, used for SDCARD VMMC, needs to be increased in order to prevent any voltage drop issues (due to limited current) happening with some SDCARDS or during specific operations (e.g. write). Tested on Dragonboard-410c and DART-SD410 boards. Fixes: 4c7d53d16d77 (arm64: dts: apq8016-sbc: add regulators support) Reported-by: Manabu Igusa Signed-off-by: Loic Poulain Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi index b6b44fdf7fac..c1028b47edde 100644 --- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi @@ -458,6 +458,8 @@ l11 { regulator-min-microvolt = <1750000>; regulator-max-microvolt = <3337000>; + regulator-allow-set-load; + regulator-system-load = <200000>; }; l12 { -- GitLab From 45ad6d87fd90814aee96d9d6cd2dd76fe0e1d5e5 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 4 Jan 2019 18:08:09 +0000 Subject: [PATCH 0358/1055] spi: cadence: Correct initialisation of runtime PM [ Upstream commit 734882a8bf984c2ac8a57d8ac3ee53230bd0bed8 ] Currently the driver calls pm_runtime_put_autosuspend but without ever having done a pm_runtime_get, this causes the reference count in the pm runtime core to become -1. The bad reference count causes the core to sometimes suspend whilst an active SPI transfer is in progress. arizona spi0.1: SPI transfer timed out spi_master spi0: failed to transfer one message from queue The correct proceedure is to do all the initialisation that requires the hardware to be powered up before enabling the PM runtime, then enable the PM runtime having called pm_runtime_set_active to inform it that the hardware is currently powered up. The core will then power it down at it's leisure and no explicit pm_runtime_put is required. Fixes: d36ccd9f7ea4 ("spi: cadence: Runtime pm adaptation") Signed-off-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-cadence.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 02bd1eba045b..d08ad93d97a1 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -584,11 +584,6 @@ static int cdns_spi_probe(struct platform_device *pdev) goto clk_dis_apb; } - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - ret = of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs); if (ret < 0) master->num_chipselect = CDNS_SPI_DEFAULT_NUM_CS; @@ -603,8 +598,10 @@ static int cdns_spi_probe(struct platform_device *pdev) /* SPI controller initializations */ cdns_spi_init_hw(xspi); - pm_runtime_mark_last_busy(&pdev->dev); - pm_runtime_put_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); irq = platform_get_irq(pdev, 0); if (irq <= 0) { -- GitLab From 70da6cce28e018bf19d0ace8d2e34cfbe14fe159 Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Fri, 11 Jan 2019 20:27:18 +0530 Subject: [PATCH 0359/1055] RDMA/iw_cxgb4: Fix the unchecked ep dereference [ Upstream commit 3352976c892301fd576a2e9ff0ac7337b2e2ca48 ] The patch 944661dd97f4: "RDMA/iw_cxgb4: atomically lookup ep and get a reference" from May 6, 2016, leads to the following Smatch complaint: drivers/infiniband/hw/cxgb4/cm.c:2953 terminate() error: we previously assumed 'ep' could be null (see line 2945) Fixes: 944661dd97f4 ("RDMA/iw_cxgb4: atomically lookup ep and get a reference") Reported-by: Dan Carpenter Signed-off-by: Raju Rangoju Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/hw/cxgb4/cm.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index bb36cdf82a8d..3668cc71b47e 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -2923,15 +2923,18 @@ static int terminate(struct c4iw_dev *dev, struct sk_buff *skb) ep = get_ep_from_tid(dev, tid); BUG_ON(!ep); - if (ep && ep->com.qp) { - pr_warn("TERM received tid %u qpid %u\n", - tid, ep->com.qp->wq.sq.qid); - attrs.next_state = C4IW_QP_STATE_TERMINATE; - c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, - C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); + if (ep) { + if (ep->com.qp) { + pr_warn("TERM received tid %u qpid %u\n", tid, + ep->com.qp->wq.sq.qid); + attrs.next_state = C4IW_QP_STATE_TERMINATE; + c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, + C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); + } + + c4iw_put_ep(&ep->com); } else pr_warn("TERM received tid %u no ep/qp\n", tid); - c4iw_put_ep(&ep->com); return 0; } -- GitLab From 199b745a0bda8f0f5bf73c5538c91b4a644047d1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 14 Jan 2019 13:49:46 +0300 Subject: [PATCH 0360/1055] drm/etnaviv: NULL vs IS_ERR() buf in etnaviv_core_dump() [ Upstream commit f8261c376e7f8cb9024af5a6c54be540c7f9108e ] The etnaviv_gem_get_pages() never returns NULL. It returns error pointers on error. Fixes: a8c21a5451d8 ("drm/etnaviv: add initial etnaviv DRM driver") Signed-off-by: Dan Carpenter Signed-off-by: Lucas Stach Signed-off-by: Sasha Levin --- drivers/gpu/drm/etnaviv/etnaviv_dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c index 2d955d7d7b6d..e154e6fb64da 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c @@ -207,7 +207,7 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu) mutex_lock(&obj->lock); pages = etnaviv_gem_get_pages(obj); mutex_unlock(&obj->lock); - if (pages) { + if (!IS_ERR(pages)) { int j; iter.hdr->data[0] = bomap - bomap_start; -- GitLab From 69984b65b6ea27570a65c13a81ad735476aeb473 Mon Sep 17 00:00:00 2001 From: Pawe? Chmiel Date: Wed, 9 Jan 2019 13:00:41 -0500 Subject: [PATCH 0361/1055] media: s5p-jpeg: Correct step and max values for V4L2_CID_JPEG_RESTART_INTERVAL [ Upstream commit 19c624c6b29e244c418f8b44a711cbf5e82e3cd4 ] This commit corrects max and step values for v4l2 control for V4L2_CID_JPEG_RESTART_INTERVAL. Max should be 0xffff and step should be 1. It was found by using v4l2-compliance tool and checking result of VIDIOC_QUERY_EXT_CTRL/QUERYMENU test. Previously it was complaining that step was bigger than difference between max and min. Fixes: 15f4bc3b1f42 ("[media] s5p-jpeg: Add JPEG controls support") Signed-off-by: Pawe? Chmiel Reviewed-by: Jacek Anaszewski Reviewed-by: Sylwester Nawrocki Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/platform/s5p-jpeg/jpeg-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 4568e68e15fa..85a5e33600c0 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -2005,7 +2005,7 @@ static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, V4L2_CID_JPEG_RESTART_INTERVAL, - 0, 3, 0xffff, 0); + 0, 0xffff, 1, 0); if (ctx->jpeg->variant->version == SJPEG_S5P) mask = ~0x06; /* 422, 420 */ } -- GitLab From f3691b5e7d89c4367493887902d8b64a1266c360 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 15 Jan 2019 16:19:00 +0900 Subject: [PATCH 0362/1055] kbuild: mark prepare0 as PHONY to fix external module build [ Upstream commit e00d8880481497474792d28c14479a9fb6752046 ] Commit c3ff2a5193fa ("powerpc/32: add stack protector support") caused kernel panic on PowerPC when an external module is used with CONFIG_STACKPROTECTOR because the 'prepare' target was not executed for the external module build. Commit e07db28eea38 ("kbuild: fix single target build for external module") turned it into a build error because the 'prepare' target is now executed but the 'prepare0' target is missing for the external module build. External module on arm/arm64 with CONFIG_STACKPROTECTOR_PER_TASK is also broken in the same way. Move 'PHONY += prepare0' to the common place. GNU Make is fine with missing rule for phony targets. I also removed the comment which is wrong irrespective of this commit. I minimize the change so it can be easily backported to 4.20.x To fix v4.20, please backport e07db28eea38 ("kbuild: fix single target build for external module"), and then this commit. Link: https://bugzilla.kernel.org/show_bug.cgi?id=201891 Fixes: e07db28eea38 ("kbuild: fix single target build for external module") Fixes: c3ff2a5193fa ("powerpc/32: add stack protector support") Fixes: 189af4657186 ("ARM: smp: add support for per-task stack canaries") Fixes: 0a1213fa7432 ("arm64: enable per-task stack canaries") Cc: linux-stable # v4.20 Reported-by: Samuel Holland Reported-by: Alexey Kardashevskiy Signed-off-by: Masahiro Yamada Acked-by: Ard Biesheuvel Tested-by: Alexey Kardashevskiy Signed-off-by: Sasha Levin --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 3e8eaabf2bcb..b538e6170f73 100644 --- a/Makefile +++ b/Makefile @@ -971,6 +971,7 @@ ifdef CONFIG_STACK_VALIDATION endif endif +PHONY += prepare0 ifeq ($(KBUILD_EXTMOD),) core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ @@ -1065,8 +1066,7 @@ include/config/kernel.release: include/config/auto.conf FORCE # archprepare is used in arch Makefiles and when processed asm symlink, # version.h and scripts_basic is processed / created. -# Listed in dependency order -PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3 +PHONY += prepare archprepare prepare1 prepare2 prepare3 # prepare3 is used to check if we are building in a separate output directory, # and if so do: -- GitLab From bc757cbe47a3e4b8e83c0b471890eeb7a3cb986a Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 9 Jan 2019 06:11:18 +0000 Subject: [PATCH 0363/1055] crypto: brcm - Fix some set-but-not-used warning [ Upstream commit 707d0cf8f7cff6dfee9197002859912310532c4f ] Fixes gcc '-Wunused-but-set-variable' warning: drivers/crypto/bcm/cipher.c: In function 'handle_ahash_req': drivers/crypto/bcm/cipher.c:720:15: warning: variable 'chunk_start' set but not used [-Wunused-but-set-variable] drivers/crypto/bcm/cipher.c: In function 'spu_rx_callback': drivers/crypto/bcm/cipher.c:1679:31: warning: variable 'areq' set but not used [-Wunused-but-set-variable] drivers/crypto/bcm/cipher.c:1678:22: warning: variable 'ctx' set but not used [-Wunused-but-set-variable] Fixes: 9d12ba86f818 ("crypto: brcm - Add Broadcom SPU driver") Signed-off-by: YueHaibing Reviewed-by: Raveendra Padasalagi Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- drivers/crypto/bcm/cipher.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c index 84422435f39b..279e907590e9 100644 --- a/drivers/crypto/bcm/cipher.c +++ b/drivers/crypto/bcm/cipher.c @@ -718,7 +718,7 @@ static int handle_ahash_req(struct iproc_reqctx_s *rctx) */ unsigned int new_data_len; - unsigned int chunk_start = 0; + unsigned int __maybe_unused chunk_start = 0; u32 db_size; /* Length of data field, incl gcm and hash padding */ int pad_len = 0; /* total pad len, including gcm, hash, stat padding */ u32 data_pad_len = 0; /* length of GCM/CCM padding */ @@ -1676,8 +1676,6 @@ static void spu_rx_callback(struct mbox_client *cl, void *msg) struct spu_hw *spu = &iproc_priv.spu; struct brcm_message *mssg = msg; struct iproc_reqctx_s *rctx; - struct iproc_ctx_s *ctx; - struct crypto_async_request *areq; int err = 0; rctx = mssg->ctx; @@ -1687,8 +1685,6 @@ static void spu_rx_callback(struct mbox_client *cl, void *msg) err = -EFAULT; goto cb_finish; } - areq = rctx->parent; - ctx = rctx->ctx; /* process the SPU status */ err = spu->spu_status_process(rctx->msg_buf.rx_stat); -- GitLab From 478428c99780eae874e04d07a1ce32fa99a9a484 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 10 Jan 2019 12:17:58 -0800 Subject: [PATCH 0364/1055] crypto: tgr192 - fix unaligned memory access [ Upstream commit f990f7fb58ac8ac9a43316f09a48cff1a49dda42 ] Fix an unaligned memory access in tgr192_transform() by using the unaligned access helpers. Fixes: 06ace7a9bafe ("[CRYPTO] Use standard byte order macros wherever possible") Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- crypto/tgr192.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crypto/tgr192.c b/crypto/tgr192.c index 321bc6ff2a9d..904c8444aa0a 100644 --- a/crypto/tgr192.c +++ b/crypto/tgr192.c @@ -25,8 +25,9 @@ #include #include #include -#include #include +#include +#include #define TGR192_DIGEST_SIZE 24 #define TGR160_DIGEST_SIZE 20 @@ -468,10 +469,9 @@ static void tgr192_transform(struct tgr192_ctx *tctx, const u8 * data) u64 a, b, c, aa, bb, cc; u64 x[8]; int i; - const __le64 *ptr = (const __le64 *)data; for (i = 0; i < 8; i++) - x[i] = le64_to_cpu(ptr[i]); + x[i] = get_unaligned_le64(data + i * sizeof(__le64)); /* save */ a = aa = tctx->a; -- GitLab From 886969f813beca055d92fa106a7dafa3702819d0 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 18 Jan 2019 10:06:52 +0100 Subject: [PATCH 0365/1055] ASoC: imx-sgtl5000: put of nodes if finding codec fails [ Upstream commit d9866572486802bc598a3e8576a5231378d190de ] Make sure to properly put the of node in case finding the codec fails. Fixes: 81e8e4926167 ("ASoC: fsl: add sgtl5000 clock support for imx-sgtl5000") Signed-off-by: Stefan Agner Reviewed-by: Daniel Baluta Acked-by: Nicolin Chen Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/fsl/imx-sgtl5000.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 8e525f7ac08d..3d99a8579c99 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -119,7 +119,8 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) codec_dev = of_find_i2c_device_by_node(codec_np); if (!codec_dev) { dev_err(&pdev->dev, "failed to find codec platform device\n"); - return -EPROBE_DEFER; + ret = -EPROBE_DEFER; + goto fail; } data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); -- GitLab From fafa1309c2a4926a8744906d0adc2edc164dd4e3 Mon Sep 17 00:00:00 2001 From: Israel Rukshin Date: Thu, 17 Jan 2019 15:45:45 +0000 Subject: [PATCH 0366/1055] IB/iser: Pass the correct number of entries for dma mapped SGL [ Upstream commit 57b26497fabe1b9379b59fbc7e35e608e114df16 ] ib_dma_map_sg() augments the SGL into a 'dma mapped SGL'. This process may change the number of entries and the lengths of each entry. Code that touches dma_address is iterating over the 'dma mapped SGL' and must use dma_nents which returned from ib_dma_map_sg(). ib_sg_to_pages() and ib_map_mr_sg() are using dma_address so they must use dma_nents. Fixes: 39405885005a ("IB/iser: Port to new fast registration API") Fixes: bfe066e256d5 ("IB/iser: Reuse ib_sg_to_pages") Signed-off-by: Israel Rukshin Reviewed-by: Max Gurtovoy Acked-by: Sagi Grimberg Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/ulp/iser/iser_memory.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 322209d5ff58..19883169e7b7 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -240,8 +240,8 @@ int iser_fast_reg_fmr(struct iscsi_iser_task *iser_task, page_vec->npages = 0; page_vec->fake_mr.page_size = SIZE_4K; plen = ib_sg_to_pages(&page_vec->fake_mr, mem->sg, - mem->size, NULL, iser_set_page); - if (unlikely(plen < mem->size)) { + mem->dma_nents, NULL, iser_set_page); + if (unlikely(plen < mem->dma_nents)) { iser_err("page vec too short to hold this SG\n"); iser_data_buf_dump(mem, device->ib_device); iser_dump_page_vec(page_vec); @@ -450,10 +450,10 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, ib_update_fast_reg_key(mr, ib_inc_rkey(mr->rkey)); - n = ib_map_mr_sg(mr, mem->sg, mem->size, NULL, SIZE_4K); - if (unlikely(n != mem->size)) { + n = ib_map_mr_sg(mr, mem->sg, mem->dma_nents, NULL, SIZE_4K); + if (unlikely(n != mem->dma_nents)) { iser_err("failed to map sg (%d/%d)\n", - n, mem->size); + n, mem->dma_nents); return n < 0 ? n : -EINVAL; } -- GitLab From 50e12e2be9c0739c472a4b37f2ef1e5ddbfb9f68 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sun, 6 Jan 2019 08:21:03 +0000 Subject: [PATCH 0367/1055] rtc: cmos: ignore bogus century byte [ Upstream commit 2a4daadd4d3e507138f8937926e6a4df49c6bfdc ] Older versions of Libreboot and Coreboot had an invalid value (`3' in my case) in the century byte affecting the GM45 in the Thinkpad X200. Not everybody's updated their firmwares, and Linux <= 4.2 was able to read the RTC without problems, so workaround this by ignoring invalid values. Fixes: 3c217e51d8a272b9 ("rtc: cmos: century support") Cc: Alexandre Belloni Cc: Alessandro Zummo Cc: Sylvain Chouleur Cc: Patrick McDermott Cc: linux-rtc@vger.kernel.org Signed-off-by: Eric Wong Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/rtc-mc146818-lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c index 2f1772a358ca..18a6f15e313d 100644 --- a/drivers/rtc/rtc-mc146818-lib.c +++ b/drivers/rtc/rtc-mc146818-lib.c @@ -82,7 +82,7 @@ unsigned int mc146818_get_time(struct rtc_time *time) time->tm_year += real_year - 72; #endif - if (century) + if (century > 20) time->tm_year += (century - 19) * 100; /* -- GitLab From 07e548c4126bda5687c3961ff07de9fb57028c2b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 23 Jan 2019 20:00:22 +0800 Subject: [PATCH 0368/1055] spi/topcliff_pch: Fix potential NULL dereference on allocation error [ Upstream commit e902cdcb5112b89ee445588147964723fd69ffb4 ] In pch_spi_handle_dma, it doesn't check for NULL returns of kcalloc so it would result in an Oops. Fixes: c37f3c2749b5 ("spi/topcliff_pch: DMA support") Signed-off-by: YueHaibing Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-topcliff-pch.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 4389ab80c23e..fa730a871d25 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1008,6 +1008,9 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) /* RX */ dma->sg_rx_p = kcalloc(num, sizeof(*dma->sg_rx_p), GFP_ATOMIC); + if (!dma->sg_rx_p) + return; + sg_init_table(dma->sg_rx_p, num); /* Initialize SG table */ /* offset, length setting */ sg = dma->sg_rx_p; @@ -1068,6 +1071,9 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) } dma->sg_tx_p = kcalloc(num, sizeof(*dma->sg_tx_p), GFP_ATOMIC); + if (!dma->sg_tx_p) + return; + sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */ /* offset, length setting */ sg = dma->sg_tx_p; -- GitLab From 0bac5b8392da768ffe67ccc0310f35e4a64a277f Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 25 Jan 2019 11:23:04 +0800 Subject: [PATCH 0369/1055] clk: sunxi-ng: sun8i-a23: Enable PLL-MIPI LDOs when ungating it [ Upstream commit 108a459ef4cd17a28711d81092044e597b5c7618 ] The PLL-MIPI clock is somewhat special as it has its own LDOs which need to be turned on for this PLL to actually work and output a clock signal. Add the 2 LDO enable bits to the gate bits. Fixes: 5690879d93e8 ("clk: sunxi-ng: Add A23 CCU") Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Signed-off-by: Sasha Levin --- drivers/clk/sunxi-ng/ccu-sun8i-a23.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c index d93b452f0df9..1cef040ebe82 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c @@ -132,7 +132,7 @@ static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_mipi_clk, "pll-mipi", 8, 4, /* N */ 4, 2, /* K */ 0, 4, /* M */ - BIT(31), /* gate */ + BIT(31) | BIT(23) | BIT(22), /* gate */ BIT(28), /* lock */ CLK_SET_RATE_UNGATE); -- GitLab From 61c39d4a8938e8a537e466e11cb005d51004e0e6 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Sun, 21 Oct 2018 18:27:26 +0300 Subject: [PATCH 0370/1055] iwlwifi: mvm: avoid possible access out of array. [ Upstream commit b0d795a9ae558209656b18930c2b4def5f8fdfb8 ] The value in txq_id can be out of array scope, validate it before accessing the array. Signed-off-by: Mordechay Goodstein Fixes: cf961e16620f ("iwlwifi: mvm: support dqa-mode agg on non-shared queue") Signed-off-by: Luca Coelho Signed-off-by: Sasha Levin --- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 0cfdbaa2af3a..684c0f65a052 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2417,7 +2417,7 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_mvm_tid_data *tid_data; u16 normalized_ssn; - int txq_id; + u16 txq_id; int ret; if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) @@ -2452,17 +2452,24 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, */ txq_id = mvmsta->tid_data[tid].txq_id; if (txq_id == IWL_MVM_INVALID_QUEUE) { - txq_id = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, - IWL_MVM_DQA_MIN_DATA_QUEUE, - IWL_MVM_DQA_MAX_DATA_QUEUE); - if (txq_id < 0) { - ret = txq_id; + ret = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, + IWL_MVM_DQA_MIN_DATA_QUEUE, + IWL_MVM_DQA_MAX_DATA_QUEUE); + if (ret < 0) { IWL_ERR(mvm, "Failed to allocate agg queue\n"); goto release_locks; } + txq_id = ret; + /* TXQ hasn't yet been enabled, so mark it only as reserved */ mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_RESERVED; + } else if (WARN_ON(txq_id >= IWL_MAX_HW_QUEUES)) { + ret = -ENXIO; + IWL_ERR(mvm, "tid_id %d out of range (0, %d)!\n", + tid, IWL_MAX_HW_QUEUES - 1); + goto out; + } else if (unlikely(mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_SHARED)) { ret = -ENXIO; -- GitLab From 1abaee5e625d202274ed9bb32431d9958fae82cd Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Wed, 26 Dec 2018 19:21:21 +0200 Subject: [PATCH 0371/1055] net/mlx5: Take lock with IRQs disabled to avoid deadlock [ Upstream commit 33814e5d127e21f53b52e17b0722c1b57d4f4d29 ] The lock in qp_table might be taken from process context or from interrupt context. This may lead to a deadlock unless it is taken with IRQs disabled. Discovered by lockdep ================================ WARNING: inconsistent lock state 4.20.0-rc6 -------------------------------- inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-W} python/12572 [HC1[1]:SC0[0]:HE0:SE1] takes: 00000000052a4df4 (&(&table->lock)->rlock#2){?.+.}, /0x50 [mlx5_core] {HARDIRQ-ON-W} state was registered at: _raw_spin_lock+0x33/0x70 mlx5_get_rsc+0x1a/0x50 [mlx5_core] mlx5_ib_eqe_pf_action+0x493/0x1be0 [mlx5_ib] process_one_work+0x90c/0x1820 worker_thread+0x87/0xbb0 kthread+0x320/0x3e0 ret_from_fork+0x24/0x30 irq event stamp: 103928 hardirqs last enabled at (103927): [] nk+0x1a/0x1c hardirqs last disabled at (103928): [] unk+0x1a/0x1c softirqs last enabled at (103924): [] tcp_sendmsg+0x31/0x40 softirqs last disabled at (103922): [] 80 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&(&table->lock)->rlock#2); lock(&(&table->lock)->rlock#2); *** DEADLOCK *** Fixes: 032080ab43ac ("IB/mlx5: Lock QP during page fault handling") Signed-off-by: Moni Shoua Reviewed-by: Leon Romanovsky Signed-off-by: Saeed Mahameed Signed-off-by: Sasha Levin --- drivers/net/ethernet/mellanox/mlx5/core/qp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/qp.c b/drivers/net/ethernet/mellanox/mlx5/core/qp.c index 5f091c6ea049..b92d5690287b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/qp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/qp.c @@ -44,14 +44,15 @@ static struct mlx5_core_rsc_common *mlx5_get_rsc(struct mlx5_core_dev *dev, { struct mlx5_qp_table *table = &dev->priv.qp_table; struct mlx5_core_rsc_common *common; + unsigned long flags; - spin_lock(&table->lock); + spin_lock_irqsave(&table->lock, flags); common = radix_tree_lookup(&table->tree, rsn); if (common) atomic_inc(&common->refcount); - spin_unlock(&table->lock); + spin_unlock_irqrestore(&table->lock, flags); if (!common) { mlx5_core_warn(dev, "Async event for bogus resource 0x%x\n", -- GitLab From f401472074c6900cb0a87aa91fc4d86b34df0374 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Nov 2018 09:51:56 +0100 Subject: [PATCH 0372/1055] iwlwifi: mvm: fix A-MPDU reference assignment [ Upstream commit 1f7698abedeeb3fef3cbcf78e16f925df675a179 ] The current code assigns the reference, and then goes to increment it if the toggle bit has changed. That way, we get Toggle 0 0 0 0 1 1 1 1 ID 1 1 1 1 1 2 2 2 Fix that by assigning the post-toggle ID to get Toggle 0 0 0 0 1 1 1 1 ID 1 1 1 1 2 2 2 2 Reported-by: Danny Alexander Signed-off-by: Johannes Berg Fixes: fbe4112791b8 ("iwlwifi: mvm: update mpdu metadata API") Signed-off-by: Luca Coelho Signed-off-by: Sasha Levin --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 7fb8bbaf2142..1a12e829e98b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -871,12 +871,12 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, bool toggle_bit = phy_info & IWL_RX_MPDU_PHY_AMPDU_TOGGLE; rx_status->flag |= RX_FLAG_AMPDU_DETAILS; - rx_status->ampdu_reference = mvm->ampdu_ref; /* toggle is switched whenever new aggregation starts */ if (toggle_bit != mvm->ampdu_toggle) { mvm->ampdu_ref++; mvm->ampdu_toggle = toggle_bit; } + rx_status->ampdu_reference = mvm->ampdu_ref; } rcu_read_lock(); -- GitLab From 35eb06fa70302bc971342646ee3a0012e6d2e401 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 30 Jan 2019 18:30:51 +0800 Subject: [PATCH 0373/1055] tty: ipwireless: Fix potential NULL pointer dereference [ Upstream commit 7dd50e205b3348dc7784efbdf85723551de64a25 ] There is a potential NULL pointer dereference in case alloc_ctrl_packet() fails and returns NULL. Fixes: 099dc4fb6265 ("ipwireless: driver for PC Card 3G/UMTS modem") Signed-off-by: YueHaibing Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/ipwireless/hardware.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c index a6b8240af6cd..960e9375a1a9 100644 --- a/drivers/tty/ipwireless/hardware.c +++ b/drivers/tty/ipwireless/hardware.c @@ -1516,6 +1516,8 @@ static void ipw_send_setup_packet(struct ipw_hardware *hw) sizeof(struct ipw_setup_get_version_query_packet), ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP, TL_SETUP_SIGNO_GET_VERSION_QRY); + if (!ver_packet) + return; ver_packet->header.length = sizeof(struct tl_setup_get_version_qry); /* -- GitLab From 1b97b03ace9e5f2d84dba9e8e347e76cfda40dbf Mon Sep 17 00:00:00 2001 From: Liu Jian Date: Wed, 23 Jan 2019 06:45:37 +0800 Subject: [PATCH 0374/1055] driver: uio: fix possible memory leak in __uio_register_device [ Upstream commit 1a392b3de7c5747506b38fc14b2e79977d3c7770 ] 'idev' is malloced in __uio_register_device() and leak free it before leaving from the uio_get_minor() error handing case, it will cause memory leak. Fixes: a93e7b331568 ("uio: Prevent device destruction while fds are open") Signed-off-by: Liu Jian Reviewed-by: Hamish Martin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/uio/uio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index fb5c9701b1fb..4e9b0ff79b13 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -939,8 +939,10 @@ int __uio_register_device(struct module *owner, atomic_set(&idev->event, 0); ret = uio_get_minor(idev); - if (ret) + if (ret) { + kfree(idev); return ret; + } idev->dev.devt = MKDEV(uio_major, idev->minor); idev->dev.class = &uio_class; -- GitLab From 548752cabfaaf3945f2da9d202e70015c2991e9a Mon Sep 17 00:00:00 2001 From: Liu Jian Date: Wed, 23 Jan 2019 06:45:38 +0800 Subject: [PATCH 0375/1055] driver: uio: fix possible use-after-free in __uio_register_device [ Upstream commit 221a1f4ac12d2ab46246c160b2e00d1b1160d5d9 ] In uio_dev_add_attributes() error handing case, idev is used after device_unregister(), in which 'idev' has been released, touch idev cause use-after-free. Fixes: a93e7b331568 ("uio: Prevent device destruction while fds are open") Signed-off-by: Liu Jian Reviewed-by: Hamish Martin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/uio/uio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 4e9b0ff79b13..7c18536a3742 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -944,6 +944,7 @@ int __uio_register_device(struct module *owner, return ret; } + device_initialize(&idev->dev); idev->dev.devt = MKDEV(uio_major, idev->minor); idev->dev.class = &uio_class; idev->dev.parent = parent; @@ -954,7 +955,7 @@ int __uio_register_device(struct module *owner, if (ret) goto err_device_create; - ret = device_register(&idev->dev); + ret = device_add(&idev->dev); if (ret) goto err_device_create; @@ -986,9 +987,10 @@ int __uio_register_device(struct module *owner, err_request_irq: uio_dev_del_attributes(idev); err_uio_dev_add_attributes: - device_unregister(&idev->dev); + device_del(&idev->dev); err_device_create: uio_free_minor(idev); + put_device(&idev->dev); return ret; } EXPORT_SYMBOL_GPL(__uio_register_device); -- GitLab From d7a7f04e10017bf95eea0cb294287b4ab26e541a Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Wed, 23 Jan 2019 11:24:18 +0000 Subject: [PATCH 0376/1055] crypto: crypto4xx - Fix wrong ppc4xx_trng_probe()/ppc4xx_trng_remove() arguments [ Upstream commit 6e88098ca43a3d80ae86908f7badba683c8a0d84 ] When building without CONFIG_HW_RANDOM_PPC4XX, I hit the following build failure: drivers/crypto/amcc/crypto4xx_core.c: In function 'crypto4xx_probe': drivers/crypto/amcc/crypto4xx_core.c:1407:20: error: passing argument 1 of 'ppc4xx_trng_probe' from incompatible pointer type [-Werror=incompatible-pointer-types] In file included from drivers/crypto/amcc/crypto4xx_core.c:50:0: drivers/crypto/amcc/crypto4xx_trng.h:28:20: note: expected 'struct crypto4xx_device *' but argument is of type 'struct crypto4xx_core_device *' drivers/crypto/amcc/crypto4xx_core.c: In function 'crypto4xx_remove': drivers/crypto/amcc/crypto4xx_core.c:1434:21: error: passing argument 1 of 'ppc4xx_trng_remove' from incompatible pointer type [-Werror=incompatible-pointer-types] In file included from drivers/crypto/amcc/crypto4xx_core.c:50:0: drivers/crypto/amcc/crypto4xx_trng.h:30:20: note: expected 'struct crypto4xx_device *' but argument is of type 'struct crypto4xx_core_device *' This patch fix the needed argument of ppc4xx_trng_probe()/ppc4xx_trng_remove() in that case. Fixes: 5343e674f32f ("crypto4xx: integrate ppc4xx-rng into crypto4xx") Signed-off-by: Corentin Labbe Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- drivers/crypto/amcc/crypto4xx_trng.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/amcc/crypto4xx_trng.h b/drivers/crypto/amcc/crypto4xx_trng.h index 931d22531f51..7bbda51b7337 100644 --- a/drivers/crypto/amcc/crypto4xx_trng.h +++ b/drivers/crypto/amcc/crypto4xx_trng.h @@ -26,9 +26,9 @@ void ppc4xx_trng_probe(struct crypto4xx_core_device *core_dev); void ppc4xx_trng_remove(struct crypto4xx_core_device *core_dev); #else static inline void ppc4xx_trng_probe( - struct crypto4xx_device *dev __maybe_unused) { } + struct crypto4xx_core_device *dev __maybe_unused) { } static inline void ppc4xx_trng_remove( - struct crypto4xx_device *dev __maybe_unused) { } + struct crypto4xx_core_device *dev __maybe_unused) { } #endif #endif -- GitLab From d7ee5bfb5541b2d8b652f1026c12a5a631d14b8e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 1 Feb 2019 01:47:53 +0100 Subject: [PATCH 0377/1055] driver core: Do not resume suppliers under device_links_write_lock() [ Upstream commit 5db25c9eb893df8f6b93c1d97b8006d768e1b6f5 ] It is incorrect to call pm_runtime_get_sync() under device_links_write_lock(), because it may end up trying to take device_links_read_lock() while resuming the target device and that will deadlock in the non-SRCU case, so avoid that by resuming the supplier device in device_link_add() before calling device_links_write_lock(). Fixes: 21d5c57b3726 ("PM / runtime: Use device links") Fixes: baa8809f6097 ("PM / runtime: Optimize the use of device links") Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/base/core.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 2b0a1054535c..93c2fc58013e 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -180,11 +180,20 @@ struct device_link *device_link_add(struct device *consumer, struct device *supplier, u32 flags) { struct device_link *link; + bool rpm_put_supplier = false; if (!consumer || !supplier || ((flags & DL_FLAG_STATELESS) && (flags & DL_FLAG_AUTOREMOVE))) return NULL; + if (flags & DL_FLAG_PM_RUNTIME && flags & DL_FLAG_RPM_ACTIVE) { + if (pm_runtime_get_sync(supplier) < 0) { + pm_runtime_put_noidle(supplier); + return NULL; + } + rpm_put_supplier = true; + } + device_links_write_lock(); device_pm_lock(); @@ -209,13 +218,8 @@ struct device_link *device_link_add(struct device *consumer, if (flags & DL_FLAG_PM_RUNTIME) { if (flags & DL_FLAG_RPM_ACTIVE) { - if (pm_runtime_get_sync(supplier) < 0) { - pm_runtime_put_noidle(supplier); - kfree(link); - link = NULL; - goto out; - } link->rpm_active = true; + rpm_put_supplier = false; } pm_runtime_new_link(consumer); /* @@ -286,6 +290,10 @@ struct device_link *device_link_add(struct device *consumer, out: device_pm_unlock(); device_links_write_unlock(); + + if (rpm_put_supplier) + pm_runtime_put(supplier); + return link; } EXPORT_SYMBOL_GPL(device_link_add); -- GitLab From 25b8cd12a15c73acf75dcb0483d3857cfbae4c48 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Sat, 26 Jan 2019 16:29:20 +0200 Subject: [PATCH 0378/1055] ARM: dts: lpc32xx: add required clocks property to keypad device node [ Upstream commit 3e88bc38b9f6fe4b69cecf81badd3c19fde97f97 ] NXP LPC32xx keypad controller requires a clock property to be defined. The change fixes the driver initialization problem: lpc32xx_keys 40050000.key: failed to get clock lpc32xx_keys: probe of 40050000.key failed with error -2 Fixes: 93898eb775e5 ("arm: dts: lpc32xx: add clock properties to device nodes") Signed-off-by: Vladimir Zapolskiy Signed-off-by: Sasha Levin --- arch/arm/boot/dts/lpc32xx.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi index d077bd2b9583..2ca881055ef0 100644 --- a/arch/arm/boot/dts/lpc32xx.dtsi +++ b/arch/arm/boot/dts/lpc32xx.dtsi @@ -462,6 +462,7 @@ key: key@40050000 { compatible = "nxp,lpc3220-key"; reg = <0x40050000 0x1000>; + clocks = <&clk LPC32XX_CLK_KEY>; interrupts = <54 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; -- GitLab From 53e4e15bb1539a2fa74333f01d7f3cd2a9778a18 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Sat, 26 Jan 2019 16:29:21 +0200 Subject: [PATCH 0379/1055] ARM: dts: lpc32xx: reparent keypad controller to SIC1 [ Upstream commit 489261c45f0ebbc1c2813f337bbdf858267f5033 ] After switching to a new interrupt controller scheme by separating SIC1 and SIC2 from MIC interrupt controller just one SoC keypad controller was not taken into account, fix it now: WARNING: CPU: 0 PID: 1 at kernel/irq/irqdomain.c:524 irq_domain_associate+0x50/0x1b0 error: hwirq 0x36 is too large for interrupt-controller@40008000 ... lpc32xx_keys 40050000.key: failed to get platform irq lpc32xx_keys: probe of 40050000.key failed with error -22 Fixes: 9b8ad3fb81ae ("ARM: dts: lpc32xx: reparent SIC1 and SIC2 interrupts from MIC") Signed-off-by: Vladimir Zapolskiy Signed-off-by: Sasha Levin --- arch/arm/boot/dts/lpc32xx.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi index 2ca881055ef0..9f9386c926d1 100644 --- a/arch/arm/boot/dts/lpc32xx.dtsi +++ b/arch/arm/boot/dts/lpc32xx.dtsi @@ -463,7 +463,8 @@ compatible = "nxp,lpc3220-key"; reg = <0x40050000 0x1000>; clocks = <&clk LPC32XX_CLK_KEY>; - interrupts = <54 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&sic1>; + interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; }; -- GitLab From e3064d2f21f4a684539384055956605e4dfdc97b Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Tue, 29 Jan 2019 21:20:39 +0200 Subject: [PATCH 0380/1055] ARM: dts: lpc32xx: fix ARM PrimeCell LCD controller variant [ Upstream commit 7a0790a4121cbcd111cc537cdc801c46ccb789ee ] ARM PrimeCell PL111 LCD controller is found on On NXP LPC3230 and LPC3250 SoCs variants, the original reference in compatible property to an older one ARM PrimeCell PL110 is invalid. Fixes: e04920d9efcb3 ("ARM: LPC32xx: DTS files for device tree conversion") Signed-off-by: Vladimir Zapolskiy Signed-off-by: Sasha Levin --- arch/arm/boot/dts/lpc32xx.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi index 9f9386c926d1..a08ebc950923 100644 --- a/arch/arm/boot/dts/lpc32xx.dtsi +++ b/arch/arm/boot/dts/lpc32xx.dtsi @@ -139,7 +139,7 @@ }; clcd: clcd@31040000 { - compatible = "arm,pl110", "arm,primecell"; + compatible = "arm,pl111", "arm,primecell"; reg = <0x31040000 0x1000>; interrupts = <14 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clk LPC32XX_CLK_LCD>; -- GitLab From f68e0cc797f7813608f934496c4db4276d1073e8 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Tue, 29 Jan 2019 21:20:40 +0200 Subject: [PATCH 0381/1055] ARM: dts: lpc32xx: fix ARM PrimeCell LCD controller clocks property [ Upstream commit 30fc01bae3cda747e7d9c352b1aa51ca113c8a9d ] The originally added ARM PrimeCell PL111 clocks property misses the required "clcdclk" clock, which is the same as a clock to enable the LCD controller on NXP LPC3230 and NXP LPC3250 SoCs. Fixes: 93898eb775e5 ("arm: dts: lpc32xx: add clock properties to device nodes") Signed-off-by: Vladimir Zapolskiy Signed-off-by: Sasha Levin --- arch/arm/boot/dts/lpc32xx.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi index a08ebc950923..c5b119ddb70b 100644 --- a/arch/arm/boot/dts/lpc32xx.dtsi +++ b/arch/arm/boot/dts/lpc32xx.dtsi @@ -142,8 +142,8 @@ compatible = "arm,pl111", "arm,primecell"; reg = <0x31040000 0x1000>; interrupts = <14 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&clk LPC32XX_CLK_LCD>; - clock-names = "apb_pclk"; + clocks = <&clk LPC32XX_CLK_LCD>, <&clk LPC32XX_CLK_LCD>; + clock-names = "clcdclk", "apb_pclk"; status = "disabled"; }; -- GitLab From 505672b687af62983b8bd9d1c5c243cd3e518fad Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Tue, 29 Jan 2019 21:20:41 +0200 Subject: [PATCH 0382/1055] ARM: dts: lpc32xx: phy3250: fix SD card regulator voltage [ Upstream commit dc141b99fc36cf910a1d8d5ee30f43f2442fd1bd ] The fixed voltage regulator on Phytec phyCORE-LPC3250 board, which supplies SD/MMC card's power, has a constant output voltage level of either 3.15V or 3.3V, the actual value depends on JP4 position, the power rail is referenced as VCC_SDIO in the board hardware manual. Fixes: d06670e96267 ("arm: dts: phy3250: add SD fixed regulator") Signed-off-by: Vladimir Zapolskiy Signed-off-by: Sasha Levin --- arch/arm/boot/dts/lpc3250-phy3250.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/lpc3250-phy3250.dts b/arch/arm/boot/dts/lpc3250-phy3250.dts index b7bd3a110a8d..dd0bdf765599 100644 --- a/arch/arm/boot/dts/lpc3250-phy3250.dts +++ b/arch/arm/boot/dts/lpc3250-phy3250.dts @@ -49,8 +49,8 @@ sd_reg: regulator@2 { compatible = "regulator-fixed"; regulator-name = "sd_reg"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; gpio = <&gpio 5 5 0>; enable-active-high; }; -- GitLab From 5cd9f229dd3e4980580406f5a47230ec5ee836d7 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 12 Dec 2018 09:45:11 +0200 Subject: [PATCH 0383/1055] iwlwifi: mvm: fix RSS config command [ Upstream commit 608dce95db10b8ee1a26dbce3f60204bb69812a5 ] The hash mask is a bitmap, so we should use BIT() on the enum values. Signed-off-by: Sara Sharon Fixes: 43413a975d06 ("iwlwifi: mvm: support rss queues configuration command") Signed-off-by: Luca Coelho Signed-off-by: Sasha Levin --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 78228f870f8f..754dcc1c1f40 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -107,12 +107,12 @@ static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm) int i; struct iwl_rss_config_cmd cmd = { .flags = cpu_to_le32(IWL_RSS_ENABLE), - .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP | - IWL_RSS_HASH_TYPE_IPV4_UDP | - IWL_RSS_HASH_TYPE_IPV4_PAYLOAD | - IWL_RSS_HASH_TYPE_IPV6_TCP | - IWL_RSS_HASH_TYPE_IPV6_UDP | - IWL_RSS_HASH_TYPE_IPV6_PAYLOAD, + .hash_mask = BIT(IWL_RSS_HASH_TYPE_IPV4_TCP) | + BIT(IWL_RSS_HASH_TYPE_IPV4_UDP) | + BIT(IWL_RSS_HASH_TYPE_IPV4_PAYLOAD) | + BIT(IWL_RSS_HASH_TYPE_IPV6_TCP) | + BIT(IWL_RSS_HASH_TYPE_IPV6_UDP) | + BIT(IWL_RSS_HASH_TYPE_IPV6_PAYLOAD), }; if (mvm->trans->num_rx_queues == 1) -- GitLab From 526eb7a254e9ffabfe567438dc091ad5ebb5c7ee Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 2 Feb 2019 22:34:49 +0000 Subject: [PATCH 0384/1055] staging: most: cdev: add missing check for cdev_add failure [ Upstream commit 5ae890780e1b4d08f2c0c5d4ea96fc3928fc0ee9 ] Currently the call to cdev_add is missing a check for failure. Fix this by checking for failure and exiting via a new error path that ensures the allocated comp_channel struct is kfree'd. Detected by CoverityScan, CID#1462359 ("Unchecked return value") Fixes: 9bc79bbcd0c5 ("Staging: most: add MOST driver's aim-cdev module") Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/staging/most/aim-cdev/cdev.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/staging/most/aim-cdev/cdev.c b/drivers/staging/most/aim-cdev/cdev.c index 1e5cbc893496..d000b6ff8a7d 100644 --- a/drivers/staging/most/aim-cdev/cdev.c +++ b/drivers/staging/most/aim-cdev/cdev.c @@ -455,7 +455,9 @@ static int aim_probe(struct most_interface *iface, int channel_id, c->devno = MKDEV(major, current_minor); cdev_init(&c->cdev, &channel_fops); c->cdev.owner = THIS_MODULE; - cdev_add(&c->cdev, c->devno, 1); + retval = cdev_add(&c->cdev, c->devno, 1); + if (retval < 0) + goto err_free_c; c->iface = iface; c->cfg = cfg; c->channel_id = channel_id; @@ -491,6 +493,7 @@ static int aim_probe(struct most_interface *iface, int channel_id, list_del(&c->list); error_alloc_kfifo: cdev_del(&c->cdev); +err_free_c: kfree(c); error_alloc_channel: ida_simple_remove(&minor_id, current_minor); -- GitLab From 7d7e9d2378899ee8e7abf8b74561d18958739042 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 5 Feb 2019 18:04:49 +0000 Subject: [PATCH 0385/1055] rtc: ds1672: fix unintended sign extension [ Upstream commit f0c04c276739ed8acbb41b4868e942a55b128dca ] Shifting a u8 by 24 will cause the value to be promoted to an integer. If the top bit of the u8 is set then the following conversion to an unsigned long will sign extend the value causing the upper 32 bits to be set in the result. Fix this by casting the u8 value to an unsigned long before the shift. Detected by CoverityScan, CID#138801 ("Unintended sign extension") Fixes: edf1aaa31fc5 ("[PATCH] RTC subsystem: DS1672 driver") Signed-off-by: Colin Ian King Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/rtc-ds1672.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 9caaccccaa57..b1ebca099b0d 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -58,7 +58,8 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) "%s: raw read data - counters=%02x,%02x,%02x,%02x\n", __func__, buf[0], buf[1], buf[2], buf[3]); - time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + time = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; rtc_time_to_tm(time, tm); -- GitLab From 032c10fb504cf15575a69e2f7e673c72c720ade7 Mon Sep 17 00:00:00 2001 From: Michael Kao Date: Fri, 1 Feb 2019 15:38:07 +0800 Subject: [PATCH 0386/1055] thermal: mediatek: fix register index error [ Upstream commit eb9aecd90d1a39601e91cd08b90d5fee51d321a6 ] The index of msr and adcpnp should match the sensor which belongs to the selected bank in the for loop. Fixes: b7cf0053738c ("thermal: Add Mediatek thermal driver for mt2701.") Signed-off-by: Michael Kao Signed-off-by: Eduardo Valentin Signed-off-by: Sasha Levin --- drivers/thermal/mtk_thermal.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c index 1e61c09153c9..76b92083744c 100644 --- a/drivers/thermal/mtk_thermal.c +++ b/drivers/thermal/mtk_thermal.c @@ -407,7 +407,8 @@ static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank) u32 raw; for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) { - raw = readl(mt->thermal_base + conf->msr[i]); + raw = readl(mt->thermal_base + + conf->msr[conf->bank_data[bank->id].sensors[i]]); temp = raw_to_mcelsius(mt, conf->bank_data[bank->id].sensors[i], @@ -544,7 +545,8 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, for (i = 0; i < conf->bank_data[num].num_sensors; i++) writel(conf->sensor_mux_values[conf->bank_data[num].sensors[i]], - mt->thermal_base + conf->adcpnp[i]); + mt->thermal_base + + conf->adcpnp[conf->bank_data[num].sensors[i]]); writel((1 << conf->bank_data[num].num_sensors) - 1, mt->thermal_base + TEMP_MONCTL0); -- GitLab From 391fd358568db5b98464b26c8fca0b2c03f6fef4 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Wed, 6 Feb 2019 21:45:29 -0800 Subject: [PATCH 0387/1055] net: phy: fixed_phy: Fix fixed_phy not checking GPIO [ Upstream commit 8f289805616e81f7c1690931aa8a586c76f4fa88 ] Fix fixed_phy not checking GPIO if no link_update callback is registered. In the original version all users registered a link_update callback so the issue was masked. Fixes: a5597008dbc2 ("phy: fixed_phy: Add gpio to determine link up/down.") Reviewed-by: Andrew Lunn Signed-off-by: Moritz Fischer Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/phy/fixed_phy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index eb5167210681..3ab2eb677a59 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -67,11 +67,11 @@ static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num) do { s = read_seqcount_begin(&fp->seqcount); /* Issue callback if user registered it. */ - if (fp->link_update) { + if (fp->link_update) fp->link_update(fp->phydev->attached_dev, &fp->status); - fixed_phy_update(fp); - } + /* Check the GPIO for change in status */ + fixed_phy_update(fp); state = fp->status; } while (read_seqcount_retry(&fp->seqcount, s)); -- GitLab From 0b9eaf82c2a711fcd2c6d011bac59bbc7d26be83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 25 Jan 2019 15:35:58 +0100 Subject: [PATCH 0388/1055] rtc: ds1307: rx8130: Fix alarm handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 3f929cad943380370b6db31fcb7a38d898d91089 ] When the EXTENSION.WADA bit is set, register 0x19 contains a bitmap of week days, not a day of month. As Linux only handles a single alarm without repetition using day of month is more flexible, so clear this bit. (Otherwise a value depending on time.tm_wday would have to be written to register 0x19.) Also optimize setting the AIE bit to use a single register write instead of a bulk write of three registers. Fixes: ee0981be7704 ("rtc: ds1307: Add support for Epson RX8130CE") Signed-off-by: Uwe Kleine-König Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/rtc-ds1307.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index e7d9215c9201..8d45d93b1db6 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -733,8 +733,8 @@ static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t) if (ret < 0) return ret; - ctl[0] &= ~RX8130_REG_EXTENSION_WADA; - ctl[1] |= RX8130_REG_FLAG_AF; + ctl[0] &= RX8130_REG_EXTENSION_WADA; + ctl[1] &= ~RX8130_REG_FLAG_AF; ctl[2] &= ~RX8130_REG_CONTROL0_AIE; ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, @@ -757,8 +757,7 @@ static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t) ctl[2] |= RX8130_REG_CONTROL0_AIE; - return regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, - sizeof(ctl)); + return regmap_write(ds1307->regmap, RX8130_REG_CONTROL0, ctl[2]); } static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled) -- GitLab From 3726373c3f243b1c41d35a2cec03c3149679bc4e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 6 Feb 2019 09:50:53 +0000 Subject: [PATCH 0389/1055] rtc: 88pm860x: fix unintended sign extension [ Upstream commit dc9e47160626cdb58d5c39a4f43dcfdb27a5c004 ] Shifting a u8 by 24 will cause the value to be promoted to an integer. If the top bit of the u8 is set then the following conversion to an unsigned long will sign extend the value causing the upper 32 bits to be set in the result. Fix this by casting the u8 value to an unsigned long before the shift. Detected by CoverityScan, CID#144925-144928 ("Unintended sign extension") Fixes: 008b30408c40 ("mfd: Add rtc support to 88pm860x") Signed-off-by: Colin Ian King Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/rtc-88pm860x.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 166faae3a59c..7d3e5168fcef 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -115,11 +115,13 @@ static int pm860x_rtc_read_time(struct device *dev, struct rtc_time *tm) pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); - base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; + base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) | + (buf[5] << 8) | buf[7]; /* load 32-bit read-only counter */ pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; ticks = base + data; dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); @@ -145,7 +147,8 @@ static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm) /* load 32-bit read-only counter */ pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; base = ticks - data; dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); @@ -170,10 +173,12 @@ static int pm860x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); - base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; + base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) | + (buf[5] << 8) | buf[7]; pm860x_bulk_read(info->i2c, PM8607_RTC_EXPIRE1, 4, buf); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; ticks = base + data; dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); @@ -198,11 +203,13 @@ static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); - base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; + base = ((unsigned long)buf[1] << 24) | (buf[3] << 16) | + (buf[5] << 8) | buf[7]; /* load 32-bit read-only counter */ pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; ticks = base + data; dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); -- GitLab From 6518484b920e1a409184c29d9db5f8e39be4e861 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 6 Feb 2019 10:08:11 +0000 Subject: [PATCH 0390/1055] rtc: 88pm80x: fix unintended sign extension [ Upstream commit fb0b322537a831b5b0cb948c56f8f958ce493d3a ] Shifting a u8 by 24 will cause the value to be promoted to an integer. If the top bit of the u8 is set then the following conversion to an unsigned long will sign extend the value causing the upper 32 bits to be set in the result. Fix this by casting the u8 value to an unsigned long before the shift. Detected by CoverityScan, CID#714646-714649 ("Unintended sign extension") Fixes: 2985c29c1964 ("rtc: Add rtc support to 88PM80X PMIC") Signed-off-by: Colin Ian King Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/rtc-88pm80x.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c index 466bf7f9a285..7da2a1fb50f8 100644 --- a/drivers/rtc/rtc-88pm80x.c +++ b/drivers/rtc/rtc-88pm80x.c @@ -116,12 +116,14 @@ static int pm80x_rtc_read_time(struct device *dev, struct rtc_time *tm) unsigned char buf[4]; unsigned long ticks, base, data; regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4); - base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]); /* load 32-bit read-only counter */ regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; ticks = base + data; dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); @@ -144,7 +146,8 @@ static int pm80x_rtc_set_time(struct device *dev, struct rtc_time *tm) /* load 32-bit read-only counter */ regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; base = ticks - data; dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); @@ -165,11 +168,13 @@ static int pm80x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) int ret; regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4); - base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]); regmap_raw_read(info->map, PM800_RTC_EXPIRE1_1, buf, 4); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; ticks = base + data; dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); @@ -192,12 +197,14 @@ static int pm80x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_ALARM1_EN, 0); regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4); - base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]); /* load 32-bit read-only counter */ regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4); - data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | + (buf[1] << 8) | buf[0]; ticks = base + data; dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", base, data, ticks); -- GitLab From 814b711f62dc28f367f7d636501b2aa725961cd1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 6 Feb 2019 10:31:02 +0000 Subject: [PATCH 0391/1055] rtc: pm8xxx: fix unintended sign extension [ Upstream commit e42280886018c6f77f0a90190f7cba344b0df3e0 ] Shifting a u8 by 24 will cause the value to be promoted to an integer. If the top bit of the u8 is set then the following conversion to an unsigned long will sign extend the value causing the upper 32 bits to be set in the result. Fix this by casting the u8 value to an unsigned long before the shift. Detected by CoverityScan, CID#1309693 ("Unintended sign extension") Fixes: 9a9a54ad7aa2 ("drivers/rtc: add support for Qualcomm PMIC8xxx RTC") Signed-off-by: Colin Ian King Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/rtc-pm8xxx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index fac835530671..a1b4b0ed1f19 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -186,7 +186,8 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) } } - secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); + secs = value[0] | (value[1] << 8) | (value[2] << 16) | + ((unsigned long)value[3] << 24); rtc_time_to_tm(secs, tm); @@ -267,7 +268,8 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) return rc; } - secs = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); + secs = value[0] | (value[1] << 8) | (value[2] << 16) | + ((unsigned long)value[3] << 24); rtc_time_to_tm(secs, &alarm->time); -- GitLab From 5bcb908399dc48093396dba7fe5f7a93e13cbad8 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 8 Feb 2019 19:24:45 +0100 Subject: [PATCH 0392/1055] fbdev: chipsfb: remove set but not used variable 'size' [ Upstream commit 8e71fa5e4d86bedfd26df85381d65d6b4c860020 ] Fixes gcc '-Wunused-but-set-variable' warning: drivers/video/fbdev/chipsfb.c: In function 'chipsfb_pci_init': drivers/video/fbdev/chipsfb.c:352:22: warning: variable 'size' set but not used [-Wunused-but-set-variable] Fixes: 8c8709334cec ("[PATCH] ppc32: Remove CONFIG_PMAC_PBOOK"). Signed-off-by: YueHaibing Acked-by: Michael Ellerman Cc: Daniel Vetter Cc: Christophe Leroy [b.zolnierkie: minor commit summary and description fixups] Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Sasha Levin --- drivers/video/fbdev/chipsfb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/video/fbdev/chipsfb.c b/drivers/video/fbdev/chipsfb.c index f103665cad43..f9b366d17587 100644 --- a/drivers/video/fbdev/chipsfb.c +++ b/drivers/video/fbdev/chipsfb.c @@ -350,7 +350,7 @@ static void init_chips(struct fb_info *p, unsigned long addr) static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) { struct fb_info *p; - unsigned long addr, size; + unsigned long addr; unsigned short cmd; int rc = -ENODEV; @@ -362,7 +362,6 @@ static int chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) if ((dp->resource[0].flags & IORESOURCE_MEM) == 0) goto err_disable; addr = pci_resource_start(dp, 0); - size = pci_resource_len(dp, 0); if (addr == 0) goto err_disable; -- GitLab From d53fea06ecdcf579c2ef4f285734e4964d72a3f2 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Fri, 1 Feb 2019 12:44:41 -0800 Subject: [PATCH 0393/1055] iw_cxgb4: use tos when importing the endpoint [ Upstream commit cb3ba0bde881f0cb7e3945d2a266901e2bd18c92 ] import_ep() is passed the correct tos, but doesn't use it correctly. Fixes: ac8e4c69a021 ("cxgb4/iw_cxgb4: TOS support") Signed-off-by: Steve Wise Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/hw/cxgb4/cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 3668cc71b47e..942403e42dd0 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -2056,7 +2056,7 @@ static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip, } else { pdev = get_real_dev(n->dev); ep->l2t = cxgb4_l2t_get(cdev->rdev.lldi.l2t, - n, pdev, 0); + n, pdev, rt_tos2priority(tos)); if (!ep->l2t) goto out; ep->mtu = dst_mtu(dst); -- GitLab From d47846800bcc9883f2f0f954f16dcd1ed8dacd75 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Fri, 1 Feb 2019 12:44:53 -0800 Subject: [PATCH 0394/1055] iw_cxgb4: use tos when finding ipv6 routes [ Upstream commit c8a7eb554a83214c3d8ee5cb322da8c72810d2dc ] When IPv6 support was added, the correct tos was not passed to cxgb_find_route6(). This potentially results in the wrong route entry. Fixes: 830662f6f032 ("RDMA/cxgb4: Add support for active and passive open connection with IPv6 address") Signed-off-by: Steve Wise Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/hw/cxgb4/cm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 942403e42dd0..7eb1cc1b1aa0 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -2147,7 +2147,8 @@ static int c4iw_reconnect(struct c4iw_ep *ep) laddr6->sin6_addr.s6_addr, raddr6->sin6_addr.s6_addr, laddr6->sin6_port, - raddr6->sin6_port, 0, + raddr6->sin6_port, + ep->com.cm_id->tos, raddr6->sin6_scope_id); iptype = 6; ra = (__u8 *)&raddr6->sin6_addr; @@ -3298,7 +3299,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) laddr6->sin6_addr.s6_addr, raddr6->sin6_addr.s6_addr, laddr6->sin6_port, - raddr6->sin6_port, 0, + raddr6->sin6_port, cm_id->tos, raddr6->sin6_scope_id); } if (!ep->dst) { -- GitLab From a580884bdb09f906d4eb7be5c2387b6d803dce95 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 5 Feb 2019 12:08:19 +0300 Subject: [PATCH 0395/1055] drm/etnaviv: potential NULL dereference [ Upstream commit 9e05352340d3a3e68c144136db9810b26ebb88c3 ] The etnaviv_gem_prime_get_sg_table() is supposed to return error pointers. Otherwise it can lead to a NULL dereference when it's called from drm_gem_map_dma_buf(). Fixes: 5f4a4a73f437 ("drm/etnaviv: fix gem_prime_get_sg_table to return new SG table") Signed-off-by: Dan Carpenter Reviewed-by: Christian Gmeiner Signed-off-by: Lucas Stach Signed-off-by: Sasha Levin --- drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c index ae884723e9b1..880b95511b98 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_prime.c @@ -26,7 +26,7 @@ struct sg_table *etnaviv_gem_prime_get_sg_table(struct drm_gem_object *obj) int npages = obj->size >> PAGE_SHIFT; if (WARN_ON(!etnaviv_obj->pages)) /* should have already pinned! */ - return NULL; + return ERR_PTR(-EINVAL); return drm_prime_pages_to_sg(etnaviv_obj->pages, npages); } -- GitLab From 27aa08b95d655306cc88647412595f8a4e9f86a8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 24 Jan 2019 13:04:52 +0100 Subject: [PATCH 0396/1055] pinctrl: sh-pfc: emev2: Add missing pinmux functions [ Upstream commit 1ecd8c9cb899ae277e6986ae134635cb1a50f5de ] The err_rst_reqb, ext_clki, lowpwr, and ref_clko pin groups are present, but no pinmux functions refer to them, hence they can not be selected. Fixes: 1e7d5d849cf4f0c5 ("sh-pfc: Add emev2 pinmux support") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-emev2.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/pinctrl/sh-pfc/pfc-emev2.c b/drivers/pinctrl/sh-pfc/pfc-emev2.c index 1cbbe04d7df6..eafd8edbcbe9 100644 --- a/drivers/pinctrl/sh-pfc/pfc-emev2.c +++ b/drivers/pinctrl/sh-pfc/pfc-emev2.c @@ -1263,6 +1263,14 @@ static const char * const dtv_groups[] = { "dtv_b", }; +static const char * const err_rst_reqb_groups[] = { + "err_rst_reqb", +}; + +static const char * const ext_clki_groups[] = { + "ext_clki", +}; + static const char * const iic0_groups[] = { "iic0", }; @@ -1285,6 +1293,10 @@ static const char * const lcd_groups[] = { "yuv3", }; +static const char * const lowpwr_groups[] = { + "lowpwr", +}; + static const char * const ntsc_groups[] = { "ntsc_clk", "ntsc_data", @@ -1298,6 +1310,10 @@ static const char * const pwm1_groups[] = { "pwm1", }; +static const char * const ref_clko_groups[] = { + "ref_clko", +}; + static const char * const sd_groups[] = { "sd_cki", }; @@ -1391,13 +1407,17 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(cam), SH_PFC_FUNCTION(cf), SH_PFC_FUNCTION(dtv), + SH_PFC_FUNCTION(err_rst_reqb), + SH_PFC_FUNCTION(ext_clki), SH_PFC_FUNCTION(iic0), SH_PFC_FUNCTION(iic1), SH_PFC_FUNCTION(jtag), SH_PFC_FUNCTION(lcd), + SH_PFC_FUNCTION(lowpwr), SH_PFC_FUNCTION(ntsc), SH_PFC_FUNCTION(pwm0), SH_PFC_FUNCTION(pwm1), + SH_PFC_FUNCTION(ref_clko), SH_PFC_FUNCTION(sd), SH_PFC_FUNCTION(sdi0), SH_PFC_FUNCTION(sdi1), -- GitLab From 8ca523cc81fbc0775efda6fe25456af78770d6af Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 23 Jan 2019 17:07:43 +0100 Subject: [PATCH 0397/1055] pinctrl: sh-pfc: r8a7791: Fix scifb2_data_c pin group [ Upstream commit a4b0350047f1b10207e25e72d7cd3f7826e93769 ] The entry for "scifb2_data_c" in the SCIFB2 pin group array contains a typo, thus the group cannot be selected. Fixes: 5088451962389924 ("pinctrl: sh-pfc: r8a7791 PFC support") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-r8a7791.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index d34982ea66bf..e4774b220040 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -5209,7 +5209,7 @@ static const char * const scifb2_groups[] = { "scifb2_data_b", "scifb2_clk_b", "scifb2_ctrl_b", - "scifb0_data_c", + "scifb2_data_c", "scifb2_clk_c", "scifb2_data_d", }; -- GitLab From b95aa104952712b8db2263e9da99e59775cbd104 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 23 Jan 2019 17:14:07 +0100 Subject: [PATCH 0398/1055] pinctrl: sh-pfc: r8a7792: Fix vin1_data18_b pin group [ Upstream commit b9fd50488b4939ce5b3a026d29e752e17c2d1800 ] The vin1_data18_b pin group itself is present, but it is not listed in the VIN1 pin group array, and thus cannot be selected. Fixes: 7dd74bb1f058786e ("pinctrl: sh-pfc: r8a7792: Add VIN pin groups") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-r8a7792.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7792.c b/drivers/pinctrl/sh-pfc/pfc-r8a7792.c index cc3597f66605..46c41ca6ea38 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7792.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7792.c @@ -1916,6 +1916,7 @@ static const char * const vin1_groups[] = { "vin1_data8", "vin1_data24_b", "vin1_data20_b", + "vin1_data18_b", "vin1_data16_b", "vin1_sync", "vin1_field", -- GitLab From 36f3abf8c0fccd453e45e9ab6638cbaa9ad48586 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 23 Jan 2019 16:51:21 +0100 Subject: [PATCH 0399/1055] pinctrl: sh-pfc: sh73a0: Fix fsic_spdif pin groups [ Upstream commit 0e6e448bdcf896d001a289a6112a704542d51516 ] There are two pin groups for the FSIC SPDIF signal, but the FSIC pin group array lists only one, and it refers to a nonexistent group. Fixes: 2ecd4154c906b7d6 ("sh-pfc: sh73a0: Add FSI pin groups and functions") Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Sasha Levin --- drivers/pinctrl/sh-pfc/pfc-sh73a0.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c index f8fbedb46585..6dca760f9f28 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c @@ -3367,7 +3367,8 @@ static const char * const fsic_groups[] = { "fsic_sclk_out", "fsic_data_in", "fsic_data_out", - "fsic_spdif", + "fsic_spdif_0", + "fsic_spdif_1", }; static const char * const fsid_groups[] = { -- GitLab From 7020a36d86bc76f49fffaf3cdf668b4a781a7b4f Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Mon, 11 Feb 2019 17:04:00 +0800 Subject: [PATCH 0400/1055] PCI: endpoint: functions: Use memcpy_fromio()/memcpy_toio() [ Upstream commit 726dabfde6aa35a4f1508e235ae37edbbf9fbc65 ] Functions copying from/to IO addresses should use the memcpy_fromio()/memcpy_toio() API rather than plain memcpy(). Fix the issue detected through the sparse tool. Fixes: 349e7a85b25f ("PCI: endpoint: functions: Add an EP function to test PCI") Suggested-by: Kishon Vijay Abraham I Signed-off-by: Wen Yang [lorenzo.pieralisi@arm.com: updated log] Signed-off-by: Lorenzo Pieralisi Acked-by: Kishon Vijay Abraham I CC: Lorenzo Pieralisi CC: Bjorn Helgaas CC: Gustavo Pimentel CC: Niklas Cassel CC: Greg Kroah-Hartman CC: Cyrille Pitchen CC: linux-pci@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: Sasha Levin --- drivers/pci/endpoint/functions/pci-epf-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c index f9308c2f22e6..c2541a772abc 100644 --- a/drivers/pci/endpoint/functions/pci-epf-test.c +++ b/drivers/pci/endpoint/functions/pci-epf-test.c @@ -177,7 +177,7 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test) goto err_map_addr; } - memcpy(buf, src_addr, reg->size); + memcpy_fromio(buf, src_addr, reg->size); crc32 = crc32_le(~0, buf, reg->size); if (crc32 != reg->checksum) @@ -231,7 +231,7 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test) get_random_bytes(buf, reg->size); reg->checksum = crc32_le(~0, buf, reg->size); - memcpy(dst_addr, buf, reg->size); + memcpy_toio(dst_addr, buf, reg->size); /* * wait 1ms inorder for the write to complete. Without this delay L3 -- GitLab From 30cf71254f9f661906f5c3eac379723899a5633e Mon Sep 17 00:00:00 2001 From: Sven Van Asbroeck Date: Mon, 11 Feb 2019 10:04:26 -0500 Subject: [PATCH 0401/1055] usb: phy: twl6030-usb: fix possible use-after-free on remove [ Upstream commit 5895d311d28f2605e2f71c1a3e043ed38f3ac9d2 ] In remove(), use cancel_delayed_work_sync() to cancel the delayed work. Otherwise there's a chance that this work will continue to run until after the device has been removed. This issue was detected with the help of Coccinelle. Cc: Tony Lindgren Cc: Bin Liu Fixes: b6a619a883c3 ("usb: phy: Check initial state for twl6030") Signed-off-by: Sven Van Asbroeck Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin --- drivers/usb/phy/phy-twl6030-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index b5dc077ed7d3..8e14fa221191 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -413,7 +413,7 @@ static int twl6030_usb_remove(struct platform_device *pdev) { struct twl6030_usb *twl = platform_get_drvdata(pdev); - cancel_delayed_work(&twl->get_status_work); + cancel_delayed_work_sync(&twl->get_status_work); twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, REG_INT_MSK_LINE_C); twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, -- GitLab From fa8552dae83acba4c9442fadbddab1d278168531 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 15 Feb 2019 19:13:08 +0800 Subject: [PATCH 0402/1055] block: don't use bio->bi_vcnt to figure out segment number [ Upstream commit 1a67356e9a4829da2935dd338630a550c59c8489 ] It is wrong to use bio->bi_vcnt to figure out how many segments there are in the bio even though CLONED flag isn't set on this bio, because this bio may be splitted or advanced. So always use bio_segments() in blk_recount_segments(), and it shouldn't cause any performance loss now because the physical segment number is figured out in blk_queue_split() and BIO_SEG_VALID is set meantime since bdced438acd83ad83a6c ("block: setup bi_phys_segments after splitting"). Reviewed-by: Omar Sandoval Reviewed-by: Christoph Hellwig Fixes: 76d8137a3113 ("blk-merge: recaculate segment if it isn't less than max segments") Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- block/blk-merge.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/block/blk-merge.c b/block/blk-merge.c index f61b50a01bc7..415b5dafd9e6 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -299,13 +299,7 @@ void blk_recalc_rq_segments(struct request *rq) void blk_recount_segments(struct request_queue *q, struct bio *bio) { - unsigned short seg_cnt; - - /* estimate segment number by bi_vcnt for non-cloned bio */ - if (bio_flagged(bio, BIO_CLONED)) - seg_cnt = bio_segments(bio); - else - seg_cnt = bio->bi_vcnt; + unsigned short seg_cnt = bio_segments(bio); if (test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags) && (seg_cnt < queue_max_segments(q))) -- GitLab From b0515d58763c039d326172e1aeed5c6a96a52b4c Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 14 Feb 2019 16:20:37 +0000 Subject: [PATCH 0403/1055] keys: Timestamp new keys [ Upstream commit 7c1857bdbdf1e4c541e45eab477ee23ed4333ea4 ] Set the timestamp on new keys rather than leaving it unset. Fixes: 31d5a79d7f3d ("KEYS: Do LRU discard in full keyrings") Signed-off-by: David Howells Signed-off-by: James Morris Signed-off-by: Sasha Levin --- security/keys/key.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/keys/key.c b/security/keys/key.c index 87172f99f73e..17244f5f54c6 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -297,6 +297,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, key->gid = gid; key->perm = perm; key->restrict_link = restrict_link; + key->last_used_at = ktime_get_real_seconds(); if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) key->flags |= 1 << KEY_FLAG_IN_QUOTA; -- GitLab From 6de29266dd3971d38956ee4d3b1fefee6cb4cbe5 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Fri, 15 Feb 2019 17:16:06 +0100 Subject: [PATCH 0404/1055] vfio_pci: Enable memory accesses before calling pci_map_rom [ Upstream commit 0cfd027be1d6def4a462cdc180c055143af24069 ] pci_map_rom/pci_get_rom_size() performs memory access in the ROM. In case the Memory Space accesses were disabled, readw() is likely to trigger a synchronous external abort on some platforms. In case memory accesses were disabled, re-enable them before the call and disable them back again just after. Fixes: 89e1f7d4c66d ("vfio: Add PCI device driver") Signed-off-by: Eric Auger Suggested-by: Alex Williamson Signed-off-by: Alex Williamson Signed-off-by: Sasha Levin --- drivers/vfio/pci/vfio_pci.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 9bd3e7911af2..550ab7707b57 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -717,6 +717,7 @@ static long vfio_pci_ioctl(void *device_data, { void __iomem *io; size_t size; + u16 orig_cmd; info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); info.flags = 0; @@ -732,15 +733,23 @@ static long vfio_pci_ioctl(void *device_data, break; } - /* Is it really there? */ + /* + * Is it really there? Enable memory decode for + * implicit access in pci_map_rom(). + */ + pci_read_config_word(pdev, PCI_COMMAND, &orig_cmd); + pci_write_config_word(pdev, PCI_COMMAND, + orig_cmd | PCI_COMMAND_MEMORY); + io = pci_map_rom(pdev, &size); - if (!io || !size) { + if (io) { + info.flags = VFIO_REGION_INFO_FLAG_READ; + pci_unmap_rom(pdev, io); + } else { info.size = 0; - break; } - pci_unmap_rom(pdev, io); - info.flags = VFIO_REGION_INFO_FLAG_READ; + pci_write_config_word(pdev, PCI_COMMAND, orig_cmd); break; } case VFIO_PCI_VGA_REGION_INDEX: -- GitLab From be889c947784c83f8eb69156c23cc36067fb8226 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 18 Feb 2019 19:54:40 +0000 Subject: [PATCH 0405/1055] hwmon: (pmbus/tps53679) Fix driver info initialization in probe routine [ Upstream commit ff066653aeed8ee2d4dadb1e35774dd91ecbb19f ] Fix tps53679_probe() by using dynamically allocated "pmbus_driver_info" structure instead of static. Usage of static structures causes overwritten of the field "vrm_version", in case the system is equipped with several tps53679 devices with the different "vrm_version". In such case the last probed device overwrites this field for all others. Fixes: 610526527a13 ("hwmon: (pmbus) Add support for Texas Instruments tps53679 device") Signed-off-by: Vadim Pasternak Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/pmbus/tps53679.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index 85b515cd9df0..2bc352c5357f 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -80,7 +80,14 @@ static struct pmbus_driver_info tps53679_info = { static int tps53679_probe(struct i2c_client *client, const struct i2c_device_id *id) { - return pmbus_do_probe(client, id, &tps53679_info); + struct pmbus_driver_info *info; + + info = devm_kmemdup(&client->dev, &tps53679_info, sizeof(*info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + return pmbus_do_probe(client, id, info); } static const struct i2c_device_id tps53679_id[] = { -- GitLab From 3af53fe7cffc149f38f93ad8da77b99c0425ef06 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Tue, 12 Feb 2019 15:37:45 +1100 Subject: [PATCH 0406/1055] KVM: PPC: Release all hardware TCE tables attached to a group [ Upstream commit a67614cc05a5052b265ea48196dab2fce11f5f2e ] The SPAPR TCE KVM device references all hardware IOMMU tables assigned to some IOMMU group to ensure that in-kernel KVM acceleration of H_PUT_TCE can work. The tables are references when an IOMMU group gets registered with the VFIO KVM device by the KVM_DEV_VFIO_GROUP_ADD ioctl; KVM_DEV_VFIO_GROUP_DEL calls into the dereferencing code in kvm_spapr_tce_release_iommu_group() which walks through the list of LIOBNs, finds a matching IOMMU table and calls kref_put() when found. However that code stops after the very first successful derefencing leaving other tables referenced till the SPAPR TCE KVM device is destroyed which normally happens on guest reboot or termination so if we do hotplug and unplug in a loop, we are leaking IOMMU tables here. This removes a premature return to let kvm_spapr_tce_release_iommu_group() find and dereference all attached tables. Fixes: 121f80ba68f ("KVM: PPC: VFIO: Add in-kernel acceleration for VFIO") Signed-off-by: Alexey Kardashevskiy Signed-off-by: Paul Mackerras Signed-off-by: Sasha Levin --- arch/powerpc/kvm/book3s_64_vio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 5e4446296021..ef6a58838e7c 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -134,7 +134,6 @@ extern void kvm_spapr_tce_release_iommu_group(struct kvm *kvm, continue; kref_put(&stit->kref, kvm_spapr_tce_liobn_put); - return; } } } -- GitLab From 1e4d478a2878419f981631bea5521d59e083768e Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Fri, 15 Feb 2019 10:24:22 +0100 Subject: [PATCH 0407/1055] staging: r8822be: check kzalloc return or bail [ Upstream commit e4b08e16b7d9d030b6475ef48f94d734a39f3c81 ] The kzalloc() in halmac_parse_psd_data_88xx() can fail and return NULL so check the psd_set->data after allocation and if allocation failed return HALMAC_CMD_PROCESS_ERROR. Signed-off-by: Nicholas Mc Guire Fixes: 938a0447f094 ("staging: r8822be: Add code for halmac sub-drive") Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- .../staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c index 544f638ed3ef..15091ee587db 100644 --- a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c @@ -2492,8 +2492,11 @@ halmac_parse_psd_data_88xx(struct halmac_adapter *halmac_adapter, u8 *c2h_buf, segment_size = (u8)PSD_DATA_GET_SEGMENT_SIZE(c2h_buf); psd_set->data_size = total_size; - if (!psd_set->data) + if (!psd_set->data) { psd_set->data = kzalloc(psd_set->data_size, GFP_KERNEL); + if (!psd_set->data) + return HALMAC_CMD_PROCESS_ERROR; + } if (segment_id == 0) psd_set->segment_size = segment_size; -- GitLab From 11d671a2d81df342d448322cbf2935d2a45a45a1 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 18 Feb 2019 18:27:06 +0000 Subject: [PATCH 0408/1055] dmaengine: mv_xor: Use correct device for DMA API [ Upstream commit 3e5daee5ecf314da33a890fabaa2404244cd2a36 ] Using dma_dev->dev for mappings before it's assigned with the correct device is unlikely to work as expected, and with future dma-direct changes, passing a NULL device may end up crashing entirely. I don't know enough about this hardware or the mv_xor_prep_dma_interrupt() operation to implement the appropriate error-handling logic that would have revealed those dma_map_single() calls failing on arm64 for as long as the driver has been enabled there, but moving the assignment earlier will at least make the current code operate as intended. Fixes: 22843545b200 ("dma: mv_xor: Add support for DMA_INTERRUPT") Reported-by: John David Anglin Tested-by: John David Anglin Signed-off-by: Robin Murphy Acked-by: Thomas Petazzoni Tested-by: Thomas Petazzoni Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/mv_xor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 1993889003fd..1c57577f49fe 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -1059,6 +1059,7 @@ mv_xor_channel_add(struct mv_xor_device *xordev, mv_chan->op_in_desc = XOR_MODE_IN_DESC; dma_dev = &mv_chan->dmadev; + dma_dev->dev = &pdev->dev; mv_chan->xordev = xordev; /* @@ -1091,7 +1092,6 @@ mv_xor_channel_add(struct mv_xor_device *xordev, dma_dev->device_free_chan_resources = mv_xor_free_chan_resources; dma_dev->device_tx_status = mv_xor_status; dma_dev->device_issue_pending = mv_xor_issue_pending; - dma_dev->dev = &pdev->dev; /* set prep routines based on capability */ if (dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask)) -- GitLab From 2792ec5b8af1b98a0e9488860178088106f198fa Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 18 Feb 2019 22:34:51 +0800 Subject: [PATCH 0409/1055] cdc-wdm: pass return value of recover_from_urb_loss [ Upstream commit 0742a338f5b3446a26de551ad8273fb41b2787f2 ] 'rv' is the correct return value, pass it upstream instead of 0 Fixes: 17d80d562fd7 ("USB: autosuspend for cdc-wdm") Signed-off-by: YueHaibing Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/class/cdc-wdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index a593cdfc897f..d5d42dccda10 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -1085,7 +1085,7 @@ static int wdm_post_reset(struct usb_interface *intf) rv = recover_from_urb_loss(desc); mutex_unlock(&desc->wlock); mutex_unlock(&desc->rlock); - return 0; + return rv; } static struct usb_driver wdm_driver = { -- GitLab From ea988ebd9f2a774d9c9b0f996a88e0890643d773 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 19 Feb 2019 18:00:00 +0800 Subject: [PATCH 0410/1055] regulator: pv88060: Fix array out-of-bounds access [ Upstream commit 7cd415f875591bc66c5ecb49bf84ef97e80d7b0e ] Fix off-by-one while iterating current_limits array. The valid index should be 0 ~ n_current_limits -1. Fixes: f307a7e9b7af ("regulator: pv88060: new regulator driver") Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/regulator/pv88060-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/pv88060-regulator.c b/drivers/regulator/pv88060-regulator.c index a9446056435f..1f2d8180506b 100644 --- a/drivers/regulator/pv88060-regulator.c +++ b/drivers/regulator/pv88060-regulator.c @@ -135,7 +135,7 @@ static int pv88060_set_current_limit(struct regulator_dev *rdev, int min, int i; /* search for closest to maximum */ - for (i = info->n_current_limits; i >= 0; i--) { + for (i = info->n_current_limits - 1; i >= 0; i--) { if (min <= info->current_limits[i] && max >= info->current_limits[i]) { return regmap_update_bits(rdev->regmap, -- GitLab From ecd54f78e7156ec2ee15c6f017e1f0e10cbc7bf5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 19 Feb 2019 18:00:01 +0800 Subject: [PATCH 0411/1055] regulator: pv88080: Fix array out-of-bounds access [ Upstream commit 3c413f594c4f9df40061445667ca11a12bc8ee34 ] Fix off-by-one while iterating current_limits array. The valid index should be 0 ~ n_current_limits -1. Fixes: 99cf3af5e2d5 ("regulator: pv88080: new regulator driver") Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/regulator/pv88080-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/pv88080-regulator.c b/drivers/regulator/pv88080-regulator.c index 9a08cb2de501..6770e4de2097 100644 --- a/drivers/regulator/pv88080-regulator.c +++ b/drivers/regulator/pv88080-regulator.c @@ -279,7 +279,7 @@ static int pv88080_set_current_limit(struct regulator_dev *rdev, int min, int i; /* search for closest to maximum */ - for (i = info->n_current_limits; i >= 0; i--) { + for (i = info->n_current_limits - 1; i >= 0; i--) { if (min <= info->current_limits[i] && max >= info->current_limits[i]) { return regmap_update_bits(rdev->regmap, -- GitLab From 2797d17a7a22aa4480733df4b983bd8cc94aac0a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 19 Feb 2019 18:00:02 +0800 Subject: [PATCH 0412/1055] regulator: pv88090: Fix array out-of-bounds access [ Upstream commit a5455c9159414748bed4678184bf69989a4f7ba3 ] Fix off-by-one while iterating current_limits array. The valid index should be 0 ~ n_current_limits -1. Fixes: c90456e36d9c ("regulator: pv88090: new regulator driver") Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/regulator/pv88090-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/pv88090-regulator.c b/drivers/regulator/pv88090-regulator.c index 7a0c15957bd0..2302b0df7630 100644 --- a/drivers/regulator/pv88090-regulator.c +++ b/drivers/regulator/pv88090-regulator.c @@ -157,7 +157,7 @@ static int pv88090_set_current_limit(struct regulator_dev *rdev, int min, int i; /* search for closest to maximum */ - for (i = info->n_current_limits; i >= 0; i--) { + for (i = info->n_current_limits - 1; i >= 0; i--) { if (min <= info->current_limits[i] && max >= info->current_limits[i]) { return regmap_update_bits(rdev->regmap, -- GitLab From f4ece3516ea926242fdeed6975a5751a203656ab Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Tue, 19 Feb 2019 12:29:43 +0530 Subject: [PATCH 0413/1055] net: dsa: qca8k: Enable delay for RGMII_ID mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit a968b5e9d5879f9535d6099505f9e14abcafb623 ] RGMII_ID specifies that we should have internal delay, so resurrect the delay addition routine but under the RGMII_ID mode. Fixes: 40269aa9f40a ("net: dsa: qca8k: disable delay for RGMII mode") Tested-by: Michal Vokáč Signed-off-by: Vinod Koul Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/dsa/qca8k.c | 12 ++++++++++++ drivers/net/dsa/qca8k.h | 1 + 2 files changed, 13 insertions(+) diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 8e49974ffa0e..8ee59b20b47a 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -459,6 +459,18 @@ qca8k_set_pad_ctrl(struct qca8k_priv *priv, int port, int mode) qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); break; + case PHY_INTERFACE_MODE_RGMII_ID: + /* RGMII_ID needs internal delay. This is enabled through + * PORT5_PAD_CTRL for all ports, rather than individual port + * registers + */ + qca8k_write(priv, reg, + QCA8K_PORT_PAD_RGMII_EN | + QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) | + QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY)); + qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, + QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); + break; case PHY_INTERFACE_MODE_SGMII: qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); break; diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h index 613fe5c50236..d146e54c8a6c 100644 --- a/drivers/net/dsa/qca8k.h +++ b/drivers/net/dsa/qca8k.h @@ -40,6 +40,7 @@ ((0x8 + (x & 0x3)) << 22) #define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) \ ((0x10 + (x & 0x3)) << 20) +#define QCA8K_MAX_DELAY 3 #define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24) #define QCA8K_PORT_PAD_SGMII_EN BIT(7) #define QCA8K_REG_MODULE_EN 0x030 -- GitLab From 0fd24a6a8a063c064a664797d4913d5f365f56a2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 25 Nov 2018 17:09:18 +0000 Subject: [PATCH 0414/1055] drm/nouveau/bios/ramcfg: fix missing parentheses when calculating RON [ Upstream commit 13649101a25c53c87f4ab98a076dfe61f3636ab1 ] Currently, the expression for calculating RON is always going to result in zero no matter the value of ram->mr[1] because the ! operator has higher precedence than the shift >> operator. I believe the missing parentheses around the expression before appying the ! operator will result in the desired result. [ Note, not tested ] Detected by CoveritScan, CID#1324005 ("Operands don't affect result") Fixes: c25bf7b6155c ("drm/nouveau/bios/ramcfg: Separate out RON pull value") Signed-off-by: Colin Ian King Signed-off-by: Ben Skeggs Signed-off-by: Sasha Levin --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c index 60ece0a8a2e1..1d2d6bae73cd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c @@ -87,7 +87,7 @@ nvkm_gddr3_calc(struct nvkm_ram *ram) WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16; /* XXX: Get these values from the VBIOS instead */ DLL = !(ram->mr[1] & 0x1); - RON = !(ram->mr[1] & 0x300) >> 8; + RON = !((ram->mr[1] & 0x300) >> 8); break; default: return -ENOSYS; -- GitLab From 1cdadf8223915491fd3b774581b199b76fcc48e0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 19 Dec 2018 15:29:49 +0000 Subject: [PATCH 0415/1055] drm/nouveau/pmu: don't print reply values if exec is false [ Upstream commit b1d03fc36ec9834465a08c275c8d563e07f6f6bf ] Currently the uninitialized values in the array reply are printed out when exec is false and nvkm_pmu_send has not updated the array. Avoid confusion by only dumping out these values if they have been actually updated. Detected by CoverityScan, CID#1271291 ("Uninitialized scaler variable") Fixes: ebb58dc2ef8c ("drm/nouveau/pmu: rename from pwr (no binary change)") Signed-off-by: Colin Ian King Signed-off-by: Ben Skeggs Signed-off-by: Sasha Levin --- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c index 11b28b086a06..7b052879af72 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c @@ -88,10 +88,10 @@ nvkm_memx_fini(struct nvkm_memx **pmemx, bool exec) if (exec) { nvkm_pmu_send(pmu, reply, PROC_MEMX, MEMX_MSG_EXEC, memx->base, finish); + nvkm_debug(subdev, "Exec took %uns, PMU_IN %08x\n", + reply[0], reply[1]); } - nvkm_debug(subdev, "Exec took %uns, PMU_IN %08x\n", - reply[0], reply[1]); kfree(memx); return 0; } -- GitLab From 23e85b26ea102e64d39e1d12e109d65b51d27575 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 19 Feb 2019 16:46:50 +0100 Subject: [PATCH 0416/1055] ASoC: qcom: Fix of-node refcount unbalance in apq8016_sbc_parse_of() [ Upstream commit 8d1667200850f8753c0265fa4bd25c9a6e5f94ce ] The apq8016 driver leaves the of-node refcount at aborting from the loop of for_each_child_of_node() in the error path. Not only the iterator node of for_each_child_of_node(), the children nodes referred from it for codec and cpu have to be properly unreferenced. Fixes: bdb052e81f62 ("ASoC: qcom: add apq8016 sound card support") Cc: Patrick Lai Cc: Banajit Goswami Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/qcom/apq8016_sbc.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index d49adc822a11..8e6b88d68ca6 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -163,41 +163,52 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) if (!cpu || !codec) { dev_err(dev, "Can't find cpu/codec DT node\n"); - return ERR_PTR(-EINVAL); + ret = -EINVAL; + goto error; } link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0); if (!link->cpu_of_node) { dev_err(card->dev, "error getting cpu phandle\n"); - return ERR_PTR(-EINVAL); + ret = -EINVAL; + goto error; } ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name); if (ret) { dev_err(card->dev, "error getting cpu dai name\n"); - return ERR_PTR(ret); + goto error; } ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); if (ret < 0) { dev_err(card->dev, "error getting codec dai name\n"); - return ERR_PTR(ret); + goto error; } link->platform_of_node = link->cpu_of_node; ret = of_property_read_string(np, "link-name", &link->name); if (ret) { dev_err(card->dev, "error getting codec dai_link name\n"); - return ERR_PTR(ret); + goto error; } link->stream_name = link->name; link->init = apq8016_sbc_dai_init; link++; + + of_node_put(cpu); + of_node_put(codec); } return data; + + error: + of_node_put(np); + of_node_put(cpu); + of_node_put(codec); + return ERR_PTR(ret); } static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = { -- GitLab From 69c5a33b72bd84a36a158c7a0401c67d776ddeec Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 30 Jan 2019 07:58:38 -0600 Subject: [PATCH 0417/1055] fs/nfs: Fix nfs_parse_devname to not modify it's argument [ Upstream commit 40cc394be1aa18848b8757e03bd8ed23281f572e ] In the rare and unsupported case of a hostname list nfs_parse_devname will modify dev_name. There is no need to modify dev_name as the all that is being computed is the length of the hostname, so the computed length can just be shorted. Fixes: dc04589827f7 ("NFS: Use common device name parsing logic for NFSv4 and NFSv2/v3") Signed-off-by: "Eric W. Biederman" Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f464f8d9060c..470b761839a5 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -1925,7 +1925,7 @@ static int nfs_parse_devname(const char *dev_name, /* kill possible hostname list: not supported */ comma = strchr(dev_name, ','); if (comma != NULL && comma < end) - *comma = 0; + len = comma - dev_name; } if (len > maxnamlen) -- GitLab From 5ada2bd122e42038dd0df468d1642095a05a33be Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 20 Feb 2019 22:25:24 -0700 Subject: [PATCH 0418/1055] staging: rtlwifi: Use proper enum for return in halmac_parse_psd_data_88xx [ Upstream commit e8edc32d70a4e09160835792eb5d1af71a0eec14 ] Clang warns: drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c:2472:11: warning: implicit conversion from enumeration type 'enum halmac_cmd_process_status' to different enumeration type 'enum halmac_ret_status' [-Wenum-conversion] return HALMAC_CMD_PROCESS_ERROR; ~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~ 1 warning generated. Fix this by using the proper enum for allocation failures, HALMAC_RET_MALLOC_FAIL, which is used in the rest of this file. Fixes: e4b08e16b7d9 ("staging: r8822be: check kzalloc return or bail") Link: https://github.com/ClangBuiltLinux/linux/issues/375 Signed-off-by: Nathan Chancellor Reviewed-by: Nicholas Mc Guire Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c index 15091ee587db..65edd14a1147 100644 --- a/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c +++ b/drivers/staging/rtlwifi/halmac/halmac_88xx/halmac_func_88xx.c @@ -2495,7 +2495,7 @@ halmac_parse_psd_data_88xx(struct halmac_adapter *halmac_adapter, u8 *c2h_buf, if (!psd_set->data) { psd_set->data = kzalloc(psd_set->data_size, GFP_KERNEL); if (!psd_set->data) - return HALMAC_CMD_PROCESS_ERROR; + return HALMAC_RET_MALLOC_FAIL; } if (segment_id == 0) -- GitLab From afdb6f57d778dff7b58e7e1cba5d12ca9baff795 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 11 Feb 2019 11:20:01 +1100 Subject: [PATCH 0419/1055] powerpc/64s: Fix logic when handling unknown CPU features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8cfaf106918a8c13abb24c641556172afbb9545c ] In cpufeatures_process_feature(), if a provided CPU feature is unknown and enable_unknown is false, we erroneously print that the feature is being enabled and return true, even though no feature has been enabled, and may also set feature bits based on the last entry in the match table. Fix this so that we only set feature bits from the match table if we have actually enabled a feature from that table, and when failing to enable an unknown feature, always print the "not enabling" message and return false. Coincidentally, some older gccs (cpu_ftr_bit_mask) An upcoming patch will enable support for kcov, which requires this option. This patch avoids the warning. Fixes: 5a61ef74f269 ("powerpc/64s: Support new device tree binding for discovering CPU features") Reported-by: Segher Boessenkool Signed-off-by: Michael Ellerman [ajd: add commit message] Signed-off-by: Andrew Donnellan Signed-off-by: Sasha Levin --- arch/powerpc/kernel/dt_cpu_ftrs.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c index 2357df60de95..7ed2b1b6643c 100644 --- a/arch/powerpc/kernel/dt_cpu_ftrs.c +++ b/arch/powerpc/kernel/dt_cpu_ftrs.c @@ -705,8 +705,10 @@ static bool __init cpufeatures_process_feature(struct dt_cpu_feature *f) m = &dt_cpu_feature_match_table[i]; if (!strcmp(f->name, m->name)) { known = true; - if (m->enable(f)) + if (m->enable(f)) { + cur_cpu_spec->cpu_features |= m->cpu_ftr_bit_mask; break; + } pr_info("not enabling: %s (disabled or unsupported by kernel)\n", f->name); @@ -714,17 +716,12 @@ static bool __init cpufeatures_process_feature(struct dt_cpu_feature *f) } } - if (!known && enable_unknown) { - if (!feat_try_enable_unknown(f)) { - pr_info("not enabling: %s (unknown and unsupported by kernel)\n", - f->name); - return false; - } + if (!known && (!enable_unknown || !feat_try_enable_unknown(f))) { + pr_info("not enabling: %s (unknown and unsupported by kernel)\n", + f->name); + return false; } - if (m->cpu_ftr_bit_mask) - cur_cpu_spec->cpu_features |= m->cpu_ftr_bit_mask; - if (known) pr_debug("enabling: %s\n", f->name); else -- GitLab From a155d39d1e4c1b7e7edcc8885742a87c2c479cd6 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 21 Feb 2019 14:51:25 -0500 Subject: [PATCH 0420/1055] NFS: Fix a soft lockup in the delegation recovery code [ Upstream commit 6f9449be53f3ce383caed797708b332ede8d952c ] Fix a soft lockup when NFS client delegation recovery is attempted but the inode is in the process of being freed. When the igrab(inode) call fails, and we have to restart the recovery process, we need to ensure that we won't attempt to recover the same delegation again. Fixes: 45870d6909d5a ("NFSv4.1: Test delegation stateids when server...") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/delegation.c | 20 ++++++++++++-------- fs/nfs/delegation.h | 1 + 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 04d57e11577e..09b3bcb86d32 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -234,6 +234,8 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation spin_lock(&delegation->lock); if (delegation->inode != NULL) inode = igrab(delegation->inode); + if (!inode) + set_bit(NFS_DELEGATION_INODE_FREEING, &delegation->flags); spin_unlock(&delegation->lock); return inode; } @@ -863,10 +865,11 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp) list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { list_for_each_entry_rcu(delegation, &server->delegations, super_list) { - if (test_bit(NFS_DELEGATION_RETURNING, - &delegation->flags)) - continue; - if (test_bit(NFS_DELEGATION_NEED_RECLAIM, + if (test_bit(NFS_DELEGATION_INODE_FREEING, + &delegation->flags) || + test_bit(NFS_DELEGATION_RETURNING, + &delegation->flags) || + test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0) continue; if (!nfs_sb_active(server->super)) @@ -971,10 +974,11 @@ void nfs_reap_expired_delegations(struct nfs_client *clp) list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { list_for_each_entry_rcu(delegation, &server->delegations, super_list) { - if (test_bit(NFS_DELEGATION_RETURNING, - &delegation->flags)) - continue; - if (test_bit(NFS_DELEGATION_TEST_EXPIRED, + if (test_bit(NFS_DELEGATION_INODE_FREEING, + &delegation->flags) || + test_bit(NFS_DELEGATION_RETURNING, + &delegation->flags) || + test_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags) == 0) continue; if (!nfs_sb_active(server->super)) diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index df41d16dc6ab..510c9edcc712 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -34,6 +34,7 @@ enum { NFS_DELEGATION_RETURNING, NFS_DELEGATION_REVOKED, NFS_DELEGATION_TEST_EXPIRED, + NFS_DELEGATION_INODE_FREEING, }; int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); -- GitLab From cc423232fb93e234e8e43edc0ca1cda830e48e21 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 10 Jan 2019 14:22:07 +0800 Subject: [PATCH 0421/1055] clocksource/drivers/sun5i: Fail gracefully when clock rate is unavailable [ Upstream commit e7e7e0d7beafebd11b0c065cd5fbc1e5759c5aab ] If the clock tree is not fully populated when the timer-sun5i init code is called, attempts to get the clock rate for the timer would fail and return 0. Make the init code for both clock events and clocksource check the returned clock rate and fail gracefully if the result is 0, instead of causing a divide by 0 exception later on. Fixes: 4a59058f0b09 ("clocksource/drivers/sun5i: Refactor the current code") Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Daniel Lezcano Signed-off-by: Sasha Levin --- drivers/clocksource/timer-sun5i.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index 2a3fe83ec337..6f4a9a8faccc 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -202,6 +202,11 @@ static int __init sun5i_setup_clocksource(struct device_node *node, } rate = clk_get_rate(clk); + if (!rate) { + pr_err("Couldn't get parent clock rate\n"); + ret = -EINVAL; + goto err_disable_clk; + } cs->timer.base = base; cs->timer.clk = clk; @@ -275,6 +280,11 @@ static int __init sun5i_setup_clockevent(struct device_node *node, void __iomem } rate = clk_get_rate(clk); + if (!rate) { + pr_err("Couldn't get parent clock rate\n"); + ret = -EINVAL; + goto err_disable_clk; + } ce->timer.base = base; ce->timer.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ); -- GitLab From ba95507ae390062f5af1e8de76c8161fcc69eade Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 18 Oct 2018 11:57:04 +0200 Subject: [PATCH 0422/1055] clocksource/drivers/exynos_mct: Fix error path in timer resources initialization [ Upstream commit b9307420196009cdf18bad55e762ac49fb9a80f4 ] While freeing interrupt handlers in error path, don't assume that all requested interrupts are per-processor interrupts and properly release standard interrupts too. Reported-by: Krzysztof Kozlowski Fixes: 56a94f13919c ("clocksource: exynos_mct: Avoid blocking calls in the cpu hotplug notifier") Signed-off-by: Marek Szyprowski Reviewed-by: Krzysztof Kozlowski Reviewed-by: Chanwoo Choi Signed-off-by: Daniel Lezcano Signed-off-by: Sasha Levin --- drivers/clocksource/exynos_mct.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index aaf5bfa9bd9c..e3ae041ac30e 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -563,7 +563,19 @@ static int __init exynos4_timer_resources(struct device_node *np, void __iomem * return 0; out_irq: - free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick); + if (mct_int_type == MCT_INT_PPI) { + free_percpu_irq(mct_irqs[MCT_L0_IRQ], &percpu_mct_tick); + } else { + for_each_possible_cpu(cpu) { + struct mct_clock_event_device *pcpu_mevt = + per_cpu_ptr(&percpu_mct_tick, cpu); + + if (pcpu_mevt->evt.irq != -1) { + free_irq(pcpu_mevt->evt.irq, pcpu_mevt); + pcpu_mevt->evt.irq = -1; + } + } + } return err; } -- GitLab From 6fdf4970d3f8832525554a4f0a79d71ecc469e1b Mon Sep 17 00:00:00 2001 From: Mattias Jacobsson <2pi@mok.nu> Date: Wed, 30 Jan 2019 16:14:24 +0100 Subject: [PATCH 0423/1055] platform/x86: wmi: fix potential null pointer dereference [ Upstream commit c355ec651a8941864549f2586f969d0eb7bf499a ] In the function wmi_dev_match() the variable id is dereferenced without first performing a NULL check. The variable can for example be NULL if a WMI driver is registered without specifying the id_table field in struct wmi_driver. Add a NULL check and return that the driver can't handle the device if the variable is NULL. Fixes: 844af950da94 ("platform/x86: wmi: Turn WMI into a bus driver") Signed-off-by: Mattias Jacobsson <2pi@mok.nu> Signed-off-by: Darren Hart (VMware) Signed-off-by: Sasha Levin --- drivers/platform/x86/wmi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 7f8fa42a1084..a56e997816b2 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -748,6 +748,9 @@ static int wmi_dev_match(struct device *dev, struct device_driver *driver) struct wmi_block *wblock = dev_to_wblock(dev); const struct wmi_device_id *id = wmi_driver->id_table; + if (id == NULL) + return 0; + while (id->guid_string) { uuid_le driver_guid; -- GitLab From 0cf0f51cc94c3e29ffc345f82468fe7c29df3b5b Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 22 Feb 2019 14:20:27 -0500 Subject: [PATCH 0424/1055] NFS/pnfs: Bulk destroy of layouts needs to be safe w.r.t. umount [ Upstream commit 5085607d209102b37b169bc94d0aa39566a9842a ] If a bulk layout recall or a metadata server reboot coincides with a umount, then holding a reference to an inode is unsafe unless we also hold a reference to the super block. Fixes: fd9a8d7160937 ("NFSv4.1: Fix bulk recall and destroy of layouts") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/pnfs.c | 33 +++++++++++++++++++++++---------- fs/nfs/pnfs.h | 1 + 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index ec04cce31814..83abf3dd7351 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -725,22 +725,35 @@ static int pnfs_layout_bulk_destroy_byserver_locked(struct nfs_client *clp, struct nfs_server *server, struct list_head *layout_list) + __must_hold(&clp->cl_lock) + __must_hold(RCU) { struct pnfs_layout_hdr *lo, *next; struct inode *inode; list_for_each_entry_safe(lo, next, &server->layouts, plh_layouts) { - if (test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) + if (test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) || + test_bit(NFS_LAYOUT_INODE_FREEING, &lo->plh_flags) || + !list_empty(&lo->plh_bulk_destroy)) continue; + /* If the sb is being destroyed, just bail */ + if (!nfs_sb_active(server->super)) + break; inode = igrab(lo->plh_inode); - if (inode == NULL) - continue; - list_del_init(&lo->plh_layouts); - if (pnfs_layout_add_bulk_destroy_list(inode, layout_list)) - continue; - rcu_read_unlock(); - spin_unlock(&clp->cl_lock); - iput(inode); + if (inode != NULL) { + list_del_init(&lo->plh_layouts); + if (pnfs_layout_add_bulk_destroy_list(inode, + layout_list)) + continue; + rcu_read_unlock(); + spin_unlock(&clp->cl_lock); + iput(inode); + } else { + rcu_read_unlock(); + spin_unlock(&clp->cl_lock); + set_bit(NFS_LAYOUT_INODE_FREEING, &lo->plh_flags); + } + nfs_sb_deactive(server->super); spin_lock(&clp->cl_lock); rcu_read_lock(); return -EAGAIN; @@ -778,7 +791,7 @@ pnfs_layout_free_bulk_destroy_list(struct list_head *layout_list, /* Free all lsegs that are attached to commit buckets */ nfs_commit_inode(inode, 0); pnfs_put_layout_hdr(lo); - iput(inode); + nfs_iput_and_deactive(inode); } return ret; } diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 87f144f14d1e..965d657086c8 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -99,6 +99,7 @@ enum { NFS_LAYOUT_RETURN_REQUESTED, /* Return this layout ASAP */ NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */ NFS_LAYOUT_FIRST_LAYOUTGET, /* Serialize first layoutget */ + NFS_LAYOUT_INODE_FREEING, /* The inode is being freed */ }; enum layoutdriver_policy_flags { -- GitLab From d95167b06b8696044c516891e0c51be7dd34e631 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sun, 23 Dec 2018 21:59:18 +0100 Subject: [PATCH 0425/1055] mmc: sdhci-brcmstb: handle mmc_of_parse() errors during probe [ Upstream commit 1e20186e706da8446f9435f2924cd65ab1397e73 ] We need to handle mmc_of_parse() errors during probe otherwise the MMC driver could start without proper initialization (e.g. power sequence). Fixes: 476bf3d62d5c ("mmc: sdhci-brcmstb: Add driver for Broadcom BRCMSTB SoCs") Signed-off-by: Stefan Wahren Signed-off-by: Ulf Hansson Signed-off-by: Sasha Levin --- drivers/mmc/host/sdhci-brcmstb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c index 552bddc5096c..1cd10356fc14 100644 --- a/drivers/mmc/host/sdhci-brcmstb.c +++ b/drivers/mmc/host/sdhci-brcmstb.c @@ -55,7 +55,9 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev) } sdhci_get_of_property(pdev); - mmc_of_parse(host->mmc); + res = mmc_of_parse(host->mmc); + if (res) + goto err; /* * Supply the existing CAPS, but clear the UHS modes. This -- GitLab From feb8ad9508f6fbba81b99cf25af1de7bee72c7b3 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 18 Feb 2019 09:31:41 +0100 Subject: [PATCH 0426/1055] ARM: 8847/1: pm: fix HYP/SVC mode mismatch when MCPM is used [ Upstream commit ca70ea43f80c98582f5ffbbd1e6f4da2742da0c4 ] MCPM does a soft reset of the CPUs and uses common cpu_resume() routine to perform low-level platform initialization. This results in a try to install HYP stubs for the second time for each CPU and results in false HYP/SVC mode mismatch detection. The HYP stubs are already installed at the beginning of the kernel initialization on the boot CPU (head.S) or in the secondary_startup() for other CPUs. To fix this issue MCPM code should use a cpu_resume() routine without HYP stubs installation. This change fixes HYP/SVC mode mismatch on Samsung Exynos5422-based Odroid XU3/XU4/HC1 boards. Fixes: 3721924c8154 ("ARM: 8081/1: MCPM: provide infrastructure to allow for MCPM loopback") Signed-off-by: Marek Szyprowski Acked-by: Nicolas Pitre Tested-by: Anand Moon Signed-off-by: Russell King Signed-off-by: Sasha Levin --- arch/arm/common/mcpm_entry.c | 2 +- arch/arm/include/asm/suspend.h | 1 + arch/arm/kernel/sleep.S | 12 ++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/arm/common/mcpm_entry.c b/arch/arm/common/mcpm_entry.c index 2b913f17d50f..c24a55b0deac 100644 --- a/arch/arm/common/mcpm_entry.c +++ b/arch/arm/common/mcpm_entry.c @@ -379,7 +379,7 @@ static int __init nocache_trampoline(unsigned long _arg) unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); phys_reset_t phys_reset; - mcpm_set_entry_vector(cpu, cluster, cpu_resume); + mcpm_set_entry_vector(cpu, cluster, cpu_resume_no_hyp); setup_mm_for_reboot(); __mcpm_cpu_going_down(cpu, cluster); diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h index 452bbdcbcc83..506314265c6f 100644 --- a/arch/arm/include/asm/suspend.h +++ b/arch/arm/include/asm/suspend.h @@ -10,6 +10,7 @@ struct sleep_save_sp { }; extern void cpu_resume(void); +extern void cpu_resume_no_hyp(void); extern void cpu_resume_arm(void); extern int cpu_suspend(unsigned long, int (*)(unsigned long)); diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S index a8257fc9cf2a..5dc8b80bb693 100644 --- a/arch/arm/kernel/sleep.S +++ b/arch/arm/kernel/sleep.S @@ -120,6 +120,14 @@ ENDPROC(cpu_resume_after_mmu) .text .align +#ifdef CONFIG_MCPM + .arm +THUMB( .thumb ) +ENTRY(cpu_resume_no_hyp) +ARM_BE8(setend be) @ ensure we are in BE mode + b no_hyp +#endif + #ifdef CONFIG_MMU .arm ENTRY(cpu_resume_arm) @@ -135,6 +143,7 @@ ARM_BE8(setend be) @ ensure we are in BE mode bl __hyp_stub_install_secondary #endif safe_svcmode_maskall r1 +no_hyp: mov r1, #0 ALT_SMP(mrc p15, 0, r0, c0, c0, 5) ALT_UP_B(1f) @@ -163,6 +172,9 @@ ENDPROC(cpu_resume) #ifdef CONFIG_MMU ENDPROC(cpu_resume_arm) +#endif +#ifdef CONFIG_MCPM +ENDPROC(cpu_resume_no_hyp) #endif .align 2 -- GitLab From 1a65ea1ea865e74490b2cb186d3ce3f934b9550d Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Wed, 20 Feb 2019 15:00:13 +0100 Subject: [PATCH 0427/1055] ARM: 8848/1: virt: Align GIC version check with arm64 counterpart [ Upstream commit 9db043d36bd379f4cc99054c079de0dabfc38d03 ] arm64 has got relaxation on GIC version check at early boot stage due to update of the GIC architecture let's align ARM with that. To help backports (even though the code was correct at the time of writing) Fixes: e59941b9b381 ("ARM: 8527/1: virt: enable GICv3 system registers") Signed-off-by: Vladimir Murzin Reviewed-by: Marc Zyngier Signed-off-by: Russell King Signed-off-by: Sasha Levin --- arch/arm/kernel/hyp-stub.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/hyp-stub.S b/arch/arm/kernel/hyp-stub.S index 60146e32619a..82a942894fc0 100644 --- a/arch/arm/kernel/hyp-stub.S +++ b/arch/arm/kernel/hyp-stub.S @@ -180,8 +180,8 @@ ARM_BE8(orr r7, r7, #(1 << 25)) @ HSCTLR.EE @ Check whether GICv3 system registers are available mrc p15, 0, r7, c0, c1, 1 @ ID_PFR1 ubfx r7, r7, #28, #4 - cmp r7, #1 - bne 2f + teq r7, #0 + beq 2f @ Enable system register accesses mrc p15, 4, r7, c12, c9, 5 @ ICC_HSRE -- GitLab From 79db752d9004b3a77528078b68de18861805b800 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 24 Feb 2019 21:16:51 +0800 Subject: [PATCH 0428/1055] regulator: wm831x-dcdc: Fix list of wm831x_dcdc_ilim from mA to uA [ Upstream commit c25d47888f0fb3d836d68322d4aea2caf31a75a6 ] The wm831x_dcdc_ilim entries needs to be uA because it is used to compare with min_uA and max_uA. While at it also make the array const and change to use unsigned int. Fixes: e4ee831f949a ("regulator: Add WM831x DC-DC buck convertor support") Signed-off-by: Axel Lin Acked-by: Charles Keepax Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/regulator/wm831x-dcdc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 5a5bc4bb08d2..df591435d12a 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -327,8 +327,8 @@ static int wm831x_buckv_get_voltage_sel(struct regulator_dev *rdev) } /* Current limit options */ -static u16 wm831x_dcdc_ilim[] = { - 125, 250, 375, 500, 625, 750, 875, 1000 +static const unsigned int wm831x_dcdc_ilim[] = { + 125000, 250000, 375000, 500000, 625000, 750000, 875000, 1000000 }; static int wm831x_buckv_set_current_limit(struct regulator_dev *rdev, -- GitLab From 223b167f01e30201e5de6db87b273ba5a36992a4 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 25 Feb 2019 14:13:41 +0100 Subject: [PATCH 0429/1055] netfilter: nft_set_hash: fix lookups with fixed size hash on big endian [ Upstream commit 3b02b0adc242a72b5e46019b6a9e4f84823592f6 ] Call jhash_1word() for the 4-bytes key case from the insertion and deactivation path, otherwise big endian arch set lookups fail. Fixes: 446a8268b7f5 ("netfilter: nft_set_hash: add lookup variant for fixed size hashtable") Reported-by: Florian Westphal Tested-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/netfilter/nft_set_hash.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c index 33aa2ac3a62e..73f8f99b1193 100644 --- a/net/netfilter/nft_set_hash.c +++ b/net/netfilter/nft_set_hash.c @@ -442,6 +442,23 @@ static bool nft_hash_lookup_fast(const struct net *net, return false; } +static u32 nft_jhash(const struct nft_set *set, const struct nft_hash *priv, + const struct nft_set_ext *ext) +{ + const struct nft_data *key = nft_set_ext_key(ext); + u32 hash, k1; + + if (set->klen == 4) { + k1 = *(u32 *)key; + hash = jhash_1word(k1, priv->seed); + } else { + hash = jhash(key, set->klen, priv->seed); + } + hash = reciprocal_scale(hash, priv->buckets); + + return hash; +} + static int nft_hash_insert(const struct net *net, const struct nft_set *set, const struct nft_set_elem *elem, struct nft_set_ext **ext) @@ -451,8 +468,7 @@ static int nft_hash_insert(const struct net *net, const struct nft_set *set, u8 genmask = nft_genmask_next(net); u32 hash; - hash = jhash(nft_set_ext_key(&this->ext), set->klen, priv->seed); - hash = reciprocal_scale(hash, priv->buckets); + hash = nft_jhash(set, priv, &this->ext); hlist_for_each_entry(he, &priv->table[hash], node) { if (!memcmp(nft_set_ext_key(&this->ext), nft_set_ext_key(&he->ext), set->klen) && @@ -491,8 +507,7 @@ static void *nft_hash_deactivate(const struct net *net, u8 genmask = nft_genmask_next(net); u32 hash; - hash = jhash(nft_set_ext_key(&this->ext), set->klen, priv->seed); - hash = reciprocal_scale(hash, priv->buckets); + hash = nft_jhash(set, priv, &this->ext); hlist_for_each_entry(he, &priv->table[hash], node) { if (!memcmp(nft_set_ext_key(&this->ext), &elem->key.val, set->klen) || -- GitLab From 76cc6d437e1349c34ef08fb428d1e4ef0c912c9d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 26 Feb 2019 11:19:46 -0500 Subject: [PATCH 0430/1055] NFSv4/flexfiles: Fix invalid deref in FF_LAYOUT_DEVID_NODE() [ Upstream commit 108bb4afd351d65826648a47f11fa3104e250d9b ] If the attempt to instantiate the mirror's layout DS pointer failed, then that pointer may hold a value of type ERR_PTR(), so we need to check that before we dereference it. Fixes: 65990d1afbd2d ("pNFS/flexfiles: Fix a deadlock on LAYOUTGET") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin --- fs/nfs/flexfilelayout/flexfilelayout.h | 32 +++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.h b/fs/nfs/flexfilelayout/flexfilelayout.h index d6515f1584f3..d78ec99b6c4c 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.h +++ b/fs/nfs/flexfilelayout/flexfilelayout.h @@ -131,16 +131,6 @@ FF_LAYOUT_LSEG(struct pnfs_layout_segment *lseg) generic_hdr); } -static inline struct nfs4_deviceid_node * -FF_LAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg, u32 idx) -{ - if (idx >= FF_LAYOUT_LSEG(lseg)->mirror_array_cnt || - FF_LAYOUT_LSEG(lseg)->mirror_array[idx] == NULL || - FF_LAYOUT_LSEG(lseg)->mirror_array[idx]->mirror_ds == NULL) - return NULL; - return &FF_LAYOUT_LSEG(lseg)->mirror_array[idx]->mirror_ds->id_node; -} - static inline struct nfs4_ff_layout_ds * FF_LAYOUT_MIRROR_DS(struct nfs4_deviceid_node *node) { @@ -150,9 +140,25 @@ FF_LAYOUT_MIRROR_DS(struct nfs4_deviceid_node *node) static inline struct nfs4_ff_layout_mirror * FF_LAYOUT_COMP(struct pnfs_layout_segment *lseg, u32 idx) { - if (idx >= FF_LAYOUT_LSEG(lseg)->mirror_array_cnt) - return NULL; - return FF_LAYOUT_LSEG(lseg)->mirror_array[idx]; + struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg); + + if (idx < fls->mirror_array_cnt) + return fls->mirror_array[idx]; + return NULL; +} + +static inline struct nfs4_deviceid_node * +FF_LAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg, u32 idx) +{ + struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, idx); + + if (mirror != NULL) { + struct nfs4_ff_layout_ds *mirror_ds = mirror->mirror_ds; + + if (!IS_ERR_OR_NULL(mirror_ds)) + return &mirror_ds->id_node; + } + return NULL; } static inline u32 -- GitLab From 3b24a4144fbd078e6665ba8c64e6611eb14cecc5 Mon Sep 17 00:00:00 2001 From: Igor Russkikh Date: Wed, 27 Feb 2019 12:10:09 +0000 Subject: [PATCH 0431/1055] net: aquantia: fixed instack structure overflow [ Upstream commit 8006e3730b6e900319411e35cee85b4513d298df ] This is a real stack undercorruption found by kasan build. The issue did no harm normally because it only overflowed 2 bytes after `bitary` array which on most architectures were mapped into `err` local. Fixes: bab6de8fd180 ("net: ethernet: aquantia: Atlantic A0 and B0 specific functions.") Signed-off-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c | 4 ++-- drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c index b0abd187cead..b83ee74d2839 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c @@ -182,8 +182,8 @@ static int hw_atl_a0_hw_rss_set(struct aq_hw_s *self, u32 i = 0U; u32 num_rss_queues = max(1U, self->aq_nic_cfg->num_rss_queues); int err = 0; - u16 bitary[(HW_ATL_A0_RSS_REDIRECTION_MAX * - HW_ATL_A0_RSS_REDIRECTION_BITS / 16U)]; + u16 bitary[1 + (HW_ATL_A0_RSS_REDIRECTION_MAX * + HW_ATL_A0_RSS_REDIRECTION_BITS / 16U)]; memset(bitary, 0, sizeof(bitary)); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 236325f48ec9..1c1bb074f664 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -183,8 +183,8 @@ static int hw_atl_b0_hw_rss_set(struct aq_hw_s *self, u32 i = 0U; u32 num_rss_queues = max(1U, self->aq_nic_cfg->num_rss_queues); int err = 0; - u16 bitary[(HW_ATL_B0_RSS_REDIRECTION_MAX * - HW_ATL_B0_RSS_REDIRECTION_BITS / 16U)]; + u16 bitary[1 + (HW_ATL_B0_RSS_REDIRECTION_MAX * + HW_ATL_B0_RSS_REDIRECTION_BITS / 16U)]; memset(bitary, 0, sizeof(bitary)); -- GitLab From 43f5a75119f6d03f88b6c59ca2745934d72ea698 Mon Sep 17 00:00:00 2001 From: Rashmica Gupta Date: Wed, 13 Feb 2019 10:29:49 +1100 Subject: [PATCH 0432/1055] powerpc/mm: Check secondary hash page table [ Upstream commit 790845e2f12709d273d08ea7a2af7c2593689519 ] We were always calling base_hpte_find() with primary = true, even when we wanted to check the secondary table. mpe: I broke this when refactoring Rashmica's original patch. Fixes: 1515ab932156 ("powerpc/mm: Dump hash table") Signed-off-by: Rashmica Gupta Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin --- arch/powerpc/mm/dump_hashpagetable.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/mm/dump_hashpagetable.c b/arch/powerpc/mm/dump_hashpagetable.c index 5c4c93dcff19..f666d74f05f5 100644 --- a/arch/powerpc/mm/dump_hashpagetable.c +++ b/arch/powerpc/mm/dump_hashpagetable.c @@ -343,7 +343,7 @@ static unsigned long hpte_find(struct pg_state *st, unsigned long ea, int psize) /* Look in secondary table */ if (slot == -1) - slot = base_hpte_find(ea, psize, true, &v, &r); + slot = base_hpte_find(ea, psize, false, &v, &r); /* No entry found */ if (slot == -1) -- GitLab From a3323a093f3af8a715ce76c7d0783b1ac3a0cf93 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 7 Nov 2018 10:36:10 +0800 Subject: [PATCH 0433/1055] nios2: ksyms: Add missing symbol exports [ Upstream commit 0f8ed994575429d6042cf5d7ef70081c94091587 ] Building nios2:allmodconfig fails as follows (each symbol is only listed once). ERROR: "__ashldi3" [drivers/md/dm-writecache.ko] undefined! ERROR: "__ashrdi3" [fs/xfs/xfs.ko] undefined! ERROR: "__ucmpdi2" [drivers/media/i2c/adv7842.ko] undefined! ERROR: "__lshrdi3" [drivers/md/dm-zoned.ko] undefined! ERROR: "flush_icache_range" [drivers/misc/lkdtm/lkdtm.ko] undefined! ERROR: "empty_zero_page" [drivers/md/dm-mod.ko] undefined! The problem is seen with gcc 7.3.0. Export the missing symbols. Fixes: 2fc8483fdcde ("nios2: Build infrastructure") Signed-off-by: Guenter Roeck Signed-off-by: Ley Foon Tan Signed-off-by: Sasha Levin --- arch/nios2/kernel/nios2_ksyms.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/nios2/kernel/nios2_ksyms.c b/arch/nios2/kernel/nios2_ksyms.c index bf2f55d10a4d..4e704046a150 100644 --- a/arch/nios2/kernel/nios2_ksyms.c +++ b/arch/nios2/kernel/nios2_ksyms.c @@ -9,12 +9,20 @@ #include #include +#include +#include + /* string functions */ EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memmove); +/* memory management */ + +EXPORT_SYMBOL(empty_zero_page); +EXPORT_SYMBOL(flush_icache_range); + /* * libgcc functions - functions that are used internally by the * compiler... (prototypes are not correct though, but that @@ -31,3 +39,7 @@ DECLARE_EXPORT(__udivsi3); DECLARE_EXPORT(__umoddi3); DECLARE_EXPORT(__umodsi3); DECLARE_EXPORT(__muldi3); +DECLARE_EXPORT(__ucmpdi2); +DECLARE_EXPORT(__lshrdi3); +DECLARE_EXPORT(__ashldi3); +DECLARE_EXPORT(__ashrdi3); -- GitLab From ba0c43da8f5d7cb2942ccf2780ad9c67ed7ba042 Mon Sep 17 00:00:00 2001 From: Qian Cai Date: Thu, 28 Feb 2019 17:01:55 -0500 Subject: [PATCH 0434/1055] x86/mm: Remove unused variable 'cpu' [ Upstream commit 3609e31bc8dc03b701390f79c74fc7fe92b95039 ] The commit a2055abe9c67 ("x86/mm: Pass flush_tlb_info to flush_tlb_others() etc") removed the unnecessary cpu parameter from uv_flush_tlb_others() but left an unused variable. arch/x86/mm/tlb.c: In function 'native_flush_tlb_others': arch/x86/mm/tlb.c:688:16: warning: variable 'cpu' set but not used [-Wunused-but-set-variable] unsigned int cpu; ^~~ Fixes: a2055abe9c67 ("x86/mm: Pass flush_tlb_info to flush_tlb_others() etc") Signed-off-by: Qian Cai Signed-off-by: Thomas Gleixner Acked-by: Andyt Lutomirski Cc: dave.hansen@linux.intel.com Cc: peterz@infradead.org Cc: bp@alien8.de Cc: hpa@zytor.com Link: https://lkml.kernel.org/r/20190228220155.88124-1-cai@lca.pw Signed-off-by: Sasha Levin --- arch/x86/mm/tlb.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 5400a24e1a8c..c5d7b4ae17ca 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -651,9 +651,6 @@ void native_flush_tlb_others(const struct cpumask *cpumask, * that UV should be updated so that smp_call_function_many(), * etc, are optimal on UV. */ - unsigned int cpu; - - cpu = smp_processor_id(); cpumask = uv_flush_tlb_others(cpumask, info); if (cpumask) smp_call_function_many(cpumask, flush_tlb_func_remote, -- GitLab From d6bf70766f60c396a8e4cb3ff0385cca93a4b1c9 Mon Sep 17 00:00:00 2001 From: Steve Sistare Date: Fri, 1 Mar 2019 06:46:28 -0800 Subject: [PATCH 0435/1055] scsi: megaraid_sas: reduce module load time [ Upstream commit 31b6a05f86e690e1818116fd23c3be915cc9d9ed ] megaraid_sas takes 1+ seconds to load while waiting for firmware: [2.822603] megaraid_sas 0000:03:00.0: Waiting for FW to come to ready state [3.871003] megaraid_sas 0000:03:00.0: FW now in Ready state This is due to the following loop in megasas_transition_to_ready(), which waits a minimum of 1 second, even though the FW becomes ready in tens of millisecs: /* * The cur_state should not last for more than max_wait secs */ for (i = 0; i < max_wait; i++) { ... msleep(1000); ... dev_info(&instance->pdev->dev, "FW now in Ready state\n"); This is a regression, caused by a change of the msleep granularity from 1 to 1000 due to concern about waiting too long on systems with coarse jiffies. To fix, increase iterations and use msleep(20), which results in: [2.670627] megaraid_sas 0000:03:00.0: Waiting for FW to come to ready state [2.739386] megaraid_sas 0000:03:00.0: FW now in Ready state Fixes: fb2f3e96d80f ("scsi: megaraid_sas: Fix msleep granularity") Signed-off-by: Steve Sistare Acked-by: Sumit Saxena Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/megaraid/megaraid_sas_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 577513649afb..6abad63b127a 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3823,12 +3823,12 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) /* * The cur_state should not last for more than max_wait secs */ - for (i = 0; i < max_wait; i++) { + for (i = 0; i < max_wait * 50; i++) { curr_abs_state = instance->instancet-> read_fw_status_reg(instance->reg_set); if (abs_state == curr_abs_state) { - msleep(1000); + msleep(20); } else break; } -- GitLab From 5ba5c4da88ae802ba8f43710d2965aa0ecba6492 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 7 Mar 2019 16:29:33 -0800 Subject: [PATCH 0436/1055] drivers/rapidio/rio_cm.c: fix potential oops in riocm_ch_listen() [ Upstream commit 5ac188b12e7cbdd92dee60877d1fac913fc1d074 ] If riocm_get_channel() fails, then we should just return -EINVAL. Calling riocm_put_channel() will trigger a NULL dereference and generally we should call put() if the get() didn't succeed. Link: http://lkml.kernel.org/r/20190110130230.GB27017@kadam Fixes: b6e8d4aa1110 ("rapidio: add RapidIO channelized messaging driver") Signed-off-by: Dan Carpenter Reviewed-by: Andrew Morton Cc: Matt Porter Cc: Alexandre Bounine Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- drivers/rapidio/rio_cm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/rapidio/rio_cm.c b/drivers/rapidio/rio_cm.c index ef989a15aefc..b29fc258eeba 100644 --- a/drivers/rapidio/rio_cm.c +++ b/drivers/rapidio/rio_cm.c @@ -1215,7 +1215,9 @@ static int riocm_ch_listen(u16 ch_id) riocm_debug(CHOP, "(ch_%d)", ch_id); ch = riocm_get_channel(ch_id); - if (!ch || !riocm_cmp_exch(ch, RIO_CM_CHAN_BOUND, RIO_CM_LISTEN)) + if (!ch) + return -EINVAL; + if (!riocm_cmp_exch(ch, RIO_CM_CHAN_BOUND, RIO_CM_LISTEN)) ret = -EINVAL; riocm_put_channel(ch); return ret; -- GitLab From 2cd5e08b9af2b40ca7537ec2c66f1459cd95ad8b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 7 Mar 2019 08:41:22 +0300 Subject: [PATCH 0437/1055] xen, cpu_hotplug: Prevent an out of bounds access [ Upstream commit 201676095dda7e5b31a5e1d116d10fc22985075e ] The "cpu" variable comes from the sscanf() so Smatch marks it as untrusted data. We can't pass a higher value than "nr_cpu_ids" to cpu_possible() or it results in an out of bounds access. Fixes: d68d82afd4c8 ("xen: implement CPU hotplugging") Signed-off-by: Dan Carpenter Reviewed-by: Juergen Gross Signed-off-by: Juergen Gross Signed-off-by: Sasha Levin --- drivers/xen/cpu_hotplug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c index b1357aa4bc55..f192b6f42da9 100644 --- a/drivers/xen/cpu_hotplug.c +++ b/drivers/xen/cpu_hotplug.c @@ -54,7 +54,7 @@ static int vcpu_online(unsigned int cpu) } static void vcpu_hotplug(unsigned int cpu) { - if (!cpu_possible(cpu)) + if (cpu >= nr_cpu_ids || !cpu_possible(cpu)) return; switch (vcpu_online(cpu)) { -- GitLab From 9ef50cb11df1163b45ac989df6b235a09a42c772 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Tue, 12 Mar 2019 02:43:18 -0500 Subject: [PATCH 0438/1055] net: sh_eth: fix a missing check of of_get_phy_mode [ Upstream commit 035a14e71f27eefa50087963b94cbdb3580d08bf ] of_get_phy_mode may fail and return a negative error code; the fix checks the return value of of_get_phy_mode and returns NULL of it fails. Fixes: b356e978e92f ("sh_eth: add device tree support") Signed-off-by: Kangjie Lu Reviewed-by: Sergei Shtylyov Reviewed-by: Geert Uytterhoeven Tested-by: Geert Uytterhoeven Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/renesas/sh_eth.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 9b1906a65e11..25f3b2ad26e9 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -3046,12 +3046,16 @@ static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev) struct device_node *np = dev->of_node; struct sh_eth_plat_data *pdata; const char *mac_addr; + int ret; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return NULL; - pdata->phy_interface = of_get_phy_mode(np); + ret = of_get_phy_mode(np); + if (ret < 0) + return NULL; + pdata->phy_interface = ret; mac_addr = of_get_mac_address(np); if (mac_addr) -- GitLab From d0d7c1cbd50bc1d32e37ea9b92c30b66075979b5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 1 Mar 2019 14:16:40 +0800 Subject: [PATCH 0439/1055] regulator: lp87565: Fix missing register for LP87565_BUCK_0 [ Upstream commit d1a6cbdf1e597917cb642c655512d91b71a35d22 ] LP87565_BUCK_0 is missed, fix it. Fixes: f0168a9bf ("regulator: lp87565: Add support for lp87565 PMIC regulators") Signed-off-by: Axel Lin Reviewed-by: Keerthy Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/regulator/lp87565-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/lp87565-regulator.c b/drivers/regulator/lp87565-regulator.c index cfdbe294fb6a..32d4e6ec2e19 100644 --- a/drivers/regulator/lp87565-regulator.c +++ b/drivers/regulator/lp87565-regulator.c @@ -188,7 +188,7 @@ static int lp87565_regulator_probe(struct platform_device *pdev) struct lp87565 *lp87565 = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; struct regulator_dev *rdev; - int i, min_idx = LP87565_BUCK_1, max_idx = LP87565_BUCK_3; + int i, min_idx = LP87565_BUCK_0, max_idx = LP87565_BUCK_3; platform_set_drvdata(pdev, lp87565); -- GitLab From b9ce28072898cafd5a06ac7a7b29c2827ae7125b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 22 Feb 2019 01:36:41 -0500 Subject: [PATCH 0440/1055] media: ivtv: update *pos correctly in ivtv_read_pos() [ Upstream commit f8e579f3ca0973daef263f513da5edff520a6c0d ] We had intended to update *pos, but the current code is a no-op. Fixes: 1a0adaf37c30 ("V4L/DVB (5345): ivtv driver for Conexant cx23416/cx23415 MPEG encoder/decoder") Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/pci/ivtv/ivtv-fileops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c index c9bd018e53de..e2b19c3eaa87 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.c +++ b/drivers/media/pci/ivtv/ivtv-fileops.c @@ -420,7 +420,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); if (rc > 0) - pos += rc; + *pos += rc; return rc; } -- GitLab From 6ae3b318c93ee18af1144fb11df995ba7bd7a190 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 22 Feb 2019 01:37:02 -0500 Subject: [PATCH 0441/1055] media: cx18: update *pos correctly in cx18_read_pos() [ Upstream commit 7afb0df554292dca7568446f619965fb8153085d ] We should be updating *pos. The current code is a no-op. Fixes: 1c1e45d17b66 ("V4L/DVB (7786): cx18: new driver for the Conexant CX23418 MPEG encoder chip") Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/pci/cx18/cx18-fileops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index 98467b2089fa..099d59b992c1 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -484,7 +484,7 @@ static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf, CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); if (rc > 0) - pos += rc; + *pos += rc; return rc; } -- GitLab From 8d53d5a2de14502ff1a62764e67568a68a558f1b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 6 Mar 2019 02:27:43 -0500 Subject: [PATCH 0442/1055] media: wl128x: Fix an error code in fm_download_firmware() [ Upstream commit ef4bb63dc1f7213c08e13f6943c69cd27f69e4a3 ] We forgot to set "ret" on this error path. Fixes: e8454ff7b9a4 ("[media] drivers:media:radio: wl128x: FM Driver Common sources") Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/radio/wl128x/fmdrv_common.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 26895ae42fcf..2d20d908e280 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -1271,8 +1271,9 @@ static int fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) switch (action->type) { case ACTION_SEND_COMMAND: /* Send */ - if (fmc_send_cmd(fmdev, 0, 0, action->data, - action->size, NULL, NULL)) + ret = fmc_send_cmd(fmdev, 0, 0, action->data, + action->size, NULL, NULL); + if (ret) goto rel_fw; cmd_cnt++; -- GitLab From 8f51a1bbe9fecdd7f7bdf7e58287bc0beda5d404 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sat, 19 Jan 2019 22:52:23 -0500 Subject: [PATCH 0443/1055] media: cx23885: check allocation return [ Upstream commit a3d7f22ef34ec4206b50ee121384d5c8bebd5591 ] Checking of kmalloc() seems to have been committed - as cx23885_dvb_register() is checking for != 0 return, returning -ENOMEM should be fine here. While at it address the coccicheck suggestion to move to kmemdup rather than using kmalloc+memcpy. Fixes: 46b21bbaa8a8 ("[media] Add support for DViCO FusionHDTV DVB-T Dual Express2") Signed-off-by: Nicholas Mc Guire Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/pci/cx23885/cx23885-dvb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index e795ddeb7fe2..60f122edaefb 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -1460,8 +1460,9 @@ static int dvb_register(struct cx23885_tsport *port) if (fe0->dvb.frontend != NULL) { struct i2c_adapter *tun_i2c; - fe0->dvb.frontend->sec_priv = kmalloc(sizeof(dib7000p_ops), GFP_KERNEL); - memcpy(fe0->dvb.frontend->sec_priv, &dib7000p_ops, sizeof(dib7000p_ops)); + fe0->dvb.frontend->sec_priv = kmemdup(&dib7000p_ops, sizeof(dib7000p_ops), GFP_KERNEL); + if (!fe0->dvb.frontend->sec_priv) + return -ENOMEM; tun_i2c = dib7000p_ops.get_i2c_master(fe0->dvb.frontend, DIBX000_I2C_INTERFACE_TUNER, 1); if (!dvb_attach(dib0070_attach, fe0->dvb.frontend, tun_i2c, &dib7070p_dib0070_config)) return -ENODEV; -- GitLab From 96ef352408a62a567c38b02b39bb87a5efb4c375 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 4 Mar 2019 16:57:52 +0800 Subject: [PATCH 0444/1055] regulator: tps65086: Fix tps65086_ldoa1_ranges for selector 0xB [ Upstream commit e69b394703e032e56a140172440ec4f9890b536d ] selector 0xB (1011) should be 2.6V rather than 2.7V, fit ix. Table 5-4. LDOA1 Output Voltage Options VID Bits VOUT VID Bits VOUT VID Bits VOUT VID Bits VOUT 0000 1.35 0100 1.8 1000 2.3 1100 2.85 0001 1.5 0101 1.9 1001 2.4 1101 3.0 0010 1.6 0110 2.0 1010 2.5 1110 3.3 0011 1.7 0111 2.1 1011 2.6 1111 Not Used Fixes: d2a2e729a666 ("regulator: tps65086: Add regulator driver for the TPS65086 PMIC") Signed-off-by: Axel Lin Acked-by: Andrew F. Davis Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/regulator/tps65086-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/tps65086-regulator.c b/drivers/regulator/tps65086-regulator.c index 45e96e154690..5a5e9b5bf4be 100644 --- a/drivers/regulator/tps65086-regulator.c +++ b/drivers/regulator/tps65086-regulator.c @@ -90,8 +90,8 @@ static const struct regulator_linear_range tps65086_buck345_25mv_ranges[] = { static const struct regulator_linear_range tps65086_ldoa1_ranges[] = { REGULATOR_LINEAR_RANGE(1350000, 0x0, 0x0, 0), REGULATOR_LINEAR_RANGE(1500000, 0x1, 0x7, 100000), - REGULATOR_LINEAR_RANGE(2300000, 0x8, 0xA, 100000), - REGULATOR_LINEAR_RANGE(2700000, 0xB, 0xD, 150000), + REGULATOR_LINEAR_RANGE(2300000, 0x8, 0xB, 100000), + REGULATOR_LINEAR_RANGE(2850000, 0xC, 0xD, 150000), REGULATOR_LINEAR_RANGE(3300000, 0xE, 0xE, 0), }; -- GitLab From a2f301a5a385581a38e740379126a3800417924c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 22 Mar 2019 15:19:16 +0100 Subject: [PATCH 0445/1055] jfs: fix bogus variable self-initialization [ Upstream commit a5fdd713d256887b5f012608701149fa939e5645 ] A statement was originally added in 2006 to shut up a gcc warning, now but now clang warns about it: fs/jfs/jfs_txnmgr.c:1932:15: error: variable 'pxd' is uninitialized when used within its own initialization [-Werror,-Wuninitialized] pxd_t pxd = pxd; /* truncated extent of xad */ ~~~ ^~~ Modern versions of gcc are fine without the silly assignment, so just drop it. Tested with gcc-4.6 (released 2011), 4.7, 4.8, and 4.9. Fixes: c9e3ad6021e5 ("JFS: Get rid of "may be used uninitialized" warnings") Signed-off-by: Arnd Bergmann Signed-off-by: Dave Kleikamp Signed-off-by: Sasha Levin --- fs/jfs/jfs_txnmgr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index 4d973524c887..224ef034004b 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -1928,8 +1928,7 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, * header ? */ if (tlck->type & tlckTRUNCATE) { - /* This odd declaration suppresses a bogus gcc warning */ - pxd_t pxd = pxd; /* truncated extent of xad */ + pxd_t pxd; /* truncated extent of xad */ int twm; /* -- GitLab From 34bb4eab1942bc1d54e4d14a8ddfc3be7904fe6e Mon Sep 17 00:00:00 2001 From: Jon Maloy Date: Fri, 22 Mar 2019 15:03:51 +0100 Subject: [PATCH 0446/1055] tipc: tipc clang warning [ Upstream commit 737889efe9713a0f20a75fd0de952841d9275e6b ] When checking the code with clang -Wsometimes-uninitialized we get the following warning: if (!tipc_link_is_establishing(l)) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ net/tipc/node.c:847:46: note: uninitialized use occurs here tipc_bearer_xmit(n->net, bearer_id, &xmitq, maddr); net/tipc/node.c:831:2: note: remove the 'if' if its condition is always true if (!tipc_link_is_establishing(l)) { ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ net/tipc/node.c:821:31: note: initialize the variable 'maddr' to silence this warning struct tipc_media_addr *maddr; We fix this by initializing 'maddr' to NULL. For the matter of clarity, we also test if 'xmitq' is non-empty before we use it and 'maddr' further down in the function. It will never happen that 'xmitq' is non- empty at the same time as 'maddr' is NULL, so this is a sufficient test. Fixes: 598411d70f85 ("tipc: make resetting of links non-atomic") Reported-by: Nathan Chancellor Signed-off-by: Jon Maloy Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/tipc/node.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/tipc/node.c b/net/tipc/node.c index 42e9bdcc4bb6..82f8f69f4d6b 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -688,10 +688,10 @@ static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id, static void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete) { struct tipc_link_entry *le = &n->links[bearer_id]; + struct tipc_media_addr *maddr = NULL; struct tipc_link *l = le->link; - struct tipc_media_addr *maddr; - struct sk_buff_head xmitq; int old_bearer_id = bearer_id; + struct sk_buff_head xmitq; if (!l) return; @@ -713,7 +713,8 @@ static void tipc_node_link_down(struct tipc_node *n, int bearer_id, bool delete) tipc_node_write_unlock(n); if (delete) tipc_mon_remove_peer(n->net, n->addr, old_bearer_id); - tipc_bearer_xmit(n->net, bearer_id, &xmitq, maddr); + if (!skb_queue_empty(&xmitq)) + tipc_bearer_xmit(n->net, bearer_id, &xmitq, maddr); tipc_sk_rcv(n->net, &le->inputq); } -- GitLab From 5bd4bd3e35d156dda9c0da69ebdef0e83c3dd360 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sat, 1 Dec 2018 11:53:10 +1100 Subject: [PATCH 0447/1055] m68k: mac: Fix VIA timer counter accesses [ Upstream commit 0ca7ce7db771580433bf24454f7a1542bd326078 ] This resolves some bugs that affect VIA timer counter accesses. Avoid lost interrupts caused by reading the counter low byte register. Make allowance for the fact that the counter will be decremented to 0xFFFF before being reloaded. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Finn Thain Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- arch/m68k/mac/via.c | 102 +++++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 49 deletions(-) diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index 9f59a662ace5..7334245abf26 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -54,16 +54,6 @@ static __u8 rbv_clear; static int gIER,gIFR,gBufA,gBufB; -/* - * Timer defs. - */ - -#define TICK_SIZE 10000 -#define MAC_CLOCK_TICK (783300/HZ) /* ticks per HZ */ -#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) -#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) - - /* * On Macs with a genuine VIA chip there is no way to mask an individual slot * interrupt. This limitation also seems to apply to VIA clone logic cores in @@ -278,22 +268,6 @@ void __init via_init(void) } } -/* - * Start the 100 Hz clock - */ - -void __init via_init_clock(irq_handler_t func) -{ - via1[vACR] |= 0x40; - via1[vT1LL] = MAC_CLOCK_LOW; - via1[vT1LH] = MAC_CLOCK_HIGH; - via1[vT1CL] = MAC_CLOCK_LOW; - via1[vT1CH] = MAC_CLOCK_HIGH; - - if (request_irq(IRQ_MAC_TIMER_1, func, 0, "timer", func)) - pr_err("Couldn't register %s interrupt\n", "timer"); -} - /* * Debugging dump, used in various places to see what's going on. */ @@ -321,29 +295,6 @@ void via_debug_dump(void) } } -/* - * This is always executed with interrupts disabled. - * - * TBI: get time offset between scheduling timer ticks - */ - -u32 mac_gettimeoffset(void) -{ - unsigned long ticks, offset = 0; - - /* read VIA1 timer 2 current value */ - ticks = via1[vT1CL] | (via1[vT1CH] << 8); - /* The probability of underflow is less than 2% */ - if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50) - /* Check for pending timer interrupt in VIA1 IFR */ - if (via1[vIFR] & 0x40) offset = TICK_SIZE; - - ticks = MAC_CLOCK_TICK - ticks; - ticks = ticks * 10000L / MAC_CLOCK_TICK; - - return (ticks + offset) * 1000; -} - /* * Flush the L2 cache on Macs that have it by flipping * the system into 24-bit mode for an instant. @@ -612,3 +563,56 @@ int via2_scsi_drq_pending(void) return via2[gIFR] & (1 << IRQ_IDX(IRQ_MAC_SCSIDRQ)); } EXPORT_SYMBOL(via2_scsi_drq_pending); + +/* timer and clock source */ + +#define VIA_CLOCK_FREQ 783360 /* VIA "phase 2" clock in Hz */ +#define VIA_TIMER_INTERVAL (1000000 / HZ) /* microseconds per jiffy */ +#define VIA_TIMER_CYCLES (VIA_CLOCK_FREQ / HZ) /* clock cycles per jiffy */ + +#define VIA_TC (VIA_TIMER_CYCLES - 2) /* including 0 and -1 */ +#define VIA_TC_LOW (VIA_TC & 0xFF) +#define VIA_TC_HIGH (VIA_TC >> 8) + +void __init via_init_clock(irq_handler_t timer_routine) +{ + if (request_irq(IRQ_MAC_TIMER_1, timer_routine, 0, "timer", NULL)) { + pr_err("Couldn't register %s interrupt\n", "timer"); + return; + } + + via1[vT1LL] = VIA_TC_LOW; + via1[vT1LH] = VIA_TC_HIGH; + via1[vT1CL] = VIA_TC_LOW; + via1[vT1CH] = VIA_TC_HIGH; + via1[vACR] |= 0x40; +} + +u32 mac_gettimeoffset(void) +{ + unsigned long flags; + u8 count_high; + u16 count, offset = 0; + + /* + * Timer counter wrap-around is detected with the timer interrupt flag + * but reading the counter low byte (vT1CL) would reset the flag. + * Also, accessing both counter registers is essentially a data race. + * These problems are avoided by ignoring the low byte. Clock accuracy + * is 256 times worse (error can reach 0.327 ms) but CPU overhead is + * reduced by avoiding slow VIA register accesses. + */ + + local_irq_save(flags); + count_high = via1[vT1CH]; + if (count_high == 0xFF) + count_high = 0; + if (count_high > 0 && (via1[vIFR] & VIA_TIMER_1_INT)) + offset = VIA_TIMER_CYCLES; + local_irq_restore(flags); + + count = count_high << 8; + count = VIA_TIMER_CYCLES - count + offset; + + return ((count * VIA_TIMER_INTERVAL) / VIA_TIMER_CYCLES) * 1000; +} -- GitLab From 9a8e28387cf4797860080bfeb09076540b4b4e53 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 25 Mar 2019 14:52:50 +0100 Subject: [PATCH 0448/1055] arm64: dts: allwinner: a64: Add missing PIO clocks [ Upstream commit 562bf19611c000cb7219431c3cc78aa60c2b371e ] The pinctrl binding mandates that we have the three clocks fed into the PIO described. Even though the old case is still supported for backward compatibility, we should update our DTs to fix this. Fixes: 6bc37fac30cf ("arm64: dts: add Allwinner A64 SoC .dtsi") Acked-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi index 8c8db1b057df..788a6f8c5994 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi @@ -274,7 +274,8 @@ interrupts = , , ; - clocks = <&ccu 58>; + clocks = <&ccu 58>, <&osc24M>, <&rtc 0>; + clock-names = "apb", "hosc", "losc"; gpio-controller; #gpio-cells = <3>; interrupt-controller; -- GitLab From 7ea5302d4890fa1fd2277f9514c633c4c6ab5354 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 21 Mar 2019 11:00:21 -0700 Subject: [PATCH 0449/1055] ARM: OMAP2+: Fix potentially uninitialized return value for _setup_reset() [ Upstream commit 7f0d078667a494466991aa7133f49594f32ff6a2 ] Commit 747834ab8347 ("ARM: OMAP2+: hwmod: revise hardreset behavior") made the call to _enable() conditional based on no oh->rst_lines_cnt. This caused the return value to be potentially uninitialized. Curiously we see no compiler warnings for this, probably as this gets inlined. We call _setup_reset() from _setup() and only _setup_postsetup() if the return value is zero. Currently the return value can be uninitialized for cases where oh->rst_lines_cnt is set and HWMOD_INIT_NO_RESET is not set. Fixes: 747834ab8347 ("ARM: OMAP2+: hwmod: revise hardreset behavior") Cc: Paul Walmsley Cc: Tero Kristo Signed-off-by: Tony Lindgren Signed-off-by: Sasha Levin --- arch/arm/mach-omap2/omap_hwmod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 45c8f2ef4e23..9274a484c6a3 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2530,7 +2530,7 @@ static void _setup_iclk_autoidle(struct omap_hwmod *oh) */ static int _setup_reset(struct omap_hwmod *oh) { - int r; + int r = 0; if (oh->_state != _HWMOD_STATE_INITIALIZED) return -EINVAL; -- GitLab From 9162cb9cf6d9ed5e3b8d0fd6cdae4048b008e645 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 22 Mar 2019 10:34:22 -0400 Subject: [PATCH 0450/1055] media: davinci-isif: avoid uninitialized variable use [ Upstream commit 0e633f97162c1c74c68e2eb20bbd9259dce87cd9 ] clang warns about a possible variable use that gcc never complained about: drivers/media/platform/davinci/isif.c:982:32: error: variable 'frame_size' is uninitialized when used here [-Werror,-Wuninitialized] dm365_vpss_set_pg_frame_size(frame_size); ^~~~~~~~~~ drivers/media/platform/davinci/isif.c:887:2: note: variable 'frame_size' is declared here struct vpss_pg_frame_size frame_size; ^ 1 error generated. There is no initialization for this variable at all, and there has never been one in the mainline kernel, so we really should not put that stack data into an mmio register. On the other hand, I suspect that gcc checks the condition more closely and notices that the global isif_cfg.bayer.config_params.test_pat_gen flag is initialized to zero and never written to from any code path, so anything depending on it can be eliminated. To shut up the clang warning, just remove the dead code manually, it has probably never been used because any attempt to do so would have resulted in undefined behavior. Fixes: 63e3ab142fa3 ("V4L/DVB: V4L - vpfe capture - source for ISIF driver on DM365") Signed-off-by: Arnd Bergmann Reviewed-by: Nathan Chancellor Acked-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/platform/davinci/isif.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c index 90d0f13283ae..12065ad1ac45 100644 --- a/drivers/media/platform/davinci/isif.c +++ b/drivers/media/platform/davinci/isif.c @@ -886,9 +886,7 @@ static int isif_set_hw_if_params(struct vpfe_hw_if_param *params) static int isif_config_ycbcr(void) { struct isif_ycbcr_config *params = &isif_cfg.ycbcr; - struct vpss_pg_frame_size frame_size; u32 modeset = 0, ccdcfg = 0; - struct vpss_sync_pol sync; dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr..."); @@ -976,13 +974,6 @@ static int isif_config_ycbcr(void) /* two fields are interleaved in memory */ regw(0x00000249, SDOFST); - /* Setup test pattern if enabled */ - if (isif_cfg.bayer.config_params.test_pat_gen) { - sync.ccdpg_hdpol = params->hd_pol; - sync.ccdpg_vdpol = params->vd_pol; - dm365_vpss_set_sync_pol(sync); - dm365_vpss_set_pg_frame_size(frame_size); - } return 0; } -- GitLab From f4c8d9e5ea524d7f53e54da2920a7d1250822ec5 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 14 Mar 2019 22:01:24 -0400 Subject: [PATCH 0451/1055] media: tw5864: Fix possible NULL pointer dereference in tw5864_handle_frame [ Upstream commit 2e7682ebfc750177a4944eeb56e97a3f05734528 ] 'vb' null check should be done before dereferencing it in tw5864_handle_frame, otherwise a NULL pointer dereference may occur. Fixes: 34d1324edd31 ("[media] pci: Add tw5864 driver") Signed-off-by: YueHaibing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/pci/tw5864/tw5864-video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c index e7bd2b8484e3..ee1230440b39 100644 --- a/drivers/media/pci/tw5864/tw5864-video.c +++ b/drivers/media/pci/tw5864/tw5864-video.c @@ -1395,13 +1395,13 @@ static void tw5864_handle_frame(struct tw5864_h264_frame *frame) input->vb = NULL; spin_unlock_irqrestore(&input->slock, flags); - v4l2_buf = to_vb2_v4l2_buffer(&vb->vb.vb2_buf); - if (!vb) { /* Gone because of disabling */ dev_dbg(&dev->pci->dev, "vb is empty, dropping frame\n"); return; } + v4l2_buf = to_vb2_v4l2_buffer(&vb->vb.vb2_buf); + /* * Check for space. * Mind the overhead of startcode emulation prevention. -- GitLab From 58ac2bc9ce809985c78bf4855dfa69e8505e6bfc Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Tue, 26 Mar 2019 22:56:23 -0700 Subject: [PATCH 0452/1055] spi: tegra114: clear packed bit for unpacked mode [ Upstream commit 7b3d10cdf54b8bc1dc0da21faed9789ac4da3684 ] Fixes: Clear packed bit when not using packed mode. Packed bit is not cleared when not using packed mode. This results in transfer timeouts for the unpacked mode transfers followed by the packed mode transfers. Signed-off-by: Sowjanya Komatineni Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-tegra114.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 2ad04796ef29..3a6b202dfffe 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -730,6 +730,8 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, if (tspi->is_packed) command1 |= SPI_PACKED; + else + command1 &= ~SPI_PACKED; command1 &= ~(SPI_CS_SEL_MASK | SPI_TX_EN | SPI_RX_EN); tspi->cur_direction = 0; -- GitLab From ffd39bb17e492dc878ed4b72201d115f7522a015 Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Tue, 26 Mar 2019 22:56:24 -0700 Subject: [PATCH 0453/1055] spi: tegra114: fix for unpacked mode transfers [ Upstream commit 1a89ac5b91895127f7c586ec5075c3753ca25501 ] Fixes: computation of actual bytes to fill/receive in/from FIFO in unpacked mode when transfer length is not a multiple of requested bits per word. unpacked mode transfers fails when the transfer includes partial bytes in the last word. Total words to be written/read to/from FIFO is computed based on transfer length and bits per word. Unpacked mode includes 0 padding bytes for partial words to align with bits per word and these extra bytes are also accounted for calculating bytes left to transfer in the current driver. This causes extra bytes access of tx/rx buffers along with buffer index position crossing actual length where remain_len becomes negative and due to unsigned type, negative value is a 32 bit representation of signed value and transferred bytes never meets the actual transfer length resulting in transfer timeout and a hang. This patch fixes this with proper computation of the actual bytes to fill in FIFO during transmit and the actual bytes to read from FIFO during receive ignoring 0 padded bytes. Signed-off-by: Sowjanya Komatineni Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-tegra114.c | 43 +++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 3a6b202dfffe..c6674b01e0fd 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -307,10 +307,16 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf( x |= (u32)(*tx_buf++) << (i * 8); tegra_spi_writel(tspi, x, SPI_TX_FIFO); } + + tspi->cur_tx_pos += written_words * tspi->bytes_per_word; } else { + unsigned int write_bytes; max_n_32bit = min(tspi->curr_dma_words, tx_empty_count); written_words = max_n_32bit; nbytes = written_words * tspi->bytes_per_word; + if (nbytes > t->len - tspi->cur_pos) + nbytes = t->len - tspi->cur_pos; + write_bytes = nbytes; for (count = 0; count < max_n_32bit; count++) { u32 x = 0; @@ -319,8 +325,10 @@ static unsigned tegra_spi_fill_tx_fifo_from_client_txbuf( x |= (u32)(*tx_buf++) << (i * 8); tegra_spi_writel(tspi, x, SPI_TX_FIFO); } + + tspi->cur_tx_pos += write_bytes; } - tspi->cur_tx_pos += written_words * tspi->bytes_per_word; + return written_words; } @@ -344,20 +352,27 @@ static unsigned int tegra_spi_read_rx_fifo_to_client_rxbuf( for (i = 0; len && (i < 4); i++, len--) *rx_buf++ = (x >> i*8) & 0xFF; } - tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word; read_words += tspi->curr_dma_words; + tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word; } else { u32 rx_mask = ((u32)1 << t->bits_per_word) - 1; + u8 bytes_per_word = tspi->bytes_per_word; + unsigned int read_bytes; + len = rx_full_count * bytes_per_word; + if (len > t->len - tspi->cur_pos) + len = t->len - tspi->cur_pos; + read_bytes = len; for (count = 0; count < rx_full_count; count++) { u32 x = tegra_spi_readl(tspi, SPI_RX_FIFO) & rx_mask; - for (i = 0; (i < tspi->bytes_per_word); i++) + for (i = 0; len && (i < bytes_per_word); i++, len--) *rx_buf++ = (x >> (i*8)) & 0xFF; } - tspi->cur_rx_pos += rx_full_count * tspi->bytes_per_word; read_words += rx_full_count; + tspi->cur_rx_pos += read_bytes; } + return read_words; } @@ -372,12 +387,17 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf( unsigned len = tspi->curr_dma_words * tspi->bytes_per_word; memcpy(tspi->tx_dma_buf, t->tx_buf + tspi->cur_pos, len); + tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word; } else { unsigned int i; unsigned int count; u8 *tx_buf = (u8 *)t->tx_buf + tspi->cur_tx_pos; unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word; + unsigned int write_bytes; + if (consume > t->len - tspi->cur_pos) + consume = t->len - tspi->cur_pos; + write_bytes = consume; for (count = 0; count < tspi->curr_dma_words; count++) { u32 x = 0; @@ -386,8 +406,9 @@ static void tegra_spi_copy_client_txbuf_to_spi_txbuf( x |= (u32)(*tx_buf++) << (i * 8); tspi->tx_dma_buf[count] = x; } + + tspi->cur_tx_pos += write_bytes; } - tspi->cur_tx_pos += tspi->curr_dma_words * tspi->bytes_per_word; /* Make the dma buffer to read by dma */ dma_sync_single_for_device(tspi->dev, tspi->tx_dma_phys, @@ -405,20 +426,28 @@ static void tegra_spi_copy_spi_rxbuf_to_client_rxbuf( unsigned len = tspi->curr_dma_words * tspi->bytes_per_word; memcpy(t->rx_buf + tspi->cur_rx_pos, tspi->rx_dma_buf, len); + tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word; } else { unsigned int i; unsigned int count; unsigned char *rx_buf = t->rx_buf + tspi->cur_rx_pos; u32 rx_mask = ((u32)1 << t->bits_per_word) - 1; + unsigned consume = tspi->curr_dma_words * tspi->bytes_per_word; + unsigned int read_bytes; + if (consume > t->len - tspi->cur_pos) + consume = t->len - tspi->cur_pos; + read_bytes = consume; for (count = 0; count < tspi->curr_dma_words; count++) { u32 x = tspi->rx_dma_buf[count] & rx_mask; - for (i = 0; (i < tspi->bytes_per_word); i++) + for (i = 0; consume && (i < tspi->bytes_per_word); + i++, consume--) *rx_buf++ = (x >> (i*8)) & 0xFF; } + + tspi->cur_rx_pos += read_bytes; } - tspi->cur_rx_pos += tspi->curr_dma_words * tspi->bytes_per_word; /* Make the dma buffer to read by dma */ dma_sync_single_for_device(tspi->dev, tspi->rx_dma_phys, -- GitLab From f24affc80580feff6a7517f8f716cfff04b63740 Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Tue, 26 Mar 2019 22:56:27 -0700 Subject: [PATCH 0454/1055] spi: tegra114: terminate dma and reset on transfer timeout [ Upstream commit 32bd1a9551cae34e6889afa235c7afdfede9aeac ] Fixes: terminate DMA and perform controller reset on transfer timeout to clear the FIFO's and errors. Signed-off-by: Sowjanya Komatineni Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-tegra114.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index c6674b01e0fd..4878d5e00c66 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -869,7 +869,16 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, if (WARN_ON(ret == 0)) { dev_err(tspi->dev, "spi transfer timeout, err %d\n", ret); + if (tspi->is_curr_dma_xfer && + (tspi->cur_direction & DATA_DIR_TX)) + dmaengine_terminate_all(tspi->tx_dma_chan); + if (tspi->is_curr_dma_xfer && + (tspi->cur_direction & DATA_DIR_RX)) + dmaengine_terminate_all(tspi->rx_dma_chan); ret = -EIO; + reset_control_assert(tspi->rst); + udelay(2); + reset_control_deassert(tspi->rst); goto complete_xfer; } -- GitLab From 938f5d5d4802b99fcca2ae846f73e16cd77740ab Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Tue, 26 Mar 2019 22:56:28 -0700 Subject: [PATCH 0455/1055] spi: tegra114: flush fifos [ Upstream commit c4fc9e5b28ff787e35137c2cc13316bb11d7657b ] Fixes: Flush TX and RX FIFOs before start of new transfer and on FIFO overflow or underrun errors. Signed-off-by: Sowjanya Komatineni Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-tegra114.c | 39 +++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 4878d5e00c66..18dfbd57c61f 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -499,22 +499,37 @@ static int tegra_spi_start_rx_dma(struct tegra_spi_data *tspi, int len) return 0; } -static int tegra_spi_start_dma_based_transfer( - struct tegra_spi_data *tspi, struct spi_transfer *t) +static int tegra_spi_flush_fifos(struct tegra_spi_data *tspi) { - u32 val; - unsigned int len; - int ret = 0; + unsigned long timeout = jiffies + HZ; u32 status; - /* Make sure that Rx and Tx fifo are empty */ status = tegra_spi_readl(tspi, SPI_FIFO_STATUS); if ((status & SPI_FIFO_EMPTY) != SPI_FIFO_EMPTY) { - dev_err(tspi->dev, "Rx/Tx fifo are not empty status 0x%08x\n", - (unsigned)status); - return -EIO; + status |= SPI_RX_FIFO_FLUSH | SPI_TX_FIFO_FLUSH; + tegra_spi_writel(tspi, status, SPI_FIFO_STATUS); + while ((status & SPI_FIFO_EMPTY) != SPI_FIFO_EMPTY) { + status = tegra_spi_readl(tspi, SPI_FIFO_STATUS); + if (time_after(jiffies, timeout)) { + dev_err(tspi->dev, + "timeout waiting for fifo flush\n"); + return -EIO; + } + + udelay(1); + } } + return 0; +} + +static int tegra_spi_start_dma_based_transfer( + struct tegra_spi_data *tspi, struct spi_transfer *t) +{ + u32 val; + unsigned int len; + int ret = 0; + val = SPI_DMA_BLK_SET(tspi->curr_dma_words - 1); tegra_spi_writel(tspi, val, SPI_DMA_BLK); @@ -779,6 +794,9 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, dev_dbg(tspi->dev, "The def 0x%x and written 0x%x\n", tspi->def_command1_reg, (unsigned)command1); + ret = tegra_spi_flush_fifos(tspi); + if (ret < 0) + return ret; if (total_fifo_words > SPI_FIFO_DEPTH) ret = tegra_spi_start_dma_based_transfer(tspi, t); else @@ -876,6 +894,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, (tspi->cur_direction & DATA_DIR_RX)) dmaengine_terminate_all(tspi->rx_dma_chan); ret = -EIO; + tegra_spi_flush_fifos(tspi); reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); @@ -929,6 +948,7 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_spi_data *tspi) tspi->status_reg); dev_err(tspi->dev, "CpuXfer 0x%08x:0x%08x\n", tspi->command1_reg, tspi->dma_control_reg); + tegra_spi_flush_fifos(tspi); reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); @@ -1001,6 +1021,7 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_spi_data *tspi) tspi->status_reg); dev_err(tspi->dev, "DmaXfer 0x%08x:0x%08x\n", tspi->command1_reg, tspi->dma_control_reg); + tegra_spi_flush_fifos(tspi); reset_control_assert(tspi->rst); udelay(2); reset_control_deassert(tspi->rst); -- GitLab From bd9f7b6a0a4ffe6ff00454085c4f0abef44d221f Mon Sep 17 00:00:00 2001 From: Sowjanya Komatineni Date: Tue, 26 Mar 2019 22:56:29 -0700 Subject: [PATCH 0456/1055] spi: tegra114: configure dma burst size to fifo trig level [ Upstream commit f4ce428c41fb22e3ed55496dded94df44cb920fa ] Fixes: Configure DMA burst size to be same as SPI TX/RX trigger levels to avoid mismatch. SPI FIFO trigger levels are calculated based on the transfer length. So this patch moves DMA slave configuration to happen before start of DMAs. Signed-off-by: Sowjanya Komatineni Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-tegra114.c | 52 ++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 18dfbd57c61f..84ff0c507f0b 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -529,6 +529,8 @@ static int tegra_spi_start_dma_based_transfer( u32 val; unsigned int len; int ret = 0; + u8 dma_burst; + struct dma_slave_config dma_sconfig = {0}; val = SPI_DMA_BLK_SET(tspi->curr_dma_words - 1); tegra_spi_writel(tspi, val, SPI_DMA_BLK); @@ -540,12 +542,16 @@ static int tegra_spi_start_dma_based_transfer( len = tspi->curr_dma_words * 4; /* Set attention level based on length of transfer */ - if (len & 0xF) + if (len & 0xF) { val |= SPI_TX_TRIG_1 | SPI_RX_TRIG_1; - else if (((len) >> 4) & 0x1) + dma_burst = 1; + } else if (((len) >> 4) & 0x1) { val |= SPI_TX_TRIG_4 | SPI_RX_TRIG_4; - else + dma_burst = 4; + } else { val |= SPI_TX_TRIG_8 | SPI_RX_TRIG_8; + dma_burst = 8; + } if (tspi->cur_direction & DATA_DIR_TX) val |= SPI_IE_TX; @@ -556,7 +562,18 @@ static int tegra_spi_start_dma_based_transfer( tegra_spi_writel(tspi, val, SPI_DMA_CTL); tspi->dma_control_reg = val; + dma_sconfig.device_fc = true; if (tspi->cur_direction & DATA_DIR_TX) { + dma_sconfig.dst_addr = tspi->phys + SPI_TX_FIFO; + dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + dma_sconfig.dst_maxburst = dma_burst; + ret = dmaengine_slave_config(tspi->tx_dma_chan, &dma_sconfig); + if (ret < 0) { + dev_err(tspi->dev, + "DMA slave config failed: %d\n", ret); + return ret; + } + tegra_spi_copy_client_txbuf_to_spi_txbuf(tspi, t); ret = tegra_spi_start_tx_dma(tspi, len); if (ret < 0) { @@ -567,6 +584,16 @@ static int tegra_spi_start_dma_based_transfer( } if (tspi->cur_direction & DATA_DIR_RX) { + dma_sconfig.src_addr = tspi->phys + SPI_RX_FIFO; + dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + dma_sconfig.src_maxburst = dma_burst; + ret = dmaengine_slave_config(tspi->rx_dma_chan, &dma_sconfig); + if (ret < 0) { + dev_err(tspi->dev, + "DMA slave config failed: %d\n", ret); + return ret; + } + /* Make the dma buffer to read by dma */ dma_sync_single_for_device(tspi->dev, tspi->rx_dma_phys, tspi->dma_buf_size, DMA_FROM_DEVICE); @@ -626,7 +653,6 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi, u32 *dma_buf; dma_addr_t dma_phys; int ret; - struct dma_slave_config dma_sconfig; dma_chan = dma_request_slave_channel_reason(tspi->dev, dma_to_memory ? "rx" : "tx"); @@ -646,19 +672,6 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi, return -ENOMEM; } - if (dma_to_memory) { - dma_sconfig.src_addr = tspi->phys + SPI_RX_FIFO; - dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dma_sconfig.src_maxburst = 0; - } else { - dma_sconfig.dst_addr = tspi->phys + SPI_TX_FIFO; - dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dma_sconfig.dst_maxburst = 0; - } - - ret = dmaengine_slave_config(dma_chan, &dma_sconfig); - if (ret) - goto scrub; if (dma_to_memory) { tspi->rx_dma_chan = dma_chan; tspi->rx_dma_buf = dma_buf; @@ -669,11 +682,6 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi, tspi->tx_dma_phys = dma_phys; } return 0; - -scrub: - dma_free_coherent(tspi->dev, tspi->dma_buf_size, dma_buf, dma_phys); - dma_release_channel(dma_chan); - return ret; } static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi, -- GitLab From a96770dea1ba612fe7210bd7ad1dfa6b86ca948b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 28 Mar 2019 17:18:41 +0300 Subject: [PATCH 0457/1055] soc/fsl/qe: Fix an error code in qe_pin_request() [ Upstream commit 5674a92ca4b7e5a6a19231edd10298d30324cd27 ] We forgot to set "err" on this error path. Fixes: 1a2d397a6eb5 ("gpio/powerpc: Eliminate duplication of of_get_named_gpio_flags()") Signed-off-by: Dan Carpenter Signed-off-by: Li Yang Signed-off-by: Sasha Levin --- drivers/soc/fsl/qe/gpio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c index 3b27075c21a7..5cbc5ce5ac15 100644 --- a/drivers/soc/fsl/qe/gpio.c +++ b/drivers/soc/fsl/qe/gpio.c @@ -152,8 +152,10 @@ struct qe_pin *qe_pin_request(struct device_node *np, int index) if (err < 0) goto err0; gc = gpio_to_chip(err); - if (WARN_ON(!gc)) + if (WARN_ON(!gc)) { + err = -ENODEV; goto err0; + } if (!of_device_is_compatible(gc->of_node, "fsl,mpc8323-qe-pario-bank")) { pr_debug("%s: tried to get a non-qe pin\n", __func__); -- GitLab From a040d2bf4437e0efd75a811207e79be3001cc5b9 Mon Sep 17 00:00:00 2001 From: Martin Sperl Date: Sat, 30 Mar 2019 09:31:02 +0000 Subject: [PATCH 0458/1055] spi: bcm2835aux: fix driver to not allow 65535 (=-1) cs-gpios [ Upstream commit 509c583620e9053e43d611bf1614fc3d3abafa96 ] The original driver by default defines num_chipselects as -1. This actually allicates an array of 65535 entries in of_spi_register_master. There is a side-effect for buggy device trees that (contrary to dt-binding documentation) have no cs-gpio defined. This mode was never supported by the driver due to limitations of native cs and additional code complexity and is explicitly not stated to be implemented. To keep backwards compatibility with such buggy DTs we limit the number of chip_selects to 1, as for all practical purposes it is only ever realistic to use a single chip select in native cs mode without negative side-effects. Fixes: 1ea29b39f4c812ec ("spi: bcm2835aux: add bcm2835 auxiliary spi device...") Signed-off-by: Martin Sperl Acked-by: Stefan Wahren Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-bcm2835aux.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c index 5c89bbb05441..e075712c501e 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -416,7 +416,18 @@ static int bcm2835aux_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); master->mode_bits = (SPI_CPOL | SPI_CS_HIGH | SPI_NO_CS); master->bits_per_word_mask = SPI_BPW_MASK(8); - master->num_chipselect = -1; + /* even though the driver never officially supported native CS + * allow a single native CS for legacy DT support purposes when + * no cs-gpio is configured. + * Known limitations for native cs are: + * * multiple chip-selects: cs0-cs2 are all simultaniously asserted + * whenever there is a transfer - this even includes SPI_NO_CS + * * SPI_CS_HIGH: is ignores - cs are always asserted low + * * cs_change: cs is deasserted after each spi_transfer + * * cs_delay_usec: cs is always deasserted one SCK cycle after + * a spi_transfer + */ + master->num_chipselect = 1; master->transfer_one = bcm2835aux_spi_transfer_one; master->handle_err = bcm2835aux_spi_handle_err; master->prepare_message = bcm2835aux_spi_prepare_message; -- GitLab From 105f6b1ab3d04b6477cb1d45b4d8dba5e64c210e Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 3 Apr 2019 15:47:59 +0800 Subject: [PATCH 0459/1055] ehea: Fix a copy-paste err in ehea_init_port_res [ Upstream commit c8f191282f819ab4e9b47b22a65c6c29734cefce ] pr->tx_bytes should be assigned to tx_bytes other than rx_bytes. Reported-by: Hulk Robot Fixes: ce45b873028f ("ehea: Fixing statistics") Signed-off-by: YueHaibing Reviewed-by: Mukesh Ojha Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/ibm/ehea/ehea_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index 30cbdf0fed59..373deb247ac0 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -1475,7 +1475,7 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, memset(pr, 0, sizeof(struct ehea_port_res)); - pr->tx_bytes = rx_bytes; + pr->tx_bytes = tx_bytes; pr->tx_packets = tx_packets; pr->rx_bytes = rx_bytes; pr->rx_packets = rx_packets; -- GitLab From 770d2807dc789f27f21c5f6555f2b1c4e6db3a6d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 4 Apr 2019 12:44:46 -0700 Subject: [PATCH 0460/1055] scsi: qla2xxx: Unregister chrdev if module initialization fails [ Upstream commit c794d24ec9eb6658909955772e70f34bef5b5b91 ] If module initialization fails after the character device has been registered, unregister the character device. Additionally, avoid duplicating error path code. Cc: Himanshu Madhani Cc: Giridhar Malavali Fixes: 6a03b4cd78f3 ("[SCSI] qla2xxx: Add char device to increase driver use count") # v2.6.35. Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/qla2xxx/qla_os.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 5617bb18c233..5f9d4dbc4a98 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -6714,8 +6714,7 @@ qla2x00_module_init(void) /* Initialize target kmem_cache and mem_pools */ ret = qlt_init(); if (ret < 0) { - kmem_cache_destroy(srb_cachep); - return ret; + goto destroy_cache; } else if (ret > 0) { /* * If initiator mode is explictly disabled by qlt_init(), @@ -6736,11 +6735,10 @@ qla2x00_module_init(void) qla2xxx_transport_template = fc_attach_transport(&qla2xxx_transport_functions); if (!qla2xxx_transport_template) { - kmem_cache_destroy(srb_cachep); ql_log(ql_log_fatal, NULL, 0x0002, "fc_attach_transport failed...Failing load!.\n"); - qlt_exit(); - return -ENODEV; + ret = -ENODEV; + goto qlt_exit; } apidev_major = register_chrdev(0, QLA2XXX_APIDEV, &apidev_fops); @@ -6752,27 +6750,37 @@ qla2x00_module_init(void) qla2xxx_transport_vport_template = fc_attach_transport(&qla2xxx_transport_vport_functions); if (!qla2xxx_transport_vport_template) { - kmem_cache_destroy(srb_cachep); - qlt_exit(); - fc_release_transport(qla2xxx_transport_template); ql_log(ql_log_fatal, NULL, 0x0004, "fc_attach_transport vport failed...Failing load!.\n"); - return -ENODEV; + ret = -ENODEV; + goto unreg_chrdev; } ql_log(ql_log_info, NULL, 0x0005, "QLogic Fibre Channel HBA Driver: %s.\n", qla2x00_version_str); ret = pci_register_driver(&qla2xxx_pci_driver); if (ret) { - kmem_cache_destroy(srb_cachep); - qlt_exit(); - fc_release_transport(qla2xxx_transport_template); - fc_release_transport(qla2xxx_transport_vport_template); ql_log(ql_log_fatal, NULL, 0x0006, "pci_register_driver failed...ret=%d Failing load!.\n", ret); + goto release_vport_transport; } return ret; + +release_vport_transport: + fc_release_transport(qla2xxx_transport_vport_template); + +unreg_chrdev: + if (apidev_major >= 0) + unregister_chrdev(apidev_major, QLA2XXX_APIDEV); + fc_release_transport(qla2xxx_transport_template); + +qlt_exit: + qlt_exit(); + +destroy_cache: + kmem_cache_destroy(srb_cachep); + return ret; } /** -- GitLab From e03671470aebcb8f7b4f19997e047fbdc7f5b261 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 2 Apr 2019 12:58:05 -0700 Subject: [PATCH 0461/1055] scsi: target/core: Fix a race condition in the LUN lookup code [ Upstream commit 63f7479439c95bcd49b7dd4af809862c316c71a3 ] The rcu_dereference(deve->se_lun) expression occurs twice in the LUN lookup functions. Since these expressions are not serialized against deve->se_lun assignments each of these expressions may yield a different result. Avoid that the wrong LUN pointer is stored in se_cmd by reading deve->se_lun only once. Cc: Mike Christie Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Nicholas Bellinger Fixes: 29a05deebf6c ("target: Convert se_node_acl->device_list[] to RCU hlist") # v4.10 Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/target/target_core_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 92b52d2314b5..cebef8e5a43d 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -85,7 +85,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u64 unpacked_lun) goto out_unlock; } - se_cmd->se_lun = rcu_dereference(deve->se_lun); + se_cmd->se_lun = se_lun; se_cmd->pr_res_key = deve->pr_res_key; se_cmd->orig_fe_lun = unpacked_lun; se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; @@ -176,7 +176,7 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u64 unpacked_lun) goto out_unlock; } - se_cmd->se_lun = rcu_dereference(deve->se_lun); + se_cmd->se_lun = se_lun; se_cmd->pr_res_key = deve->pr_res_key; se_cmd->orig_fe_lun = unpacked_lun; se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; -- GitLab From f7919eec49098a9c5172dd67132227d12e08b155 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 29 Jan 2019 16:03:24 +0800 Subject: [PATCH 0462/1055] ARM: pxa: ssp: Fix "WARNING: invalid free of devm_ allocated data" [ Upstream commit 9ee8578d953023cc57e7e736ae48502c707c0210 ] Since commit 1c459de1e645 ("ARM: pxa: ssp: use devm_ functions") kfree, iounmap, clk_put etc are not needed anymore in remove path. Fixes: 1c459de1e645 ("ARM: pxa: ssp: use devm_ functions") Signed-off-by: YueHaibing [ commit message spelling fix ] Signed-off-by: Robert Jarzmik Signed-off-by: Sasha Levin --- arch/arm/plat-pxa/ssp.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm/plat-pxa/ssp.c b/arch/arm/plat-pxa/ssp.c index b92673efffff..97bd43c16cd8 100644 --- a/arch/arm/plat-pxa/ssp.c +++ b/arch/arm/plat-pxa/ssp.c @@ -230,18 +230,12 @@ static int pxa_ssp_probe(struct platform_device *pdev) static int pxa_ssp_remove(struct platform_device *pdev) { - struct resource *res; struct ssp_device *ssp; ssp = platform_get_drvdata(pdev); if (ssp == NULL) return -ENODEV; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - clk_put(ssp->clk); - mutex_lock(&ssp_lock); list_del(&ssp->node); mutex_unlock(&ssp_lock); -- GitLab From d2a71849205a6746f6013e71062c8e15e8ccdafd Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Mon, 15 Apr 2019 21:48:39 +0800 Subject: [PATCH 0463/1055] net: hns3: fix for vport->bw_limit overflow problem [ Upstream commit 2566f10676ba996b745e138f54f3e2f974311692 ] When setting vport->bw_limit to hdev->tm_info.pg_info[0].bw_limit in hclge_tm_vport_tc_info_update, vport->bw_limit can be as big as HCLGE_ETHER_MAX_RATE (100000), which can not fit into u16 (65535). So this patch fixes it by using u32 for vport->bw_limit. Fixes: 848440544b41 ("net: hns3: Add support of TX Scheduler & Shaper to HNS3 driver") Reported-by: Dan Carpenter Signed-off-by: Yunsheng Lin Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 9fcfd9395424..a4c5e72d6012 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -480,7 +480,7 @@ struct hclge_vport { u16 alloc_rss_size; u16 qs_offset; - u16 bw_limit; /* VSI BW Limit (0 = disabled) */ + u32 bw_limit; /* VSI BW Limit (0 = disabled) */ u8 dwrr; int vport_id; -- GitLab From ec16a5a2cc3059b2d6571b7db1e9ad98cf7882ee Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 5 Apr 2019 08:44:41 -0700 Subject: [PATCH 0464/1055] hwmon: (w83627hf) Use request_muxed_region for Super-IO accesses [ Upstream commit e95fd518d05bfc087da6fcdea4900a57cfb083bd ] Super-IO accesses may fail on a system with no or unmapped LPC bus. Also, other drivers may attempt to access the LPC bus at the same time, resulting in undefined behavior. Use request_muxed_region() to ensure that IO access on the requested address space is supported, and to ensure that access by multiple drivers is synchronized. Fixes: b72656dbc491 ("hwmon: (w83627hf) Stop using globals for I/O port numbers") Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/w83627hf.c | 42 +++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 8ac89d0781cc..a575e1cdb81a 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -130,17 +130,23 @@ superio_select(struct w83627hf_sio_data *sio, int ld) outb(ld, sio->sioaddr + 1); } -static inline void +static inline int superio_enter(struct w83627hf_sio_data *sio) { + if (!request_muxed_region(sio->sioaddr, 2, DRVNAME)) + return -EBUSY; + outb(0x87, sio->sioaddr); outb(0x87, sio->sioaddr); + + return 0; } static inline void superio_exit(struct w83627hf_sio_data *sio) { outb(0xAA, sio->sioaddr); + release_region(sio->sioaddr, 2); } #define W627_DEVID 0x52 @@ -1278,7 +1284,7 @@ static DEVICE_ATTR_RO(name); static int __init w83627hf_find(int sioaddr, unsigned short *addr, struct w83627hf_sio_data *sio_data) { - int err = -ENODEV; + int err; u16 val; static __initconst char *const names[] = { @@ -1290,7 +1296,11 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr, }; sio_data->sioaddr = sioaddr; - superio_enter(sio_data); + err = superio_enter(sio_data); + if (err) + return err; + + err = -ENODEV; val = force_id ? force_id : superio_inb(sio_data, DEVID); switch (val) { case W627_DEVID: @@ -1644,9 +1654,21 @@ static int w83627thf_read_gpio5(struct platform_device *pdev) struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev); int res = 0xff, sel; - superio_enter(sio_data); + if (superio_enter(sio_data)) { + /* + * Some other driver reserved the address space for itself. + * We don't want to fail driver instantiation because of that, + * so display a warning and keep going. + */ + dev_warn(&pdev->dev, + "Can not read VID data: Failed to enable SuperIO access\n"); + return res; + } + superio_select(sio_data, W83627HF_LD_GPIO5); + res = 0xff; + /* Make sure these GPIO pins are enabled */ if (!(superio_inb(sio_data, W83627THF_GPIO5_EN) & (1<<3))) { dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n"); @@ -1677,7 +1699,17 @@ static int w83687thf_read_vid(struct platform_device *pdev) struct w83627hf_sio_data *sio_data = dev_get_platdata(&pdev->dev); int res = 0xff; - superio_enter(sio_data); + if (superio_enter(sio_data)) { + /* + * Some other driver reserved the address space for itself. + * We don't want to fail driver instantiation because of that, + * so display a warning and keep going. + */ + dev_warn(&pdev->dev, + "Can not read VID data: Failed to enable SuperIO access\n"); + return res; + } + superio_select(sio_data, W83627HF_LD_HWM); /* Make sure these GPIO pins are enabled */ -- GitLab From 16d61aeda20bb6cd5c88f0c6c4bdc78ee9436d70 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 30 Mar 2019 00:17:12 +0000 Subject: [PATCH 0465/1055] platform/x86: alienware-wmi: fix kfree on potentially uninitialized pointer [ Upstream commit 98e2630284ab741804bd0713e932e725466f2f84 ] Currently the kfree of output.pointer can be potentially freeing an uninitalized pointer in the case where out_data is NULL. Fix this by reworking the case where out_data is not-null to perform the ACPI status check and also the kfree of outpoint.pointer in one block and hence ensuring the pointer is only freed when it has been used. Also replace the if (ptr != NULL) idiom with just if (ptr). Fixes: ff0e9f26288d ("platform/x86: alienware-wmi: Correct a memory leak") Signed-off-by: Colin Ian King Signed-off-by: Darren Hart (VMware) Signed-off-by: Sasha Levin --- drivers/platform/x86/alienware-wmi.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index e335b18da20f..cbd84e2e3bd4 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -505,23 +505,22 @@ static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args, input.length = (acpi_size) sizeof(*in_args); input.pointer = in_args; - if (out_data != NULL) { + if (out_data) { output.length = ACPI_ALLOCATE_BUFFER; output.pointer = NULL; status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0, command, &input, &output); - } else + if (ACPI_SUCCESS(status)) { + obj = (union acpi_object *)output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + *out_data = (u32)obj->integer.value; + } + kfree(output.pointer); + } else { status = wmi_evaluate_method(WMAX_CONTROL_GUID, 0, command, &input, NULL); - - if (ACPI_SUCCESS(status) && out_data != NULL) { - obj = (union acpi_object *)output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) - *out_data = (u32) obj->integer.value; } - kfree(output.pointer); return status; - } /* -- GitLab From edefec3a6d59fad0902d8d2209442a593a6af6e6 Mon Sep 17 00:00:00 2001 From: Jie Liu Date: Tue, 16 Apr 2019 13:10:09 +0800 Subject: [PATCH 0466/1055] tipc: set sysctl_tipc_rmem and named_timeout right range [ Upstream commit 4bcd4ec1017205644a2697bccbc3b5143f522f5f ] We find that sysctl_tipc_rmem and named_timeout do not have the right minimum setting. sysctl_tipc_rmem should be larger than zero, like sysctl_tcp_rmem. And named_timeout as a timeout setting should be not less than zero. Fixes: cc79dd1ba9c10 ("tipc: change socket buffer overflow control to respect sk_rcvbuf") Fixes: a5325ae5b8bff ("tipc: add name distributor resiliency queue") Signed-off-by: Jie Liu Reported-by: Qiang Ning Reviewed-by: Zhiqiang Liu Reviewed-by: Miaohe Lin Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/tipc/sysctl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/tipc/sysctl.c b/net/tipc/sysctl.c index 1a779b1e8510..40f6d82083d7 100644 --- a/net/tipc/sysctl.c +++ b/net/tipc/sysctl.c @@ -37,6 +37,8 @@ #include +static int zero; +static int one = 1; static struct ctl_table_header *tipc_ctl_hdr; static struct ctl_table tipc_table[] = { @@ -45,14 +47,16 @@ static struct ctl_table tipc_table[] = { .data = &sysctl_tipc_rmem, .maxlen = sizeof(sysctl_tipc_rmem), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_minmax, + .extra1 = &one, }, { .procname = "named_timeout", .data = &sysctl_tipc_named_timeout, .maxlen = sizeof(sysctl_tipc_named_timeout), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, }, {} }; -- GitLab From c0d4d3bdf73f868e6afbec16395d1edc448651b0 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 8 Apr 2019 10:13:44 -0700 Subject: [PATCH 0467/1055] selftests/ipc: Fix msgque compiler warnings [ Upstream commit a147faa96f832f76e772b1e448e94ea84c774081 ] This fixes the various compiler warnings when building the msgque selftest. The primary change is using sys/msg.h instead of linux/msg.h directly to gain the API declarations. Fixes: 3a665531a3b7 ("selftests: IPC message queue copy feature test") Signed-off-by: Kees Cook Signed-off-by: Shuah Khan Signed-off-by: Sasha Levin --- tools/testing/selftests/ipc/msgque.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c index ee9382bdfadc..c5587844fbb8 100644 --- a/tools/testing/selftests/ipc/msgque.c +++ b/tools/testing/selftests/ipc/msgque.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE #include #include #include #include -#include +#include #include #include "../kselftest.h" @@ -73,7 +74,7 @@ int restore_queue(struct msgque_data *msgque) return 0; destroy: - if (msgctl(id, IPC_RMID, 0)) + if (msgctl(id, IPC_RMID, NULL)) printf("Failed to destroy queue: %d\n", -errno); return ret; } @@ -120,7 +121,7 @@ int check_and_destroy_queue(struct msgque_data *msgque) ret = 0; err: - if (msgctl(msgque->msq_id, IPC_RMID, 0)) { + if (msgctl(msgque->msq_id, IPC_RMID, NULL)) { printf("Failed to destroy queue: %d\n", -errno); return -errno; } @@ -129,7 +130,7 @@ int check_and_destroy_queue(struct msgque_data *msgque) int dump_queue(struct msgque_data *msgque) { - struct msqid64_ds ds; + struct msqid_ds ds; int kern_id; int i, ret; @@ -246,7 +247,7 @@ int main(int argc, char **argv) return ksft_exit_pass(); err_destroy: - if (msgctl(msgque.msq_id, IPC_RMID, 0)) { + if (msgctl(msgque.msq_id, IPC_RMID, NULL)) { printf("Failed to destroy queue: %d\n", -errno); return ksft_exit_fail(); } -- GitLab From c707b68465f91759515e09783119a8cc2f802530 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 22 Mar 2019 04:24:37 +0000 Subject: [PATCH 0468/1055] powerpc: vdso: Make vdso32 installation conditional in vdso_install [ Upstream commit ff6d27823f619892ab96f7461764840e0d786b15 ] The 32-bit vDSO is not needed and not normally built for 64-bit little-endian configurations. However, the vdso_install target still builds and installs it. Add the same config condition as is normally used for the build. Fixes: e0d005916994 ("powerpc/vdso: Disable building the 32-bit VDSO ...") Signed-off-by: Ben Hutchings Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin --- arch/powerpc/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 0f04c878113e..9c78ef298257 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -385,7 +385,9 @@ vdso_install: ifeq ($(CONFIG_PPC64),y) $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso64 $@ endif +ifdef CONFIG_VDSO32 $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso32 $@ +endif archclean: $(Q)$(MAKE) $(clean)=$(boot) -- GitLab From 78f7e2aa4e4549429bb5d4ca8fdfca8c8cd237dd Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 12 Apr 2019 02:23:14 +0300 Subject: [PATCH 0469/1055] ARM: dts: ls1021: Fix SGMII PCS link remaining down after PHY disconnect [ Upstream commit c7861adbe37f576931650ad8ef805e0c47564b9a ] Each eTSEC MAC has its own TBI (SGMII) PCS and private MDIO bus. But due to a DTS oversight, both SGMII-compatible MACs of the LS1021 SoC are pointing towards the same internal PCS. Therefore nobody is controlling the internal PCS of eTSEC0. Upon initial ndo_open, the SGMII link is ok by virtue of U-boot initialization. But upon an ifdown/ifup sequence, the code path from ndo_open -> init_phy -> gfar_configure_serdes does not get executed for the PCS of eTSEC0 (and is executed twice for MAC eTSEC1). So the SGMII link remains down for eTSEC0. On the LS1021A-TWR board, to signal this failure condition, the PHY driver keeps printing '803x_aneg_done: SGMII link is not ok'. Also, it changes compatible of mdio0 to "fsl,etsec2-mdio" to match mdio1 device. Fixes: 055223d4d22d ("ARM: dts: ls1021a: Enable the eTSEC ports on QDS and TWR") Signed-off-by: Vladimir Oltean Reviewed-by: Claudiu Manoil Acked-by: Li Yang Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin --- arch/arm/boot/dts/ls1021a-twr.dts | 9 ++++++++- arch/arm/boot/dts/ls1021a.dtsi | 11 ++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/ls1021a-twr.dts b/arch/arm/boot/dts/ls1021a-twr.dts index 44715c8ef756..72a3fc63d0ec 100644 --- a/arch/arm/boot/dts/ls1021a-twr.dts +++ b/arch/arm/boot/dts/ls1021a-twr.dts @@ -143,7 +143,7 @@ }; &enet0 { - tbi-handle = <&tbi1>; + tbi-handle = <&tbi0>; phy-handle = <&sgmii_phy2>; phy-connection-type = "sgmii"; status = "okay"; @@ -222,6 +222,13 @@ sgmii_phy2: ethernet-phy@2 { reg = <0x2>; }; + tbi0: tbi-phy@1f { + reg = <0x1f>; + device_type = "tbi-phy"; + }; +}; + +&mdio1 { tbi1: tbi-phy@1f { reg = <0x1f>; device_type = "tbi-phy"; diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index 2d20f60947b9..1343c86988c5 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -562,13 +562,22 @@ }; mdio0: mdio@2d24000 { - compatible = "gianfar"; + compatible = "fsl,etsec2-mdio"; device_type = "mdio"; #address-cells = <1>; #size-cells = <0>; reg = <0x0 0x2d24000 0x0 0x4000>; }; + mdio1: mdio@2d64000 { + compatible = "fsl,etsec2-mdio"; + device_type = "mdio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x2d64000 0x0 0x4000>, + <0x0 0x2d50030 0x0 0x4>; + }; + ptp_clock@2d10e00 { compatible = "fsl,etsec-ptp"; reg = <0x0 0x2d10e00 0x0 0xb0>; -- GitLab From 62ca24f153245509e1278c8fe62b6ec01f8a3739 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 30 Mar 2019 10:01:32 -0400 Subject: [PATCH 0470/1055] media: ov2659: fix unbalanced mutex_lock/unlock [ Upstream commit 384538bda10913e5c94ec5b5d34bd3075931bcf4 ] Avoid returning with mutex locked. Fixes: fa8cb6444c32 ("[media] ov2659: Don't depend on subdev API") Cc: "Lad, Prabhakar" Signed-off-by: Akinobu Mita Acked-by: Lad, Prabhakar Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/i2c/ov2659.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 44b0584eb8a6..e7768ed1ff9c 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1136,7 +1136,7 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd, mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; #else - return -ENOTTY; + ret = -ENOTTY; #endif } else { s64 val; -- GitLab From 0d5d07b98b7dbfa0b87c02b5925498d5fd667993 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 3 Apr 2019 08:34:16 +0300 Subject: [PATCH 0471/1055] 6lowpan: Off by one handling ->nexthdr [ Upstream commit f57c4bbf34439531adccd7d3a4ecc14f409c1399 ] NEXTHDR_MAX is 255. What happens here is that we take a u8 value "hdr->nexthdr" from the network and then look it up in lowpan_nexthdr_nhcs[]. The problem is that if hdr->nexthdr is 0xff then we read one element beyond the end of the array so the array needs to be one element larger. Fixes: 92aa7c65d295 ("6lowpan: add generic nhc layer interface") Signed-off-by: Dan Carpenter Acked-by: Jukka Rissanen Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin --- net/6lowpan/nhc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/6lowpan/nhc.c b/net/6lowpan/nhc.c index 4fa2fdda174d..9e56fb98f33c 100644 --- a/net/6lowpan/nhc.c +++ b/net/6lowpan/nhc.c @@ -18,7 +18,7 @@ #include "nhc.h" static struct rb_root rb_root = RB_ROOT; -static struct lowpan_nhc *lowpan_nexthdr_nhcs[NEXTHDR_MAX]; +static struct lowpan_nhc *lowpan_nexthdr_nhcs[NEXTHDR_MAX + 1]; static DEFINE_SPINLOCK(lowpan_nhc_lock); static int lowpan_nhc_insert(struct lowpan_nhc *nhc) -- GitLab From 2722d16445fab8dde6166f12875e3b93a366a1a8 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Tue, 26 Mar 2019 16:05:20 +0200 Subject: [PATCH 0472/1055] dmaengine: axi-dmac: Don't check the number of frames for alignment [ Upstream commit 648865a79d8ee3d1aa64aab5eb2a9d12eeed14f9 ] In 2D transfers (for the AXI DMAC), the number of frames (numf) represents Y_LENGTH, and the length of a frame is X_LENGTH. 2D transfers are useful for video transfers where screen resolutions ( X * Y ) are typically aligned for X, but not for Y. There is no requirement for Y_LENGTH to be aligned to the bus-width (or anything), and this is also true for AXI DMAC. Checking the Y_LENGTH for alignment causes false errors when initiating DMA transfers. This change fixes this by checking only that the Y_LENGTH is non-zero. Fixes: 0e3b67b348b8 ("dmaengine: Add support for the Analog Devices AXI-DMAC DMA controller") Signed-off-by: Alexandru Ardelean Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/dma-axi-dmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index 7f0b9aa15867..9887f2a14aa9 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -451,7 +451,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_interleaved( if (chan->hw_2d) { if (!axi_dmac_check_len(chan, xt->sgl[0].size) || - !axi_dmac_check_len(chan, xt->numf)) + xt->numf == 0) return NULL; if (xt->sgl[0].size + dst_icg > chan->max_length || xt->sgl[0].size + src_icg > chan->max_length) -- GitLab From a1a19d86859db27a62762d9f6b49c80b85b29316 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 24 Apr 2019 13:00:03 +0200 Subject: [PATCH 0473/1055] ALSA: usb-audio: Handle the error from snd_usb_mixer_apply_create_quirk() [ Upstream commit 328e9f6973be2ee67862cb17bf6c0c5c5918cd72 ] The error from snd_usb_mixer_apply_create_quirk() is ignored in the current usb-audio driver code, which will continue the probing even after the error. Let's take it more serious. Fixes: 7b1eda223deb ("ALSA: usb-mixer: factor out quirks") Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/usb/mixer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 044193b2364d..e6e4c3b9d9d3 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2632,7 +2632,9 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, (err = snd_usb_mixer_status_create(mixer)) < 0) goto _error; - snd_usb_mixer_apply_create_quirk(mixer); + err = snd_usb_mixer_apply_create_quirk(mixer); + if (err < 0) + goto _error; err = snd_device_new(chip->card, SNDRV_DEV_CODEC, mixer, &dev_ops); if (err < 0) -- GitLab From a5553f27402b64e7164d7ddf7b87bc5d48042433 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 7 Apr 2019 13:59:02 -0400 Subject: [PATCH 0474/1055] NFS: Don't interrupt file writeout due to fatal errors [ Upstream commit 14bebe3c90b326d2a0df78aed5e9de090c71d878 ] When flushing out dirty pages, the fact that we may hit fatal errors is not a reason to stop writeback. Those errors are reported through fsync(), not through the flush mechanism. Fixes: a6598813a4c5b ("NFS: Don't write back further requests if there...") Signed-off-by: Trond Myklebust Signed-off-by: Anna Schumaker Signed-off-by: Sasha Levin --- fs/nfs/write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 01b9d9341b54..ed3f5afc4ff7 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -643,7 +643,7 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, return ret; out_launder: nfs_write_error_remove_page(req); - return ret; + return 0; } static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, -- GitLab From ded647fdda63e9dd50d51f1303768e673e6339c1 Mon Sep 17 00:00:00 2001 From: Hongbo Yao Date: Mon, 8 Apr 2019 22:01:03 +0800 Subject: [PATCH 0475/1055] irqchip/gic-v3-its: fix some definitions of inner cacheability attributes [ Upstream commit 0f29456d08042134aff6e562d07a6365c841c4ad ] Some definitions of Inner Cacheability attibutes need to be corrected. Fixes: 8c828a535e29f ("irqchip/gicv3-its: Restore all cacheability attributes") Signed-off-by: Hongbo Yao Signed-off-by: Marc Zyngier Signed-off-by: Sasha Levin --- include/linux/irqchip/arm-gic-v3.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 845ff8c51564..0fe1fdedb8a1 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -152,7 +152,7 @@ #define GICR_PROPBASER_nCnB GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, nCnB) #define GICR_PROPBASER_nC GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, nC) #define GICR_PROPBASER_RaWt GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWt) -#define GICR_PROPBASER_RaWb GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWt) +#define GICR_PROPBASER_RaWb GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWb) #define GICR_PROPBASER_WaWt GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, WaWt) #define GICR_PROPBASER_WaWb GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, WaWb) #define GICR_PROPBASER_RaWaWt GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWaWt) @@ -179,7 +179,7 @@ #define GICR_PENDBASER_nCnB GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, nCnB) #define GICR_PENDBASER_nC GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, nC) #define GICR_PENDBASER_RaWt GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWt) -#define GICR_PENDBASER_RaWb GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWt) +#define GICR_PENDBASER_RaWb GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWb) #define GICR_PENDBASER_WaWt GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, WaWt) #define GICR_PENDBASER_WaWb GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, WaWb) #define GICR_PENDBASER_RaWaWt GIC_BASER_CACHEABILITY(GICR_PENDBASER, INNER, RaWaWt) @@ -238,7 +238,7 @@ #define GICR_VPROPBASER_nCnB GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, nCnB) #define GICR_VPROPBASER_nC GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, nC) #define GICR_VPROPBASER_RaWt GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWt) -#define GICR_VPROPBASER_RaWb GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWt) +#define GICR_VPROPBASER_RaWb GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWb) #define GICR_VPROPBASER_WaWt GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, WaWt) #define GICR_VPROPBASER_WaWb GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, WaWb) #define GICR_VPROPBASER_RaWaWt GIC_BASER_CACHEABILITY(GICR_VPROPBASER, INNER, RaWaWt) @@ -264,7 +264,7 @@ #define GICR_VPENDBASER_nCnB GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, nCnB) #define GICR_VPENDBASER_nC GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, nC) #define GICR_VPENDBASER_RaWt GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, RaWt) -#define GICR_VPENDBASER_RaWb GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, RaWt) +#define GICR_VPENDBASER_RaWb GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, RaWb) #define GICR_VPENDBASER_WaWt GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, WaWt) #define GICR_VPENDBASER_WaWb GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, WaWb) #define GICR_VPENDBASER_RaWaWt GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, RaWaWt) @@ -337,7 +337,7 @@ #define GITS_CBASER_nCnB GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, nCnB) #define GITS_CBASER_nC GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, nC) #define GITS_CBASER_RaWt GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWt) -#define GITS_CBASER_RaWb GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWt) +#define GITS_CBASER_RaWb GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWb) #define GITS_CBASER_WaWt GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, WaWt) #define GITS_CBASER_WaWb GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, WaWb) #define GITS_CBASER_RaWaWt GIC_BASER_CACHEABILITY(GITS_CBASER, INNER, RaWaWt) @@ -361,7 +361,7 @@ #define GITS_BASER_nCnB GIC_BASER_CACHEABILITY(GITS_BASER, INNER, nCnB) #define GITS_BASER_nC GIC_BASER_CACHEABILITY(GITS_BASER, INNER, nC) #define GITS_BASER_RaWt GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWt) -#define GITS_BASER_RaWb GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWt) +#define GITS_BASER_RaWb GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWb) #define GITS_BASER_WaWt GIC_BASER_CACHEABILITY(GITS_BASER, INNER, WaWt) #define GITS_BASER_WaWb GIC_BASER_CACHEABILITY(GITS_BASER, INNER, WaWb) #define GITS_BASER_RaWaWt GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWaWt) -- GitLab From ab353598ceed8af45a9a83bf50b5e2056733742c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 17 Apr 2019 14:44:11 -0700 Subject: [PATCH 0476/1055] scsi: qla2xxx: Fix a format specifier [ Upstream commit 19ce192cd718e02f880197c0983404ca48236807 ] Since mcmd->sess->port_name is eight bytes long, use %8phC to format that port name instead of %phC. Cc: Himanshu Madhani Cc: Giridhar Malavali Fixes: 726b85487067 ("qla2xxx: Add framework for async fabric discovery") # v4.11. Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/qla2xxx/qla_target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 55227d20496a..1000422ef4f8 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -2179,7 +2179,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) mcmd->orig_iocb.imm_ntfy.u.isp24.status_subcode == ELS_TPRLO) { ql_dbg(ql_dbg_disc, vha, 0x2106, - "TM response logo %phC status %#x state %#x", + "TM response logo %8phC status %#x state %#x", mcmd->sess->port_name, mcmd->fc_tm_rsp, mcmd->flags); qlt_schedule_sess_for_deletion_lock(mcmd->sess); -- GitLab From 6a75405369e9cdb7509dd760c0213154e819c353 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 17 Apr 2019 14:44:42 -0700 Subject: [PATCH 0477/1055] scsi: qla2xxx: Avoid that qlt_send_resp_ctio() corrupts memory [ Upstream commit a861b49273578e255426a499842cf7f465456351 ] The "(&ctio->u.status1.sense_data)[i]" where i >= 0 expressions in qlt_send_resp_ctio() are probably typos and should have been "(&ctio->u.status1.sense_data[4 * i])" instead. Instead of only fixing these typos, modify the code for storing sense data such that it becomes easy to read. This patch fixes a Coverity complaint about accessing an array outside its bounds. Cc: Himanshu Madhani Cc: Giridhar Malavali Fixes: be25152c0d9e ("qla2xxx: Improve T10-DIF/PI handling in driver.") # v4.11. Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/qla2xxx/qla_target.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 1000422ef4f8..21011c5fddeb 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -2122,14 +2122,14 @@ void qlt_send_resp_ctio(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, ctio->u.status1.scsi_status |= cpu_to_le16(SS_RESIDUAL_UNDER); - /* Response code and sense key */ - put_unaligned_le32(((0x70 << 24) | (sense_key << 8)), - (&ctio->u.status1.sense_data)[0]); + /* Fixed format sense data. */ + ctio->u.status1.sense_data[0] = 0x70; + ctio->u.status1.sense_data[2] = sense_key; /* Additional sense length */ - put_unaligned_le32(0x0a, (&ctio->u.status1.sense_data)[1]); + ctio->u.status1.sense_data[7] = 0xa; /* ASC and ASCQ */ - put_unaligned_le32(((asc << 24) | (ascq << 16)), - (&ctio->u.status1.sense_data)[3]); + ctio->u.status1.sense_data[12] = asc; + ctio->u.status1.sense_data[13] = ascq; /* Memory Barrier */ wmb(); -- GitLab From dd1ce3f27ba05819659b28a41d6885cac1cdca0d Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Mon, 29 Apr 2019 11:46:55 -0400 Subject: [PATCH 0478/1055] packet: in recvmsg msg_name return at least sizeof sockaddr_ll [ Upstream commit b2cf86e1563e33a14a1c69b3e508d15dc12f804c ] Packet send checks that msg_name is at least sizeof sockaddr_ll. Packet recv must return at least this length, so that its output can be passed unmodified to packet send. This ceased to be true since adding support for lladdr longer than sll_addr. Since, the return value uses true address length. Always return at least sizeof sockaddr_ll, even if address length is shorter. Zero the padding bytes. Change v1->v2: do not overwrite zeroed padding again. use copy_len. Fixes: 0fb375fb9b93 ("[AF_PACKET]: Allow for > 8 byte hardware addresses.") Suggested-by: David Laight Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/packet/af_packet.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 4e1058159b08..e788f9c7c398 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -3407,20 +3407,29 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, sock_recv_ts_and_drops(msg, sk, skb); if (msg->msg_name) { + int copy_len; + /* If the address length field is there to be filled * in, we fill it in now. */ if (sock->type == SOCK_PACKET) { __sockaddr_check_size(sizeof(struct sockaddr_pkt)); msg->msg_namelen = sizeof(struct sockaddr_pkt); + copy_len = msg->msg_namelen; } else { struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll; msg->msg_namelen = sll->sll_halen + offsetof(struct sockaddr_ll, sll_addr); + copy_len = msg->msg_namelen; + if (msg->msg_namelen < sizeof(struct sockaddr_ll)) { + memset(msg->msg_name + + offsetof(struct sockaddr_ll, sll_addr), + 0, sizeof(sll->sll_addr)); + msg->msg_namelen = sizeof(struct sockaddr_ll); + } } - memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, - msg->msg_namelen); + memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, copy_len); } if (pkt_sk(sk)->auxdata) { -- GitLab From 0075f99fb42ddcf77c527740fa9503bbad0f98d0 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 29 Apr 2019 11:47:49 +0200 Subject: [PATCH 0479/1055] ASoC: fix valid stream condition [ Upstream commit 6a7c59c6d9f3b280e81d7a04bbe4e55e90152dce ] A stream may specify a rate range using 'rate_min' and 'rate_max', so a stream may be valid and not specify any rates. However, as stream cannot be valid and not have any channel. Let's use this condition instead to determine if a stream is valid or not. Fixes: cde79035c6cf ("ASoC: Handle multiple codecs with split playback / capture") Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/soc-pcm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 24047375c2fb..70e1a60a2e98 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -48,8 +48,8 @@ static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream) else codec_stream = &dai->driver->capture; - /* If the codec specifies any rate at all, it supports the stream. */ - return codec_stream->rates; + /* If the codec specifies any channels at all, it supports the stream */ + return codec_stream->channels_min; } /** -- GitLab From 152920f6c6fe9fa91e837dc99b34b607b10d4958 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 16 Apr 2019 14:25:32 +0200 Subject: [PATCH 0480/1055] usb: gadget: fsl: fix link error against usb-gadget module [ Upstream commit 2100e3ca3676e894fa48b8f6f01d01733387fe81 ] The dependency to ensure this driver links correctly fails since it can not be a loadable module: drivers/usb/phy/phy-fsl-usb.o: In function `fsl_otg_set_peripheral': phy-fsl-usb.c:(.text+0x2224): undefined reference to `usb_gadget_vbus_disconnect' Make the option 'tristate' so it can work correctly. Fixes: 5a8d651a2bde ("usb: gadget: move gadget API functions to udc-core") Signed-off-by: Arnd Bergmann Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin --- drivers/usb/phy/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 85a92d0813dd..440238061edd 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -20,7 +20,7 @@ config AB8500_USB in host mode, low speed. config FSL_USB2_OTG - bool "Freescale USB OTG Transceiver Driver" + tristate "Freescale USB OTG Transceiver Driver" depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM=y && PM depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' select USB_PHY -- GitLab From 1e5c78fb5b18af8d51433cb74358979a0f13a36e Mon Sep 17 00:00:00 2001 From: Minas Harutyunyan Date: Fri, 22 Feb 2019 15:49:19 +0400 Subject: [PATCH 0481/1055] dwc2: gadget: Fix completed transfer size calculation in DDMA [ Upstream commit 5acb4b970184d189d901192d075997c933b82260 ] Fix calculation of transfer size on completion in function dwc2_gadget_get_xfersize_ddma(). Added increment of descriptor pointer to move to next descriptor in the loop. Fixes: aa3e8bc81311 ("usb: dwc2: gadget: DDMA transfer start and complete") Signed-off-by: Minas Harutyunyan Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin --- drivers/usb/dwc2/gadget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index e164439b2154..4af9a1c652ed 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2276,6 +2276,7 @@ static unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep) if (status & DEV_DMA_STS_MASK) dev_err(hsotg->dev, "descriptor %d closed with %x\n", i, status & DEV_DMA_STS_MASK); + desc++; } return bytes_rem; -- GitLab From 35fe8691b18701ac0ff6fc7efd601f7bb930bab0 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Wed, 1 May 2019 08:38:30 +0300 Subject: [PATCH 0482/1055] IB/mlx5: Add missing XRC options to QP optional params mask [ Upstream commit 8f4426aa19fcdb9326ac44154a117b1a3a5ae126 ] The QP transition optional parameters for the various transition for XRC QPs are identical to those for RC QPs. Many of the XRC QP transition optional parameter bits are missing from the QP optional mask table. These omissions caused failures when doing XRC QP state transitions. For example, when trying to change the response timer of an XRC receive QP via the RTS2RTS transition, the new timer value was ignored because MLX5_QP_OPTPAR_RNR_TIMEOUT bit was missing from the optional params mask for XRC qps for the RTS2RTS transition. Fix this by adding the missing XRC optional parameters for all QP transitions to the opt_mask table. Fixes: e126ba97dba9 ("mlx5: Add driver for Mellanox Connect-IB adapters") Fixes: a4774e9095de ("IB/mlx5: Fix opt param mask according to firmware spec") Signed-off-by: Jack Morgenstein Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/hw/mlx5/qp.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 5a7dcb5afe6e..84c962820aa2 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -2357,6 +2357,11 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_PKEY_INDEX | MLX5_QP_OPTPAR_Q_KEY | MLX5_QP_OPTPAR_PRI_PORT, + [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_RRE | + MLX5_QP_OPTPAR_RAE | + MLX5_QP_OPTPAR_RWE | + MLX5_QP_OPTPAR_PKEY_INDEX | + MLX5_QP_OPTPAR_PRI_PORT, }, [MLX5_QP_STATE_RTR] = { [MLX5_QP_ST_RC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | @@ -2390,6 +2395,12 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q MLX5_QP_OPTPAR_RWE | MLX5_QP_OPTPAR_PM_STATE, [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY, + [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_ALT_ADDR_PATH | + MLX5_QP_OPTPAR_RRE | + MLX5_QP_OPTPAR_RAE | + MLX5_QP_OPTPAR_RWE | + MLX5_QP_OPTPAR_PM_STATE | + MLX5_QP_OPTPAR_RNR_TIMEOUT, }, }, [MLX5_QP_STATE_RTS] = { @@ -2406,6 +2417,12 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q [MLX5_QP_ST_UD] = MLX5_QP_OPTPAR_Q_KEY | MLX5_QP_OPTPAR_SRQN | MLX5_QP_OPTPAR_CQN_RCV, + [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_RRE | + MLX5_QP_OPTPAR_RAE | + MLX5_QP_OPTPAR_RWE | + MLX5_QP_OPTPAR_RNR_TIMEOUT | + MLX5_QP_OPTPAR_PM_STATE | + MLX5_QP_OPTPAR_ALT_ADDR_PATH, }, }, [MLX5_QP_STATE_SQER] = { @@ -2417,6 +2434,10 @@ static enum mlx5_qp_optpar opt_mask[MLX5_QP_NUM_STATE][MLX5_QP_NUM_STATE][MLX5_Q MLX5_QP_OPTPAR_RWE | MLX5_QP_OPTPAR_RAE | MLX5_QP_OPTPAR_RRE, + [MLX5_QP_ST_XRC] = MLX5_QP_OPTPAR_RNR_TIMEOUT | + MLX5_QP_OPTPAR_RWE | + MLX5_QP_OPTPAR_RAE | + MLX5_QP_OPTPAR_RRE, }, }, }; -- GitLab From feed4aa653cf0bdf4f1b5cb8ae80ee5a8186840b Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Thu, 2 May 2019 09:34:26 +0800 Subject: [PATCH 0483/1055] iommu/vt-d: Make kernel parameter igfx_off work with vIOMMU [ Upstream commit 5daab58043ee2bca861068e2595564828f3bc663 ] The kernel parameter igfx_off is used by users to disable DMA remapping for the Intel integrated graphic device. It was designed for bare metal cases where a dedicated IOMMU is used for graphic. This doesn't apply to virtual IOMMU case where an include-all IOMMU is used. This makes the kernel parameter work with virtual IOMMU as well. Cc: Ashok Raj Cc: Jacob Pan Suggested-by: Kevin Tian Fixes: c0771df8d5297 ("intel-iommu: Export a flag indicating that the IOMMU is used for iGFX.") Signed-off-by: Lu Baolu Tested-by: Zhenyu Wang Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/intel-iommu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 523d0889c2a4..4fbd183d973a 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -3361,9 +3361,12 @@ static int __init init_dmars(void) iommu_identity_mapping |= IDENTMAP_ALL; #ifdef CONFIG_INTEL_IOMMU_BROKEN_GFX_WA - iommu_identity_mapping |= IDENTMAP_GFX; + dmar_map_gfx = 0; #endif + if (!dmar_map_gfx) + iommu_identity_mapping |= IDENTMAP_GFX; + check_tylersburg_isoch(); if (iommu_identity_mapping) { -- GitLab From 44d443842c6a5c4b8a5ca3cd1748a63f13541052 Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Wed, 1 May 2019 16:47:03 +0300 Subject: [PATCH 0484/1055] net: ena: fix swapped parameters when calling ena_com_indirect_table_fill_entry [ Upstream commit 3c6eeff295f01bdf1c6c3addcb0a04c0c6c029e9 ] second parameter should be the index of the table rather than the value. Fixes: 1738cd3ed342 ("net: ena: Add a driver for Amazon Elastic Network Adapters (ENA)") Signed-off-by: Saeed Bshara Signed-off-by: Sameeh Jubran Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index 967020fb26ee..a2f02c23fe14 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -694,8 +694,8 @@ static int ena_set_rxfh(struct net_device *netdev, const u32 *indir, if (indir) { for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) { rc = ena_com_indirect_table_fill_entry(ena_dev, - ENA_IO_RXQ_IDX(indir[i]), - i); + i, + ENA_IO_RXQ_IDX(indir[i])); if (unlikely(rc)) { netif_err(adapter, drv, netdev, "Cannot fill indirect table (index is too large)\n"); -- GitLab From 7799cd5d6b0efea6dbad635738b9049362810457 Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Wed, 1 May 2019 16:47:05 +0300 Subject: [PATCH 0485/1055] net: ena: fix: Free napi resources when ena_up() fails [ Upstream commit b287cdbd1cedfc9606682c6e02b58d00ff3a33ae ] ena_up() calls ena_init_napi() but does not call ena_del_napi() in case of failure. This causes a segmentation fault upon rmmod when netif_napi_del() is called. Fix this bug by calling ena_del_napi() before returning error from ena_up(). Fixes: 1738cd3ed342 ("net: ena: Add a driver for Amazon Elastic Network Adapters (ENA)") Signed-off-by: Arthur Kiyanovski Signed-off-by: Sameeh Jubran Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index d22b138c2b09..518ff393a026 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -1796,6 +1796,7 @@ static int ena_up(struct ena_adapter *adapter) err_setup_tx: ena_free_io_irq(adapter); err_req_irq: + ena_del_napi(adapter); return rc; } -- GitLab From 086815f78499514e5d532df6343aadd65ed2a247 Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Wed, 1 May 2019 16:47:06 +0300 Subject: [PATCH 0486/1055] net: ena: fix incorrect test of supported hash function [ Upstream commit d3cfe7ddbc3dfbb9b201615b7fef8fd66d1b5fe8 ] ena_com_set_hash_function() tests if a hash function is supported by the device before setting it. The test returns the opposite result than needed. Reverse the condition to return the correct value. Also use the BIT macro instead of inline shift. Fixes: 1738cd3ed342 ("net: ena: Add a driver for Amazon Elastic Network Adapters (ENA)") Signed-off-by: Arthur Kiyanovski Signed-off-by: Sameeh Jubran Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/amazon/ena/ena_com.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 1a4ffc5d3da4..011b54c541aa 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -2002,7 +2002,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev) if (unlikely(ret)) return ret; - if (get_resp.u.flow_hash_func.supported_func & (1 << rss->hash_func)) { + if (!(get_resp.u.flow_hash_func.supported_func & BIT(rss->hash_func))) { pr_err("Func hash %d isn't supported by device, abort\n", rss->hash_func); return -EOPNOTSUPP; -- GitLab From 709f31c4b346c16ff25829e908bde81f9d7f3f7d Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Wed, 1 May 2019 16:47:09 +0300 Subject: [PATCH 0487/1055] net: ena: fix ena_com_fill_hash_function() implementation [ Upstream commit 11bd7a00c0d8ffe33d1e926f8e789b4aea787186 ] ena_com_fill_hash_function() didn't configure the rss->hash_func. Fixes: 1738cd3ed342 ("net: ena: Add a driver for Amazon Elastic Network Adapters (ENA)") Signed-off-by: Netanel Belgazal Signed-off-by: Sameeh Jubran Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/amazon/ena/ena_com.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 011b54c541aa..10e6053f6671 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -2087,6 +2087,7 @@ int ena_com_fill_hash_function(struct ena_com_dev *ena_dev, return -EINVAL; } + rss->hash_func = func; rc = ena_com_set_hash_function(ena_dev); /* Restore the old function */ -- GitLab From 5131126c746631b34fcd001594b4c1c73dbc425a Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Thu, 2 May 2019 18:25:17 +0530 Subject: [PATCH 0488/1055] dmaengine: tegra210-adma: restore channel status [ Upstream commit f33e7bb3eb922618612a90f0a828c790e8880773 ] Status of ADMA channel registers is not saved and restored during system suspend. During active playback if system enters suspend, this results in wrong state of channel registers during system resume and playback fails to resume properly. Fix this by saving following channel registers in runtime suspend and restore during runtime resume. * ADMA_CH_LOWER_SRC_ADDR * ADMA_CH_LOWER_TRG_ADDR * ADMA_CH_FIFO_CTRL * ADMA_CH_CONFIG * ADMA_CH_CTRL * ADMA_CH_CMD * ADMA_CH_TC Runtime PM calls will be inovked during system resume path if a playback or capture needs to be resumed. Hence above changes work fine for system suspend case. Fixes: f46b195799b5 ("dmaengine: tegra-adma: Add support for Tegra210 ADMA") Signed-off-by: Sameer Pujar Reviewed-by: Jon Hunter Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/tegra210-adma.c | 46 ++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index 09b6756366c3..ac2a6b800db3 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -98,6 +98,7 @@ struct tegra_adma_chan_regs { unsigned int src_addr; unsigned int trg_addr; unsigned int fifo_ctrl; + unsigned int cmd; unsigned int tc; }; @@ -127,6 +128,7 @@ struct tegra_adma_chan { enum dma_transfer_direction sreq_dir; unsigned int sreq_index; bool sreq_reserved; + struct tegra_adma_chan_regs ch_regs; /* Transfer count and position info */ unsigned int tx_buf_count; @@ -635,8 +637,30 @@ static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec, static int tegra_adma_runtime_suspend(struct device *dev) { struct tegra_adma *tdma = dev_get_drvdata(dev); + struct tegra_adma_chan_regs *ch_reg; + struct tegra_adma_chan *tdc; + int i; tdma->global_cmd = tdma_read(tdma, ADMA_GLOBAL_CMD); + if (!tdma->global_cmd) + goto clk_disable; + + for (i = 0; i < tdma->nr_channels; i++) { + tdc = &tdma->channels[i]; + ch_reg = &tdc->ch_regs; + ch_reg->cmd = tdma_ch_read(tdc, ADMA_CH_CMD); + /* skip if channel is not active */ + if (!ch_reg->cmd) + continue; + ch_reg->tc = tdma_ch_read(tdc, ADMA_CH_TC); + ch_reg->src_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_SRC_ADDR); + ch_reg->trg_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_TRG_ADDR); + ch_reg->ctrl = tdma_ch_read(tdc, ADMA_CH_CTRL); + ch_reg->fifo_ctrl = tdma_ch_read(tdc, ADMA_CH_FIFO_CTRL); + ch_reg->config = tdma_ch_read(tdc, ADMA_CH_CONFIG); + } + +clk_disable: clk_disable_unprepare(tdma->ahub_clk); return 0; @@ -645,7 +669,9 @@ static int tegra_adma_runtime_suspend(struct device *dev) static int tegra_adma_runtime_resume(struct device *dev) { struct tegra_adma *tdma = dev_get_drvdata(dev); - int ret; + struct tegra_adma_chan_regs *ch_reg; + struct tegra_adma_chan *tdc; + int ret, i; ret = clk_prepare_enable(tdma->ahub_clk); if (ret) { @@ -654,6 +680,24 @@ static int tegra_adma_runtime_resume(struct device *dev) } tdma_write(tdma, ADMA_GLOBAL_CMD, tdma->global_cmd); + if (!tdma->global_cmd) + return 0; + + for (i = 0; i < tdma->nr_channels; i++) { + tdc = &tdma->channels[i]; + ch_reg = &tdc->ch_regs; + /* skip if channel was not active earlier */ + if (!ch_reg->cmd) + continue; + tdma_ch_write(tdc, ADMA_CH_TC, ch_reg->tc); + tdma_ch_write(tdc, ADMA_CH_LOWER_SRC_ADDR, ch_reg->src_addr); + tdma_ch_write(tdc, ADMA_CH_LOWER_TRG_ADDR, ch_reg->trg_addr); + tdma_ch_write(tdc, ADMA_CH_CTRL, ch_reg->ctrl); + tdma_ch_write(tdc, ADMA_CH_FIFO_CTRL, ch_reg->fifo_ctrl); + tdma_ch_write(tdc, ADMA_CH_CONFIG, ch_reg->config); + tdma_ch_write(tdc, ADMA_CH_CMD, ch_reg->cmd); + } + return 0; } -- GitLab From acab21ffa8c0951f2180f80184c921fa4799c786 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Wed, 17 Apr 2019 16:28:37 +0800 Subject: [PATCH 0489/1055] mmc: core: fix possible use after free of host [ Upstream commit 8e1943af2986db42bee2b8dddf49a36cdb2e9219 ] In the function mmc_alloc_host, the function put_device is called to release allocated resources when mmc_gpio_alloc fails. Finally, the function pointed by host->class_dev.class->dev_release (i.e., mmc_host_classdev_release) is used to release resources including the host structure. However, after put_device, host is used and released again. Resulting in a use-after-free bug. Fixes: 1ed217194488 ("mmc: core: fix error path in mmc_host_alloc") Signed-off-by: Pan Bian Signed-off-by: Ulf Hansson Signed-off-by: Sasha Levin --- drivers/mmc/core/host.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index ad88deb2e8f3..3740fb0052a4 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -376,8 +376,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) if (mmc_gpio_alloc(host)) { put_device(&host->class_dev); - ida_simple_remove(&mmc_host_ida, host->index); - kfree(host); return NULL; } -- GitLab From 1dc93fb4fe6690531f499e99f7eb2031ad1202c5 Mon Sep 17 00:00:00 2001 From: Igor Konopko Date: Sat, 4 May 2019 20:37:59 +0200 Subject: [PATCH 0490/1055] lightnvm: pblk: fix lock order in pblk_rb_tear_down_check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 486b5aac85f6ec0b2df3e82a6a629d5eb7804db5 ] In pblk_rb_tear_down_check() the spinlock functions are not called in proper order. Fixes: a4bd217 ("lightnvm: physical block device (pblk) target") Signed-off-by: Igor Konopko Reviewed-by: Javier González Reviewed-by: Hans Holmberg Signed-off-by: Matias Bjørling Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/lightnvm/pblk-rb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/lightnvm/pblk-rb.c b/drivers/lightnvm/pblk-rb.c index c0dd17a82170..73de2deaba67 100644 --- a/drivers/lightnvm/pblk-rb.c +++ b/drivers/lightnvm/pblk-rb.c @@ -825,8 +825,8 @@ int pblk_rb_tear_down_check(struct pblk_rb *rb) } out: - spin_unlock(&rb->w_lock); spin_unlock_irq(&rb->s_lock); + spin_unlock(&rb->w_lock); return ret; } -- GitLab From ae04bb451d966c993d7afe9ed0e8655810805801 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 1 May 2019 13:27:09 +0100 Subject: [PATCH 0491/1055] afs: Fix the afs.cell and afs.volume xattr handlers [ Upstream commit c73aa4102f5b9f261a907c3b3df94cd2c478504d ] Fix the ->get handlers for the afs.cell and afs.volume xattrs to pass the source data size to memcpy() rather than target buffer size. Overcopying the source data occasionally causes the kernel to oops. Fixes: d3e3b7eac886 ("afs: Add metadata xattrs") Signed-off-by: David Howells Signed-off-by: Sasha Levin --- fs/afs/xattr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/afs/xattr.c b/fs/afs/xattr.c index 2830e4f48d85..7c6b62a94e7e 100644 --- a/fs/afs/xattr.c +++ b/fs/afs/xattr.c @@ -50,7 +50,7 @@ static int afs_xattr_get_cell(const struct xattr_handler *handler, return namelen; if (namelen > size) return -ERANGE; - memcpy(buffer, cell->name, size); + memcpy(buffer, cell->name, namelen); return namelen; } @@ -104,7 +104,7 @@ static int afs_xattr_get_volume(const struct xattr_handler *handler, return namelen; if (namelen > size) return -ERANGE; - memcpy(buffer, volname, size); + memcpy(buffer, volname, namelen); return namelen; } -- GitLab From 2d464b0246a08f2a03c4c5c3e7fc8cc226f77064 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 30 Apr 2019 17:49:28 -0500 Subject: [PATCH 0492/1055] vfio/mdev: Avoid release parent reference during error path [ Upstream commit 60e7f2c3fe9919cee9534b422865eed49f4efb15 ] During mdev parent registration in mdev_register_device(), if parent device is duplicate, it releases the reference of existing parent device. This is incorrect. Existing parent device should not be touched. Fixes: 7b96953bc640 ("vfio: Mediated device Core driver") Reviewed-by: Cornelia Huck Reviewed-by: Kirti Wankhede Reviewed-by: Maxim Levitsky Signed-off-by: Parav Pandit Signed-off-by: Alex Williamson Signed-off-by: Sasha Levin --- drivers/vfio/mdev/mdev_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index 0212f0ee8aea..8cfa71230877 100644 --- a/drivers/vfio/mdev/mdev_core.c +++ b/drivers/vfio/mdev/mdev_core.c @@ -182,6 +182,7 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops) /* Check for duplicate */ parent = __find_parent_device(dev); if (parent) { + parent = NULL; ret = -EEXIST; goto add_dev_err; } -- GitLab From f736690af39473dce29705e4a75a44c9fe242e21 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 30 Apr 2019 17:49:33 -0500 Subject: [PATCH 0493/1055] vfio/mdev: Fix aborting mdev child device removal if one fails [ Upstream commit 6093e348a5e2475c5bb2e571346460f939998670 ] device_for_each_child() stops executing callback function for remaining child devices, if callback hits an error. Each child mdev device is independent of each other. While unregistering parent device, mdev core must remove all child mdev devices. Therefore, mdev_device_remove_cb() always returns success so that device_for_each_child doesn't abort if one child removal hits error. While at it, improve remove and unregister functions for below simplicity. There isn't need to pass forced flag pointer during mdev parent removal which invokes mdev_device_remove(). So simplify the flow. mdev_device_remove() is called from two paths. 1. mdev_unregister_driver() mdev_device_remove_cb() mdev_device_remove() 2. remove_store() mdev_device_remove() Fixes: 7b96953bc640 ("vfio: Mediated device Core driver") Reviewed-by: Maxim Levitsky Signed-off-by: Parav Pandit Signed-off-by: Alex Williamson Signed-off-by: Sasha Levin --- drivers/vfio/mdev/mdev_core.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index 8cfa71230877..e052f62fdea7 100644 --- a/drivers/vfio/mdev/mdev_core.c +++ b/drivers/vfio/mdev/mdev_core.c @@ -150,10 +150,10 @@ static int mdev_device_remove_ops(struct mdev_device *mdev, bool force_remove) static int mdev_device_remove_cb(struct device *dev, void *data) { - if (!dev_is_mdev(dev)) - return 0; + if (dev_is_mdev(dev)) + mdev_device_remove(dev, true); - return mdev_device_remove(dev, data ? *(bool *)data : true); + return 0; } /* @@ -241,7 +241,6 @@ EXPORT_SYMBOL(mdev_register_device); void mdev_unregister_device(struct device *dev) { struct mdev_parent *parent; - bool force_remove = true; mutex_lock(&parent_list_lock); parent = __find_parent_device(dev); @@ -255,8 +254,7 @@ void mdev_unregister_device(struct device *dev) list_del(&parent->next); class_compat_remove_link(mdev_bus_compat_class, dev, NULL); - device_for_each_child(dev, (void *)&force_remove, - mdev_device_remove_cb); + device_for_each_child(dev, NULL, mdev_device_remove_cb); parent_remove_sysfs_files(parent); -- GitLab From cbd028fdf2ad4edaab71243346a5ba11814d8e3f Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 6 May 2019 22:44:04 +0800 Subject: [PATCH 0494/1055] l2tp: Fix possible NULL pointer dereference [ Upstream commit 638a3a1e349ddf5b82f222ff5cb3b4f266e7c278 ] BUG: unable to handle kernel NULL pointer dereference at 0000000000000128 PGD 0 P4D 0 Oops: 0000 [#1 CPU: 0 PID: 5697 Comm: modprobe Tainted: G W 5.1.0-rc7+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.9.3-0-ge2fc41e-prebuilt.qemu-project.org 04/01/2014 RIP: 0010:__lock_acquire+0x53/0x10b0 Code: 8b 1c 25 40 5e 01 00 4c 8b 6d 10 45 85 e4 0f 84 bd 06 00 00 44 8b 1d 7c d2 09 02 49 89 fe 41 89 d2 45 85 db 0f 84 47 02 00 00 <48> 81 3f a0 05 70 83 b8 00 00 00 00 44 0f 44 c0 83 fe 01 0f 86 3a RSP: 0018:ffffc90001c07a28 EFLAGS: 00010002 RAX: 0000000000000000 RBX: ffff88822f038440 RCX: 0000000000000000 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000128 RBP: ffffc90001c07a88 R08: 0000000000000001 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000001 R13: 0000000000000000 R14: 0000000000000128 R15: 0000000000000000 FS: 00007fead0811540(0000) GS:ffff888237a00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000128 CR3: 00000002310da000 CR4: 00000000000006f0 Call Trace: ? __lock_acquire+0x24e/0x10b0 lock_acquire+0xdf/0x230 ? flush_workqueue+0x71/0x530 flush_workqueue+0x97/0x530 ? flush_workqueue+0x71/0x530 l2tp_exit_net+0x170/0x2b0 [l2tp_core ? l2tp_exit_net+0x93/0x2b0 [l2tp_core ops_exit_list.isra.6+0x36/0x60 unregister_pernet_operations+0xb8/0x110 unregister_pernet_device+0x25/0x40 l2tp_init+0x55/0x1000 [l2tp_core ? 0xffffffffa018d000 do_one_initcall+0x6c/0x3cc ? do_init_module+0x22/0x1f1 ? rcu_read_lock_sched_held+0x97/0xb0 ? kmem_cache_alloc_trace+0x325/0x3b0 do_init_module+0x5b/0x1f1 load_module+0x1db1/0x2690 ? m_show+0x1d0/0x1d0 __do_sys_finit_module+0xc5/0xd0 __x64_sys_finit_module+0x15/0x20 do_syscall_64+0x6b/0x1d0 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x7fead031a839 Code: 00 f3 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 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 73 01 c3 48 8b 0d 1f f6 2c 00 f7 d8 64 89 01 48 RSP: 002b:00007ffe8d9acca8 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 RAX: ffffffffffffffda RBX: 0000560078398b80 RCX: 00007fead031a839 RDX: 0000000000000000 RSI: 000056007659dc2e RDI: 0000000000000003 RBP: 000056007659dc2e R08: 0000000000000000 R09: 0000560078398b80 R10: 0000000000000003 R11: 0000000000000246 R12: 0000000000000000 R13: 00005600783a04a0 R14: 0000000000040000 R15: 0000560078398b80 Modules linked in: l2tp_core(+) e1000 ip_tables ipv6 [last unloaded: l2tp_core CR2: 0000000000000128 ---[ end trace 8322b2b8bf83f8e1 If alloc_workqueue fails in l2tp_init, l2tp_net_ops is unregistered on failure path. Then l2tp_exit_net is called which will flush NULL workqueue, this patch add a NULL check to fix it. Fixes: 67e04c29ec0d ("l2tp: unregister l2tp_net_ops on failure path") Signed-off-by: YueHaibing Acked-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/l2tp/l2tp_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index e494f04819e9..b9be0360ab94 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1892,7 +1892,8 @@ static __net_exit void l2tp_exit_net(struct net *net) } rcu_read_unlock_bh(); - flush_workqueue(l2tp_wq); + if (l2tp_wq) + flush_workqueue(l2tp_wq); rcu_barrier(); } -- GitLab From ecad62adbecc3dde19a5ed239e16dbb76b958bcd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 11 Apr 2019 05:01:57 -0400 Subject: [PATCH 0495/1055] media: omap_vout: potential buffer overflow in vidioc_dqbuf() [ Upstream commit dd6e2a981bfe83aa4a493143fd8cf1edcda6c091 ] The "b->index" is a u32 the comes from the user in the ioctl. It hasn't been checked. We aren't supposed to use it but we're instead supposed to use the value that gets written to it when we call videobuf_dqbuf(). The videobuf_dqbuf() first memsets it to zero and then re-initializes it inside the videobuf_status() function. It's this final value which we want. Hans Verkuil pointed out that we need to check the return from videobuf_dqbuf(). I ended up doing a little cleanup related to that as well. Fixes: 72915e851da9 ("[media] V4L2: OMAP: VOUT: dma map and unmap v4l2 buffers in qbuf and dqbuf") Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/platform/omap/omap_vout.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 4d29860d27b4..18604b608ab2 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -1527,23 +1527,20 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) unsigned long size; struct videobuf_buffer *vb; - vb = q->bufs[b->index]; - if (!vout->streaming) return -EINVAL; - if (file->f_flags & O_NONBLOCK) - /* Call videobuf_dqbuf for non blocking mode */ - ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1); - else - /* Call videobuf_dqbuf for blocking mode */ - ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0); + ret = videobuf_dqbuf(q, b, !!(file->f_flags & O_NONBLOCK)); + if (ret) + return ret; + + vb = q->bufs[b->index]; addr = (unsigned long) vout->buf_phy_addr[vb->i]; size = (unsigned long) vb->size; dma_unmap_single(vout->vid_dev->v4l2_dev.dev, addr, size, DMA_TO_DEVICE); - return ret; + return 0; } static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) -- GitLab From a2b94c244825fb80e03a83c1d29522e6265cddef Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 24 Apr 2019 05:46:27 -0400 Subject: [PATCH 0496/1055] media: davinci/vpbe: array underflow in vpbe_enum_outputs() [ Upstream commit b72845ee5577b227131b1fef23f9d9a296621d7b ] In vpbe_enum_outputs() we check if (temp_index >= cfg->num_outputs) but the problem is that "temp_index" can be negative. This patch changes the types to unsigned to address this array underflow bug. Fixes: 66715cdc3224 ("[media] davinci vpbe: VPBE display driver") Signed-off-by: Dan Carpenter Acked-by: "Lad, Prabhakar" Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/platform/davinci/vpbe.c | 2 +- include/media/davinci/vpbe.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 1d3c13e36904..915af9ca4711 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -126,7 +126,7 @@ static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev, struct v4l2_output *output) { struct vpbe_config *cfg = vpbe_dev->cfg; - int temp_index = output->index; + unsigned int temp_index = output->index; if (temp_index >= cfg->num_outputs) return -EINVAL; diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h index 79a566d7defd..180a05e91497 100644 --- a/include/media/davinci/vpbe.h +++ b/include/media/davinci/vpbe.h @@ -92,7 +92,7 @@ struct vpbe_config { struct encoder_config_info *ext_encoders; /* amplifier information goes here */ struct amp_config_info *amp; - int num_outputs; + unsigned int num_outputs; /* Order is venc outputs followed by LCD and then external encoders */ struct vpbe_output *outputs; }; -- GitLab From a21d4ba48183c5c498cbdea1f64e4dbb2bad5a7f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 24 Apr 2019 12:44:18 +0300 Subject: [PATCH 0497/1055] platform/x86: alienware-wmi: printing the wrong error code [ Upstream commit 6d1f8b3d75419a8659ac916a1e9543bb3513a882 ] The "out_data" variable is uninitialized at the point. Originally, this used to print "status" instead and that seems like the correct thing to print. Fixes: bc2ef884320b ("alienware-wmi: For WMAX HDMI method, introduce a way to query HDMI cable status") Signed-off-by: Dan Carpenter Reviewed-by: Mario Limonciello Signed-off-by: Andy Shevchenko Signed-off-by: Sasha Levin --- drivers/platform/x86/alienware-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index cbd84e2e3bd4..2c82188f8486 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -570,7 +570,7 @@ static ssize_t show_hdmi_source(struct device *dev, return scnprintf(buf, PAGE_SIZE, "input [gpu] unknown\n"); } - pr_err("alienware-wmi: unknown HDMI source status: %d\n", out_data); + pr_err("alienware-wmi: unknown HDMI source status: %u\n", status); return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n"); } -- GitLab From b98958074cae36b6bc6b4267b06af266bc3ea511 Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Tue, 7 May 2019 16:37:03 +0300 Subject: [PATCH 0498/1055] crypto: caam - fix caam_dump_sg that iterates through scatterlist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8c65d35435e8cbfdf953cafe5ebe3648ee9276a2 ] Fix caam_dump_sg by correctly determining the next scatterlist entry in the list. Fixes: 5ecf8ef9103c ("crypto: caam - fix sg dump") Signed-off-by: Iuliana Prodan Reviewed-by: Horia Geantă Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- drivers/crypto/caam/error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c index 8da88beb1abb..832ba2afdcd5 100644 --- a/drivers/crypto/caam/error.c +++ b/drivers/crypto/caam/error.c @@ -22,7 +22,7 @@ void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type, size_t len; void *buf; - for (it = sg; it && tlen > 0 ; it = sg_next(sg)) { + for (it = sg; it && tlen > 0 ; it = sg_next(it)) { /* * make sure the scatterlist's page * has a valid virtual memory mapping -- GitLab From eba68981c6eb2246198d6fe8f5f959ab2ca982ff Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sun, 5 May 2019 18:47:33 +0200 Subject: [PATCH 0499/1055] netfilter: ebtables: CONFIG_COMPAT: reject trailing data after last rule [ Upstream commit 680f6af5337c98d116e4f127cea7845339dba8da ] If userspace provides a rule blob with trailing data after last target, we trigger a splat, then convert ruleset to 64bit format (with trailing data), then pass that to do_replace_finish() which then returns -EINVAL. Erroring out right away avoids the splat plus unneeded translation and error unwind. Fixes: 81e675c227ec ("netfilter: ebtables: add CONFIG_COMPAT support") Reported-by: Tetsuo Handa Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/bridge/netfilter/ebtables.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 35a670ec9077..a1834ad7422c 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -2164,7 +2164,9 @@ static int compat_copy_entries(unsigned char *data, unsigned int size_user, if (ret < 0) return ret; - WARN_ON(size_remaining); + if (size_remaining) + return -EINVAL; + return state->buf_kern_offset; } -- GitLab From 220461f5537b050ee0fc4ff129e0e68dd60fd7f6 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Mon, 1 Apr 2019 20:18:16 +0200 Subject: [PATCH 0500/1055] pwm: meson: Consider 128 a valid pre-divider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 51496e4446875726d50a5617a6e0e0dabbc2e6da ] The pre-divider allows configuring longer PWM periods compared to using the input clock directly. The pre-divider is 7 bit wide, meaning it's maximum value is 128 (the register value is off-by-one: 0x7f or 127). Change the loop to also allow for the maximum possible value to be considered valid. Fixes: 211ed630753d2f ("pwm: Add support for Meson PWM Controller") Signed-off-by: Martin Blumenstingl Acked-by: Uwe Kleine-König Reviewed-by: Neil Armstrong Signed-off-by: Thierry Reding Signed-off-by: Sasha Levin --- drivers/pwm/pwm-meson.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 9b79cbc7a715..9551f896dd6f 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -188,7 +188,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, do_div(fin_ps, fin_freq); /* Calc pre_div with the period */ - for (pre_div = 0; pre_div < MISC_CLK_DIV_MASK; pre_div++) { + for (pre_div = 0; pre_div <= MISC_CLK_DIV_MASK; pre_div++) { cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000, fin_ps * (pre_div + 1)); dev_dbg(meson->chip.dev, "fin_ps=%llu pre_div=%u cnt=%u\n", @@ -197,7 +197,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, break; } - if (pre_div == MISC_CLK_DIV_MASK) { + if (pre_div > MISC_CLK_DIV_MASK) { dev_err(meson->chip.dev, "unable to get period pre_div\n"); return -EINVAL; } -- GitLab From 6f6200cb6dc2fb7a55a218e23806c140fc89ad2e Mon Sep 17 00:00:00 2001 From: Bichao Zheng Date: Mon, 1 Apr 2019 20:18:17 +0200 Subject: [PATCH 0501/1055] pwm: meson: Don't disable PWM when setting duty repeatedly [ Upstream commit a279345807e1e0ae79567a52cfdd9d30c9174a3c ] There is an abnormally low about 20ms,when setting duty repeatedly. Because setting the duty will disable PWM and then enable. Delete this operation now. Fixes: 211ed630753d2f ("pwm: Add support for Meson PWM Controller") Signed-off-by: Bichao Zheng [ Dropped code instead of hiding it behind a comment ] Signed-off-by: Martin Blumenstingl Reviewed-by: Neil Armstrong Signed-off-by: Thierry Reding Signed-off-by: Sasha Levin --- drivers/pwm/pwm-meson.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 9551f896dd6f..3d2c36963a4f 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -325,11 +325,6 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, if (state->period != channel->state.period || state->duty_cycle != channel->state.duty_cycle || state->polarity != channel->state.polarity) { - if (channel->state.enabled) { - meson_pwm_disable(meson, pwm->hwpwm); - channel->state.enabled = false; - } - if (state->polarity != channel->state.polarity) { if (state->polarity == PWM_POLARITY_NORMAL) meson->inverter_mask |= BIT(pwm->hwpwm); -- GitLab From 1229ccad5380c4b97874bdb4d9e6c7d639417151 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 27 Apr 2019 22:43:49 +0100 Subject: [PATCH 0502/1055] ARM: riscpc: fix lack of keyboard interrupts after irq conversion [ Upstream commit 63a0666bca9311f35017be454587f3ba903644b8 ] Fix lack of keyboard interrupts for RiscPC due to incorrect conversion. Fixes: e8d36d5dbb6a ("ARM: kill off set_irq_flags usage") Signed-off-by: Russell King Signed-off-by: Sasha Levin --- arch/arm/mach-rpc/irq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-rpc/irq.c b/arch/arm/mach-rpc/irq.c index b8a61cb11207..7f0f40178634 100644 --- a/arch/arm/mach-rpc/irq.c +++ b/arch/arm/mach-rpc/irq.c @@ -118,7 +118,7 @@ extern unsigned char rpc_default_fiq_start, rpc_default_fiq_end; void __init rpc_init_irq(void) { - unsigned int irq, clr, set = 0; + unsigned int irq, clr, set; iomd_writeb(0, IOMD_IRQMASKA); iomd_writeb(0, IOMD_IRQMASKB); @@ -130,6 +130,7 @@ void __init rpc_init_irq(void) for (irq = 0; irq < NR_IRQS; irq++) { clr = IRQ_NOREQUEST; + set = 0; if (irq <= 6 || (irq >= 9 && irq <= 15)) clr |= IRQ_NOPROBE; -- GitLab From 67b69c426a1c8d5a5e771c7ff1348e1bd3803719 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 6 May 2019 15:50:18 +0300 Subject: [PATCH 0503/1055] kdb: do a sanity check on the cpu in kdb_per_cpu() [ Upstream commit b586627e10f57ee3aa8f0cfab0d6f7dc4ae63760 ] The "whichcpu" comes from argv[3]. The cpu_online() macro looks up the cpu in a bitmap of online cpus, but if the value is too high then it could read beyond the end of the bitmap and possibly Oops. Fixes: 5d5314d6795f ("kdb: core for kgdb back end (1 of 2)") Signed-off-by: Dan Carpenter Reviewed-by: Douglas Anderson Signed-off-by: Daniel Thompson Signed-off-by: Sasha Levin --- kernel/debug/kdb/kdb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 993db6b2348e..15d902daeef6 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -2634,7 +2634,7 @@ static int kdb_per_cpu(int argc, const char **argv) diag = kdbgetularg(argv[3], &whichcpu); if (diag) return diag; - if (!cpu_online(whichcpu)) { + if (whichcpu >= nr_cpu_ids || !cpu_online(whichcpu)) { kdb_printf("cpu %ld is not online\n", whichcpu); return KDB_BADCPUNUM; } -- GitLab From 616d12400dc2cf57969978fd96e257d6559ea046 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Wed, 24 Apr 2019 05:25:03 -0400 Subject: [PATCH 0504/1055] backlight: lm3630a: Return 0 on success in update_status functions [ Upstream commit d3f48ec0954c6aac736ab21c34a35d7554409112 ] lm3630a_bank_a_update_status() and lm3630a_bank_b_update_status() both return the brightness value if the brightness was successfully updated. Writing to these attributes via sysfs would cause a 'Bad address' error to be returned. These functions should return 0 on success, so let's change it to correct that error. Fixes: 28e64a68a2ef ("backlight: lm3630: apply chip revision") Signed-off-by: Brian Masney Acked-by: Pavel Machek Acked-by: Daniel Thompson Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/video/backlight/lm3630a_bl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c index 2030a6b77a09..ef2553f452ca 100644 --- a/drivers/video/backlight/lm3630a_bl.c +++ b/drivers/video/backlight/lm3630a_bl.c @@ -201,7 +201,7 @@ static int lm3630a_bank_a_update_status(struct backlight_device *bl) LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE); if (ret < 0) goto out_i2c_err; - return bl->props.brightness; + return 0; out_i2c_err: dev_err(pchip->dev, "i2c failed to access\n"); @@ -278,7 +278,7 @@ static int lm3630a_bank_b_update_status(struct backlight_device *bl) LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE); if (ret < 0) goto out_i2c_err; - return bl->props.brightness; + return 0; out_i2c_err: dev_err(pchip->dev, "i2c failed to access REG_CTRL\n"); -- GitLab From 0450254e832c40401c074c84e664d2f37bae7155 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 2 May 2019 11:32:38 -0700 Subject: [PATCH 0505/1055] thermal: cpu_cooling: Actually trace CPU load in thermal_power_cpu_get_power [ Upstream commit bf45ac18b78038e43af3c1a273cae4ab5704d2ce ] The CPU load values passed to the thermal_power_cpu_get_power tracepoint are zero for all CPUs, unless, unless the thermal_power_cpu_limit tracepoint is enabled too: irq/41-rockchip-98 [000] .... 290.972410: thermal_power_cpu_get_power: cpus=0000000f freq=1800000 load={{0x0,0x0,0x0,0x0}} dynamic_power=4815 vs irq/41-rockchip-96 [000] .... 95.773585: thermal_power_cpu_get_power: cpus=0000000f freq=1800000 load={{0x56,0x64,0x64,0x5e}} dynamic_power=4959 irq/41-rockchip-96 [000] .... 95.773596: thermal_power_cpu_limit: cpus=0000000f freq=408000 cdev_state=10 power=416 There seems to be no good reason for omitting the CPU load information depending on another tracepoint. My guess is that the intention was to check whether thermal_power_cpu_get_power is (still) enabled, however 'load_cpu != NULL' already indicates that it was at least enabled when cpufreq_get_requested_power() was entered, there seems little gain from omitting the assignment if the tracepoint was just disabled, so just remove the check. Fixes: 6828a4711f99 ("thermal: add trace events to the power allocator governor") Signed-off-by: Matthias Kaehlcke Reviewed-by: Daniel Lezcano Acked-by: Javi Merino Acked-by: Viresh Kumar Signed-off-by: Eduardo Valentin Signed-off-by: Sasha Levin --- drivers/thermal/cpu_cooling.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 908a8014cf76..aed995ec2c90 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -514,7 +514,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, load = 0; total_load += load; - if (trace_thermal_power_cpu_limit_enabled() && load_cpu) + if (load_cpu) load_cpu[i] = load; i++; -- GitLab From 857247a21385e45dbffbc87b95f3761faa04fa81 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 14 May 2019 10:49:09 +0000 Subject: [PATCH 0506/1055] EDAC/mc: Fix edac_mc_find() in case no device is found [ Upstream commit 29a0c843973bc385918158c6976e4dbe891df969 ] The function should return NULL in case no device is found, but it always returns the last checked mc device from the list even if the index did not match. Fix that. I did some analysis why this did not raise any issues for about 3 years and the reason is that edac_mc_find() is mostly used to search for existing devices. Thus, the bug is not triggered. [ bp: Drop the if (mci->mc_idx > idx) test in favor of readability. ] Fixes: c73e8833bec5 ("EDAC, mc: Fix locking around mc_devices list") Signed-off-by: Robert Richter Signed-off-by: Borislav Petkov Cc: "linux-edac@vger.kernel.org" Cc: James Morse Cc: Mauro Carvalho Chehab Link: https://lkml.kernel.org/r/20190514104838.15065-1-rrichter@marvell.com Signed-off-by: Sasha Levin --- drivers/edac/edac_mc.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index f7fa05fee45a..329021189c38 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -680,22 +680,18 @@ static int del_mc_from_global_list(struct mem_ctl_info *mci) struct mem_ctl_info *edac_mc_find(int idx) { - struct mem_ctl_info *mci = NULL; + struct mem_ctl_info *mci; struct list_head *item; mutex_lock(&mem_ctls_mutex); list_for_each(item, &mc_devices) { mci = list_entry(item, struct mem_ctl_info, link); - - if (mci->mc_idx >= idx) { - if (mci->mc_idx == idx) { - goto unlock; - } - break; - } + if (mci->mc_idx == idx) + goto unlock; } + mci = NULL; unlock: mutex_unlock(&mem_ctls_mutex); return mci; -- GitLab From 4f531be6de4085e1e61fb01ef02c4278ce263d60 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sat, 18 May 2019 17:40:14 +0200 Subject: [PATCH 0507/1055] ARM: dts: sun8i-h3: Fix wifi in Beelink X2 DT [ Upstream commit ca0961011db57e39880df0b5708df8aa3339dc6f ] mmc1 node where wifi module is connected doesn't have properly defined power supplies so wifi module is never powered up. Fix that by specifying additional power supplies. Additionally, this STB may have either Realtek or Broadcom based wifi module. One based on Broadcom module also needs external clock to work properly. Fix that by adding clock property to wifi_pwrseq node. Fixes: e582b47a9252 ("ARM: dts: sun8i-h3: Add dts for the Beelink X2 STB") Signed-off-by: Jernej Skrabec Signed-off-by: Maxime Ripard Signed-off-by: Sasha Levin --- arch/arm/boot/dts/sun8i-h3-beelink-x2.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts index 10da56e86ab8..21b38c386f1b 100644 --- a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts +++ b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts @@ -79,6 +79,8 @@ wifi_pwrseq: wifi_pwrseq { compatible = "mmc-pwrseq-simple"; reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 */ + clocks = <&rtc 1>; + clock-names = "ext_clock"; }; sound_spdif { @@ -128,6 +130,8 @@ pinctrl-names = "default"; pinctrl-0 = <&mmc1_pins_a>; vmmc-supply = <®_vcc3v3>; + vqmmc-supply = <®_vcc3v3>; + mmc-pwrseq = <&wifi_pwrseq>; bus-width = <4>; non-removable; status = "okay"; -- GitLab From 71bc62b08059915218d3fbc78092f40cedbfe446 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 16 May 2019 16:53:52 +0100 Subject: [PATCH 0508/1055] dmaengine: tegra210-adma: Fix crash during probe [ Upstream commit b53611fb1ce9b1786bd18205473e0c1d6bfa8934 ] Commit f33e7bb3eb92 ("dmaengine: tegra210-adma: restore channel status") added support to save and restore the DMA channel registers when runtime suspending the ADMA. This change is causing the kernel to crash when probing the ADMA, if the device is probed deferred when looking up the channel interrupts. The crash occurs because not all of the channel base addresses have been setup at this point and in the clean-up path of the probe, pm_runtime_suspend() is called invoking its callback which expects all the channel base addresses to be initialised. Although this could be fixed by simply checking for a NULL address, on further review of the driver it seems more appropriate that we only call pm_runtime_get_sync() after all the channel interrupts and base addresses have been configured. Therefore, fix this crash by moving the calls to pm_runtime_enable(), pm_runtime_get_sync() and tegra_adma_init() after the DMA channels have been initialised. Fixes: f33e7bb3eb92 ("dmaengine: tegra210-adma: restore channel status") Signed-off-by: Jon Hunter Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/tegra210-adma.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index ac2a6b800db3..4f4733d831a1 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -744,16 +744,6 @@ static int tegra_adma_probe(struct platform_device *pdev) return PTR_ERR(tdma->ahub_clk); } - pm_runtime_enable(&pdev->dev); - - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) - goto rpm_disable; - - ret = tegra_adma_init(tdma); - if (ret) - goto rpm_put; - INIT_LIST_HEAD(&tdma->dma_dev.channels); for (i = 0; i < tdma->nr_channels; i++) { struct tegra_adma_chan *tdc = &tdma->channels[i]; @@ -771,6 +761,16 @@ static int tegra_adma_probe(struct platform_device *pdev) tdc->tdma = tdma; } + pm_runtime_enable(&pdev->dev); + + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) + goto rpm_disable; + + ret = tegra_adma_init(tdma); + if (ret) + goto rpm_put; + dma_cap_set(DMA_SLAVE, tdma->dma_dev.cap_mask); dma_cap_set(DMA_PRIVATE, tdma->dma_dev.cap_mask); dma_cap_set(DMA_CYCLIC, tdma->dma_dev.cap_mask); @@ -812,13 +812,13 @@ static int tegra_adma_probe(struct platform_device *pdev) dma_remove: dma_async_device_unregister(&tdma->dma_dev); -irq_dispose: - while (--i >= 0) - irq_dispose_mapping(tdma->channels[i].irq); rpm_put: pm_runtime_put_sync(&pdev->dev); rpm_disable: pm_runtime_disable(&pdev->dev); +irq_dispose: + while (--i >= 0) + irq_dispose_mapping(tdma->channels[i].irq); return ret; } -- GitLab From 733ab5b38187791b0cc9e7de8f0f795be5cd48d9 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 18 Apr 2019 14:27:09 +0200 Subject: [PATCH 0509/1055] arm64: dts: meson: libretech-cc: set eMMC as removable [ Upstream commit 9f72e321d5506fe3e162a6308a4a295d7f10bb5d ] The eMMC on this board is add-on module which is not mandatory. Removing 'non-removable' property should prevent some errors when booting a board w/o an eMMC module present. Fixes: 72fb2c852188 ("ARM64: dts: meson-gxl-s905x-libretech-cc: fixup board definition") Signed-off-by: Jerome Brunet Reviewed-by: Martin Blumenstingl Signed-off-by: Kevin Hilman Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts index e2c71753e327..407d32f4fe73 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts @@ -226,7 +226,6 @@ cap-mmc-highspeed; mmc-ddr-3_3v; max-frequency = <50000000>; - non-removable; disable-wp; mmc-pwrseq = <&emmc_pwrseq>; -- GitLab From 6a494caf49a7fc9946d87bbd347a8965e9200b39 Mon Sep 17 00:00:00 2001 From: Sagiv Ozeri Date: Mon, 20 May 2019 12:33:20 +0300 Subject: [PATCH 0510/1055] RDMA/qedr: Fix incorrect device rate. [ Upstream commit 69054666df0a9b4e8331319f98b6b9a88bc3fcc4 ] Use the correct enum value introduced in commit 12113a35ada6 ("IB/core: Add HDR speed enum") Prior to this change a 50Gbps port would show 40Gbps. This patch also cleaned up the redundant redefiniton of ib speeds for qedr. Fixes: 12113a35ada6 ("IB/core: Add HDR speed enum") Signed-off-by: Sagiv Ozeri Signed-off-by: Michal Kalderon Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/hw/qedr/verbs.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 8bfe9073da78..6ae72accae3d 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -178,54 +178,47 @@ int qedr_query_device(struct ib_device *ibdev, return 0; } -#define QEDR_SPEED_SDR (1) -#define QEDR_SPEED_DDR (2) -#define QEDR_SPEED_QDR (4) -#define QEDR_SPEED_FDR10 (8) -#define QEDR_SPEED_FDR (16) -#define QEDR_SPEED_EDR (32) - static inline void get_link_speed_and_width(int speed, u8 *ib_speed, u8 *ib_width) { switch (speed) { case 1000: - *ib_speed = QEDR_SPEED_SDR; + *ib_speed = IB_SPEED_SDR; *ib_width = IB_WIDTH_1X; break; case 10000: - *ib_speed = QEDR_SPEED_QDR; + *ib_speed = IB_SPEED_QDR; *ib_width = IB_WIDTH_1X; break; case 20000: - *ib_speed = QEDR_SPEED_DDR; + *ib_speed = IB_SPEED_DDR; *ib_width = IB_WIDTH_4X; break; case 25000: - *ib_speed = QEDR_SPEED_EDR; + *ib_speed = IB_SPEED_EDR; *ib_width = IB_WIDTH_1X; break; case 40000: - *ib_speed = QEDR_SPEED_QDR; + *ib_speed = IB_SPEED_QDR; *ib_width = IB_WIDTH_4X; break; case 50000: - *ib_speed = QEDR_SPEED_QDR; - *ib_width = IB_WIDTH_4X; + *ib_speed = IB_SPEED_HDR; + *ib_width = IB_WIDTH_1X; break; case 100000: - *ib_speed = QEDR_SPEED_EDR; + *ib_speed = IB_SPEED_EDR; *ib_width = IB_WIDTH_4X; break; default: /* Unsupported */ - *ib_speed = QEDR_SPEED_SDR; + *ib_speed = IB_SPEED_SDR; *ib_width = IB_WIDTH_1X; } } -- GitLab From 0d56b73c7e727b3a1de39035a504637b800adccd Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Wed, 22 May 2019 11:00:36 +0000 Subject: [PATCH 0511/1055] spi: spi-fsl-spi: call spi_finalize_current_message() at the end [ Upstream commit 44a042182cb1e9f7916e015c836967bf638b33c4 ] spi_finalize_current_message() shall be called once all actions are finished, otherwise the last actions might step over a newly started transfer. Fixes: c592becbe704 ("spi: fsl-(e)spi: migrate to generic master queueing") Signed-off-by: Christophe Leroy Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-fsl-spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 8b79e36fab21..cd784552de7f 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -407,7 +407,6 @@ static int fsl_spi_do_one_msg(struct spi_master *master, } m->status = status; - spi_finalize_current_message(master); if (status || !cs_change) { ndelay(nsecs); @@ -415,6 +414,7 @@ static int fsl_spi_do_one_msg(struct spi_master *master, } fsl_spi_setup_transfer(spi, NULL); + spi_finalize_current_message(master); return 0; } -- GitLab From a90e4a8e08333eaae2767a766c4fd6d165af10d4 Mon Sep 17 00:00:00 2001 From: "Hook, Gary" Date: Tue, 14 May 2019 21:53:23 +0000 Subject: [PATCH 0512/1055] crypto: ccp - fix AES CFB error exposed by new test vectors [ Upstream commit c3b359d6567c0b8f413e924feb37cf025067d55a ] Updated testmgr will exhibit this error message when loading the ccp-crypto module: alg: skcipher: cfb-aes-ccp encryption failed with err -22 on test vector 3, cfg="in-place" Update the CCP crypto driver to correctly treat CFB as a streaming mode cipher (instead of block mode). Update the configuration for CFB to specify the block size as a single byte; Fixes: 2b789435d7f3 ('crypto: ccp - CCP AES crypto API support') Signed-off-by: Gary R Hook Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- drivers/crypto/ccp/ccp-crypto-aes.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c index 89291c15015c..3f768699332b 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes.c +++ b/drivers/crypto/ccp/ccp-crypto-aes.c @@ -1,7 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * AMD Cryptographic Coprocessor (CCP) AES crypto API support * - * Copyright (C) 2013,2016 Advanced Micro Devices, Inc. + * Copyright (C) 2013-2019 Advanced Micro Devices, Inc. * * Author: Tom Lendacky * @@ -79,8 +80,7 @@ static int ccp_aes_crypt(struct ablkcipher_request *req, bool encrypt) return -EINVAL; if (((ctx->u.aes.mode == CCP_AES_MODE_ECB) || - (ctx->u.aes.mode == CCP_AES_MODE_CBC) || - (ctx->u.aes.mode == CCP_AES_MODE_CFB)) && + (ctx->u.aes.mode == CCP_AES_MODE_CBC)) && (req->nbytes & (AES_BLOCK_SIZE - 1))) return -EINVAL; @@ -291,7 +291,7 @@ static struct ccp_aes_def aes_algs[] = { .version = CCP_VERSION(3, 0), .name = "cfb(aes)", .driver_name = "cfb-aes-ccp", - .blocksize = AES_BLOCK_SIZE, + .blocksize = 1, .ivsize = AES_BLOCK_SIZE, .alg_defaults = &ccp_aes_defaults, }, -- GitLab From 9080a21773ca3f60d98b0126951a6135c2d96f66 Mon Sep 17 00:00:00 2001 From: "Hook, Gary" Date: Tue, 14 May 2019 21:53:30 +0000 Subject: [PATCH 0513/1055] crypto: ccp - Fix 3DES complaint from ccp-crypto module [ Upstream commit 89646fdda4cae203185444ac7988835f36a21ee1 ] Crypto self-tests reveal an error: alg: skcipher: cbc-des3-ccp encryption test failed (wrong output IV) on test vector 0, cfg="in-place" The offset value should not be recomputed when retrieving the context. Also, a code path exists which makes decisions based on older (version 3) hardware; a v3 device deosn't support 3DES so remove this check. Fixes: 990672d48515 ('crypto: ccp - Enable 3DES function on v5 CCPs') Signed-off-by: Gary R Hook Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- drivers/crypto/ccp/ccp-ops.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index 1e2e42106dee..4b48b8523a40 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -1293,6 +1293,9 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) int ret; /* Error checks */ + if (cmd_q->ccp->vdata->version < CCP_VERSION(5, 0)) + return -EINVAL; + if (!cmd_q->ccp->vdata->perform->des3) return -EINVAL; @@ -1375,8 +1378,6 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) * passthru option to convert from big endian to little endian. */ if (des3->mode != CCP_DES3_MODE_ECB) { - u32 load_mode; - op.sb_ctx = cmd_q->sb_ctx; ret = ccp_init_dm_workarea(&ctx, cmd_q, @@ -1392,12 +1393,8 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) if (ret) goto e_ctx; - if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) - load_mode = CCP_PASSTHRU_BYTESWAP_NOOP; - else - load_mode = CCP_PASSTHRU_BYTESWAP_256BIT; ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx, - load_mode); + CCP_PASSTHRU_BYTESWAP_256BIT); if (ret) { cmd->engine_error = cmd_q->cmd_error; goto e_ctx; @@ -1459,10 +1456,6 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) } /* ...but we only need the last DES3_EDE_BLOCK_SIZE bytes */ - if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0)) - dm_offset = CCP_SB_BYTES - des3->iv_len; - else - dm_offset = 0; ccp_get_dm_area(&ctx, dm_offset, des3->iv, 0, DES3_EDE_BLOCK_SIZE); } -- GitLab From 58828c8a7ba68580c5683781cfcc644d43c21778 Mon Sep 17 00:00:00 2001 From: Erwan Le Ray Date: Tue, 21 May 2019 17:45:42 +0200 Subject: [PATCH 0514/1055] serial: stm32: fix rx error handling [ Upstream commit 4f01d833fdcdd6f9b85d9e5d5d7568eb683626a7 ] - Fixes parity and framing error bit by clearing parity and framing error flag. The current implementation doesn't clear the error bits when an error is detected. - Fixes the incorrect name of framing error clearing flag in header file. - Fixes misalignement between data frame and errors status. The status read for "n" frame was the status of "n+1" frame". - Fixes break detection was not triggered by the expected register. Fixes: 48a6092fb41f ("serial: stm32-usart: Add STM32 USART Driver") Signed-off-by: Erwan Le Ray Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/stm32-usart.c | 54 +++++++++++++++++++++----------- drivers/tty/serial/stm32-usart.h | 10 ++---- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 03a583264d9e..c43590077372 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -118,35 +118,51 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) { sr |= USART_SR_DUMMY_RX; - c = stm32_get_char(port, &sr, &stm32_port->last_res); flag = TTY_NORMAL; - port->icount.rx++; + /* + * Status bits has to be cleared before reading the RDR: + * In FIFO mode, reading the RDR will pop the next data + * (if any) along with its status bits into the SR. + * Not doing so leads to misalignement between RDR and SR, + * and clear status bits of the next rx data. + * + * Clear errors flags for stm32f7 and stm32h7 compatible + * devices. On stm32f4 compatible devices, the error bit is + * cleared by the sequence [read SR - read DR]. + */ + if ((sr & USART_SR_ERR_MASK) && ofs->icr != UNDEF_REG) + stm32_clr_bits(port, ofs->icr, USART_ICR_ORECF | + USART_ICR_PECF | USART_ICR_FECF); + + c = stm32_get_char(port, &sr, &stm32_port->last_res); + port->icount.rx++; if (sr & USART_SR_ERR_MASK) { - if (sr & USART_SR_LBD) { - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (sr & USART_SR_ORE) { - if (ofs->icr != UNDEF_REG) - writel_relaxed(USART_ICR_ORECF, - port->membase + - ofs->icr); + if (sr & USART_SR_ORE) { port->icount.overrun++; } else if (sr & USART_SR_PE) { port->icount.parity++; } else if (sr & USART_SR_FE) { - port->icount.frame++; + /* Break detection if character is null */ + if (!c) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else { + port->icount.frame++; + } } sr &= port->read_status_mask; - if (sr & USART_SR_LBD) - flag = TTY_BREAK; - else if (sr & USART_SR_PE) + if (sr & USART_SR_PE) { flag = TTY_PARITY; - else if (sr & USART_SR_FE) - flag = TTY_FRAME; + } else if (sr & USART_SR_FE) { + if (!c) + flag = TTY_BREAK; + else + flag = TTY_FRAME; + } } if (uart_handle_sysrq_char(port, c)) @@ -569,14 +585,14 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, if (termios->c_iflag & INPCK) port->read_status_mask |= USART_SR_PE | USART_SR_FE; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - port->read_status_mask |= USART_SR_LBD; + port->read_status_mask |= USART_SR_FE; /* Characters to ignore */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) port->ignore_status_mask = USART_SR_PE | USART_SR_FE; if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= USART_SR_LBD; + port->ignore_status_mask |= USART_SR_FE; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index ffc0c5285e51..9d087881913a 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -108,7 +108,6 @@ struct stm32_usart_info stm32h7_info = { #define USART_SR_RXNE BIT(5) #define USART_SR_TC BIT(6) #define USART_SR_TXE BIT(7) -#define USART_SR_LBD BIT(8) #define USART_SR_CTSIF BIT(9) #define USART_SR_CTS BIT(10) /* F7 */ #define USART_SR_RTOF BIT(11) /* F7 */ @@ -120,8 +119,7 @@ struct stm32_usart_info stm32h7_info = { #define USART_SR_SBKF BIT(18) /* F7 */ #define USART_SR_WUF BIT(20) /* H7 */ #define USART_SR_TEACK BIT(21) /* F7 */ -#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \ - USART_SR_FE | USART_SR_PE) +#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_FE | USART_SR_PE) /* Dummy bits */ #define USART_SR_DUMMY_RX BIT(16) @@ -166,8 +164,6 @@ struct stm32_usart_info stm32h7_info = { /* USART_CR2 */ #define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */ #define USART_CR2_ADDM7 BIT(4) /* F7 */ -#define USART_CR2_LBDL BIT(5) -#define USART_CR2_LBDIE BIT(6) #define USART_CR2_LBCL BIT(8) #define USART_CR2_CPHA BIT(9) #define USART_CR2_CPOL BIT(10) @@ -224,12 +220,10 @@ struct stm32_usart_info stm32h7_info = { /* USART_ICR */ #define USART_ICR_PECF BIT(0) /* F7 */ -#define USART_ICR_FFECF BIT(1) /* F7 */ -#define USART_ICR_NCF BIT(2) /* F7 */ +#define USART_ICR_FECF BIT(1) /* F7 */ #define USART_ICR_ORECF BIT(3) /* F7 */ #define USART_ICR_IDLECF BIT(4) /* F7 */ #define USART_ICR_TCCF BIT(6) /* F7 */ -#define USART_ICR_LBDCF BIT(8) /* F7 */ #define USART_ICR_CTSCF BIT(9) /* F7 */ #define USART_ICR_RTOCF BIT(11) /* F7 */ #define USART_ICR_EOBCF BIT(12) /* F7 */ -- GitLab From 2e0f6b8569f2a2b447a13dfecacd35a6bc3aa421 Mon Sep 17 00:00:00 2001 From: Erwan Le Ray Date: Tue, 21 May 2019 17:45:44 +0200 Subject: [PATCH 0515/1055] serial: stm32: fix transmit_chars when tx is stopped [ Upstream commit b83b957c91f68e53f0dc596e129e8305761f2a32 ] Disables the tx irq when the transmission is ended and updates stop_tx conditions for code cleanup. Fixes: 48a6092fb41f ("serial: stm32-usart: Add STM32 USART Driver") Signed-off-by: Erwan Le Ray Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/stm32-usart.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index c43590077372..a1e31913bcf9 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -310,13 +310,8 @@ static void stm32_transmit_chars(struct uart_port *port) return; } - if (uart_tx_stopped(port)) { - stm32_stop_tx(port); - return; - } - - if (uart_circ_empty(xmit)) { - stm32_stop_tx(port); + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); return; } @@ -329,7 +324,7 @@ static void stm32_transmit_chars(struct uart_port *port) uart_write_wakeup(port); if (uart_circ_empty(xmit)) - stm32_stop_tx(port); + stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); } static irqreturn_t stm32_interrupt(int irq, void *ptr) -- GitLab From 6859cf2284a7c4be2e8678bf75ffd7c8f51a0147 Mon Sep 17 00:00:00 2001 From: Erwan Le Ray Date: Tue, 21 May 2019 17:45:45 +0200 Subject: [PATCH 0516/1055] serial: stm32: Add support of TC bit status check [ Upstream commit 64c32eab660386f9904bb295a104c9c425e9f8b2 ] Adds a check on the Transmission Complete bit status before closing the com port. Prevents the port closure before the end of the transmission. TC poll loop is moved from stm32_tx_dma_complete to stm32_shutdown routine, in order to check TC before shutdown in both dma and PIO tx modes. TC clear is added in stm32_transmit_char routine, in order to be cleared before transmitting in both dma and PIO tx modes. Fixes: 3489187204eb ("serial: stm32: adding dma support") Signed-off-by: Erwan Le Ray Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/stm32-usart.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index a1e31913bcf9..2384f786b76d 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -180,21 +180,6 @@ static void stm32_tx_dma_complete(void *arg) struct uart_port *port = arg; struct stm32_port *stm32port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32port->info->ofs; - unsigned int isr; - int ret; - - ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, - isr, - (isr & USART_SR_TC), - 10, 100000); - - if (ret) - dev_err(port->dev, "terminal count not set\n"); - - if (ofs->icr == UNDEF_REG) - stm32_clr_bits(port, ofs->isr, USART_SR_TC); - else - stm32_set_bits(port, ofs->icr, USART_CR_TC); stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); stm32port->tx_dma_busy = false; @@ -286,7 +271,6 @@ static void stm32_transmit_chars_dma(struct uart_port *port) /* Issue pending DMA TX requests */ dma_async_issue_pending(stm32port->tx_ch); - stm32_clr_bits(port, ofs->isr, USART_SR_TC); stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT); xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); @@ -315,6 +299,11 @@ static void stm32_transmit_chars(struct uart_port *port) return; } + if (ofs->icr == UNDEF_REG) + stm32_clr_bits(port, ofs->isr, USART_SR_TC); + else + stm32_set_bits(port, ofs->icr, USART_ICR_TCCF); + if (stm32_port->tx_ch) stm32_transmit_chars_dma(port); else @@ -491,12 +480,21 @@ static void stm32_shutdown(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct stm32_usart_config *cfg = &stm32_port->info->cfg; - u32 val; + u32 val, isr; + int ret; val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; val |= BIT(cfg->uart_enable_bit); if (stm32_port->fifoen) val |= USART_CR1_FIFOEN; + + ret = readl_relaxed_poll_timeout(port->membase + ofs->isr, + isr, (isr & USART_SR_TC), + 10, 100000); + + if (ret) + dev_err(port->dev, "transmission complete not set\n"); + stm32_clr_bits(port, ofs->cr1, val); dev_pm_clear_wake_irq(port->dev); -- GitLab From c837323da42905c0dd26bf062ed4d3a2eedc41f5 Mon Sep 17 00:00:00 2001 From: Erwan Le Ray Date: Tue, 21 May 2019 17:45:46 +0200 Subject: [PATCH 0517/1055] serial: stm32: fix wakeup source initialization [ Upstream commit 5297f274e8b61ceb9676cba6649d3de9d03387ad ] Fixes dedicated_irq_wakeup issue and deactivated uart as wakeup source by default. Fixes: 270e5a74fe4c ("serial: stm32: add wakeup mechanism") Signed-off-by: Erwan Le Ray Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/stm32-usart.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 2384f786b76d..f8f3f8fafd9f 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -447,7 +447,6 @@ static int stm32_startup(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct stm32_usart_config *cfg = &stm32_port->info->cfg; const char *name = to_platform_device(port->dev)->name; u32 val; int ret; @@ -458,15 +457,6 @@ static int stm32_startup(struct uart_port *port) if (ret) return ret; - if (cfg->has_wakeup && stm32_port->wakeirq >= 0) { - ret = dev_pm_set_dedicated_wake_irq(port->dev, - stm32_port->wakeirq); - if (ret) { - free_irq(port->irq, port); - return ret; - } - } - val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; if (stm32_port->fifoen) val |= USART_CR1_FIFOEN; @@ -497,7 +487,6 @@ static void stm32_shutdown(struct uart_port *port) stm32_clr_bits(port, ofs->cr1, val); - dev_pm_clear_wake_irq(port->dev); free_irq(port->irq, port); } @@ -904,11 +893,18 @@ static int stm32_serial_probe(struct platform_device *pdev) ret = device_init_wakeup(&pdev->dev, true); if (ret) goto err_uninit; + + ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, + stm32port->wakeirq); + if (ret) + goto err_nowup; + + device_set_wakeup_enable(&pdev->dev, false); } ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); if (ret) - goto err_nowup; + goto err_wirq; ret = stm32_of_dma_rx_probe(stm32port, pdev); if (ret) @@ -922,6 +918,10 @@ static int stm32_serial_probe(struct platform_device *pdev) return 0; +err_wirq: + if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) + dev_pm_clear_wake_irq(&pdev->dev); + err_nowup: if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) device_init_wakeup(&pdev->dev, false); @@ -959,8 +959,10 @@ static int stm32_serial_remove(struct platform_device *pdev) TX_BUF_L, stm32_port->tx_buf, stm32_port->tx_dma_buf); - if (cfg->has_wakeup && stm32_port->wakeirq >= 0) + if (cfg->has_wakeup && stm32_port->wakeirq >= 0) { + dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); + } clk_disable_unprepare(stm32_port->clk); -- GitLab From 50eafd6938decd0693085d0b713060bd0e539d8b Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Fri, 24 May 2019 09:15:17 -0700 Subject: [PATCH 0518/1055] misc: sgi-xp: Properly initialize buf in xpc_get_rsvd_page_pa [ Upstream commit b0576f9ecb5c51e9932531d23c447b2739261841 ] Clang warns: drivers/misc/sgi-xp/xpc_partition.c:73:14: warning: variable 'buf' is uninitialized when used within its own initialization [-Wuninitialized] void *buf = buf; ~~~ ^~~ 1 warning generated. Arnd's explanation during review: /* * Returns the physical address of the partition's reserved page through * an iterative number of calls. * * On first call, 'cookie' and 'len' should be set to 0, and 'addr' * set to the nasid of the partition whose reserved page's address is * being sought. * On subsequent calls, pass the values, that were passed back on the * previous call. * * While the return status equals SALRET_MORE_PASSES, keep calling * this function after first copying 'len' bytes starting at 'addr' * into 'buf'. Once the return status equals SALRET_OK, 'addr' will * be the physical address of the partition's reserved page. If the * return status equals neither of these, an error as occurred. */ static inline s64 sn_partition_reserved_page_pa(u64 buf, u64 *cookie, u64 *addr, u64 *len) so *len is set to zero on the first call and tells the bios how many bytes are accessible at 'buf', and it does get updated by the BIOS to tell us how many bytes it needs, and then we allocate that and try again. Fixes: 279290294662 ("[IA64-SGI] cleanup the way XPC locates the reserved page") Link: https://github.com/ClangBuiltLinux/linux/issues/466 Suggested-by: Stephen Hines Reviewed-by: Arnd Bergmann Reviewed-by: Nick Desaulniers Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/misc/sgi-xp/xpc_partition.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 6956f7e7d439..ca5f0102daef 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -70,7 +70,7 @@ xpc_get_rsvd_page_pa(int nasid) unsigned long rp_pa = nasid; /* seed with nasid */ size_t len = 0; size_t buf_len = 0; - void *buf = buf; + void *buf = NULL; void *buf_base = NULL; enum xp_retval (*get_partition_rsvd_page_pa) (void *, u64 *, unsigned long *, size_t *) = -- GitLab From a31ef6b36d7703379d46914eae56f65b6d6e108b Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Tue, 21 May 2019 15:27:35 +0800 Subject: [PATCH 0519/1055] iommu: Use right function to get group for device [ Upstream commit 57274ea25736496ee019a5c40479855b21888839 ] The iommu_group_get_for_dev() will allocate a group for a device if it isn't in any group. This isn't the use case in iommu_request_dm_for_dev(). Let's use iommu_group_get() instead. Fixes: d290f1e70d85a ("iommu: Introduce iommu_request_dm_for_dev()") Signed-off-by: Lu Baolu Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/iommu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 4b761678a18b..2c48a9d6d91e 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1856,9 +1856,9 @@ int iommu_request_dm_for_dev(struct device *dev) int ret; /* Device must already be in a group before calling this function */ - group = iommu_group_get_for_dev(dev); - if (IS_ERR(group)) - return PTR_ERR(group); + group = iommu_group_get(dev); + if (!group) + return -EINVAL; mutex_lock(&group->mutex); -- GitLab From 9360b13308b085c57430e8b28fa5ea1ecf6e6645 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 15 May 2019 12:33:50 -0500 Subject: [PATCH 0520/1055] signal/cifs: Fix cifs_put_tcp_session to call send_sig instead of force_sig [ Upstream commit 72abe3bcf0911d69b46c1e8bdb5612675e0ac42c ] The locking in force_sig_info is not prepared to deal with a task that exits or execs (as sighand may change). The is not a locking problem in force_sig as force_sig is only built to handle synchronous exceptions. Further the function force_sig_info changes the signal state if the signal is ignored, or blocked or if SIGNAL_UNKILLABLE will prevent the delivery of the signal. The signal SIGKILL can not be ignored and can not be blocked and SIGNAL_UNKILLABLE won't prevent it from being delivered. So using force_sig rather than send_sig for SIGKILL is confusing and pointless. Because it won't impact the sending of the signal and and because using force_sig is wrong, replace force_sig with send_sig. Cc: Namjae Jeon Cc: Jeff Layton Cc: Steve French Fixes: a5c3e1c725af ("Revert "cifs: No need to send SIGKILL to demux_thread during umount"") Fixes: e7ddee9037e7 ("cifs: disable sharing session and tcon and add new TCP sharing code") Signed-off-by: "Eric W. Biederman" Signed-off-by: Sasha Levin --- fs/cifs/connect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f523a9ca9574..51bbb1c0b71a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2320,7 +2320,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) task = xchg(&server->tsk, NULL); if (task) - force_sig(SIGKILL, task); + send_sig(SIGKILL, task, 1); } static struct TCP_Server_Info * -- GitLab From 4f80b033f61bafc56239ae6507d944aa4d13ddd6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 27 May 2019 16:56:48 -0700 Subject: [PATCH 0521/1055] inet: frags: call inet_frags_fini() after unregister_pernet_subsys() [ Upstream commit ae7352d384a552d8c799c242e74a934809990a71 ] Both IPv6 and 6lowpan are calling inet_frags_fini() too soon. inet_frags_fini() is dismantling a kmem_cache, that might be needed later when unregister_pernet_subsys() eventually has to remove frags queues from hash tables and free them. This fixes potential use-after-free, and is a prereq for the following patch. Fixes: d4ad4d22e7ac ("inet: frags: use kmem_cache for inet_frag_queue") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/ieee802154/6lowpan/reassembly.c | 2 +- net/ipv6/reassembly.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c index ec7a5da56129..e873a6a007f2 100644 --- a/net/ieee802154/6lowpan/reassembly.c +++ b/net/ieee802154/6lowpan/reassembly.c @@ -634,7 +634,7 @@ int __init lowpan_net_frag_init(void) void lowpan_net_frag_exit(void) { - inet_frags_fini(&lowpan_frags); lowpan_frags_sysctl_unregister(); unregister_pernet_subsys(&lowpan_frags_ops); + inet_frags_fini(&lowpan_frags); } diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index fe797b29ca89..6dea6e92e686 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -593,8 +593,8 @@ int __init ipv6_frag_init(void) void ipv6_frag_exit(void) { - inet_frags_fini(&ip6_frags); ip6_frags_sysctl_unregister(); unregister_pernet_subsys(&ip6_frags_ops); inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT); + inet_frags_fini(&ip6_frags); } -- GitLab From 7313729555616597f2ca79cb72de28778298abeb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 28 May 2019 11:47:30 -0700 Subject: [PATCH 0522/1055] netvsc: unshare skb in VF rx handler [ Upstream commit 996ed04741467f6d1552440c92988b132a9487ec ] The netvsc VF skb handler should make sure that skb is not shared. Similar logic already exists in bonding and team device drivers. This is not an issue in practice because the VF devicex does not send up shared skb's. But the netvsc driver should do the right thing if it did. Fixes: 0c195567a8f6 ("netvsc: transparent VF management") Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/hyperv/netvsc_drv.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index a89de5752a8c..9e48855f6407 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -1840,6 +1840,12 @@ static rx_handler_result_t netvsc_vf_handle_frame(struct sk_buff **pskb) struct netvsc_vf_pcpu_stats *pcpu_stats = this_cpu_ptr(ndev_ctx->vf_stats); + skb = skb_share_check(skb, GFP_ATOMIC); + if (unlikely(!skb)) + return RX_HANDLER_CONSUMED; + + *pskb = skb; + skb->dev = ndev; u64_stats_update_begin(&pcpu_stats->syncp); -- GitLab From 0ba089779082da6e53b4a57d478091a94e94abb4 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 22 May 2019 11:45:46 -0700 Subject: [PATCH 0523/1055] cpufreq: brcmstb-avs-cpufreq: Fix initial command check [ Upstream commit 22a26cc6a51ef73dcfeb64c50513903f6b2d53d8 ] There is a logical error in brcm_avs_is_firmware_loaded() whereby if the firmware returns -EINVAL, we will be reporting this as an error. The comment is correct, the code was not. Fixes: de322e085995 ("cpufreq: brcmstb-avs-cpufreq: AVS CPUfreq driver for Broadcom STB SoCs") Signed-off-by: Florian Fainelli Acked-by: Markus Mayer Signed-off-by: Viresh Kumar Signed-off-by: Sasha Levin --- drivers/cpufreq/brcmstb-avs-cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c index 7281a2c19c36..bae319037658 100644 --- a/drivers/cpufreq/brcmstb-avs-cpufreq.c +++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c @@ -762,8 +762,8 @@ static bool brcm_avs_is_firmware_loaded(struct private_data *priv) rc = brcm_avs_get_pmap(priv, NULL); magic = readl(priv->base + AVS_MBOX_MAGIC); - return (magic == AVS_FIRMWARE_MAGIC) && (rc != -ENOTSUPP) && - (rc != -EINVAL); + return (magic == AVS_FIRMWARE_MAGIC) && ((rc != -ENOTSUPP) || + (rc != -EINVAL)); } static unsigned int brcm_avs_cpufreq_get(unsigned int cpu) -- GitLab From d4fa8aa0ef869c05559653c23359c68c5bb921b7 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 22 May 2019 11:45:47 -0700 Subject: [PATCH 0524/1055] cpufreq: brcmstb-avs-cpufreq: Fix types for voltage/frequency [ Upstream commit 4c5681fcc684c762b09435de3e82ffeee7769d21 ] What we read back from the register is going to be capped at 32-bits, and cpufreq_freq_table.frequency is an unsigned int. Avoid any possible value truncation by using the appropriate return value. Fixes: de322e085995 ("cpufreq: brcmstb-avs-cpufreq: AVS CPUfreq driver for Broadcom STB SoCs") Signed-off-by: Florian Fainelli Acked-by: Markus Mayer Signed-off-by: Viresh Kumar Signed-off-by: Sasha Levin --- drivers/cpufreq/brcmstb-avs-cpufreq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c index bae319037658..39c462711eae 100644 --- a/drivers/cpufreq/brcmstb-avs-cpufreq.c +++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c @@ -468,12 +468,12 @@ static int brcm_avs_set_pstate(struct private_data *priv, unsigned int pstate) return __issue_avs_command(priv, AVS_CMD_SET_PSTATE, true, args); } -static unsigned long brcm_avs_get_voltage(void __iomem *base) +static u32 brcm_avs_get_voltage(void __iomem *base) { return readl(base + AVS_MBOX_VOLTAGE1); } -static unsigned long brcm_avs_get_frequency(void __iomem *base) +static u32 brcm_avs_get_frequency(void __iomem *base) { return readl(base + AVS_MBOX_FREQUENCY) * 1000; /* in kHz */ } @@ -973,14 +973,14 @@ static ssize_t show_brcm_avs_voltage(struct cpufreq_policy *policy, char *buf) { struct private_data *priv = policy->driver_data; - return sprintf(buf, "0x%08lx\n", brcm_avs_get_voltage(priv->base)); + return sprintf(buf, "0x%08x\n", brcm_avs_get_voltage(priv->base)); } static ssize_t show_brcm_avs_frequency(struct cpufreq_policy *policy, char *buf) { struct private_data *priv = policy->driver_data; - return sprintf(buf, "0x%08lx\n", brcm_avs_get_frequency(priv->base)); + return sprintf(buf, "0x%08x\n", brcm_avs_get_frequency(priv->base)); } cpufreq_freq_attr_ro(brcm_avs_pstate); -- GitLab From 317357415bef2cc2ec618d4c4f274abbcdc20bab Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 4 Jun 2019 10:55:15 -0400 Subject: [PATCH 0525/1055] media: vivid: fix incorrect assignment operation when setting video mode [ Upstream commit d4ec9550e4b2d2e357a46fdc65d8ef3d4d15984c ] The assigment of FB_VMODE_NONINTERLACE to var->vmode should be a bit-wise or of FB_VMODE_NONINTERLACE instead of an assignment, otherwise the previous clearing of the FB_VMODE_MASK bits of var->vmode makes no sense and is redundant. Addresses-Coverity: ("Unused value") Fixes: ad4e02d5081d ("[media] vivid: add a simple framebuffer device for overlay testing") Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/platform/vivid/vivid-osd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c index bdc380b14e0c..a95b7c56569e 100644 --- a/drivers/media/platform/vivid/vivid-osd.c +++ b/drivers/media/platform/vivid/vivid-osd.c @@ -167,7 +167,7 @@ static int _vivid_fb_check_var(struct fb_var_screeninfo *var, struct vivid_dev * var->nonstd = 0; var->vmode &= ~FB_VMODE_MASK; - var->vmode = FB_VMODE_NONINTERLACED; + var->vmode |= FB_VMODE_NONINTERLACED; /* Dummy values */ var->hsync_len = 24; -- GitLab From 21b0815f71553fe95ddc16caf5b33eecad2bd56d Mon Sep 17 00:00:00 2001 From: George Wilkie Date: Fri, 7 Jun 2019 11:49:41 +0100 Subject: [PATCH 0526/1055] mpls: fix warning with multi-label encap [ Upstream commit 2f3f7d1fa0d1039b24a55d127ed190f196fc3e79 ] If you configure a route with multiple labels, e.g. ip route add 10.10.3.0/24 encap mpls 16/100 via 10.10.2.2 dev ens4 A warning is logged: kernel: [ 130.561819] netlink: 'ip': attribute type 1 has an invalid length. This happens because mpls_iptunnel_policy has set the type of MPLS_IPTUNNEL_DST to fixed size NLA_U32. Change it to a minimum size. nla_get_labels() does the remaining validation. Fixes: e3e4712ec096 ("mpls: ip tunnel support") Signed-off-by: George Wilkie Reviewed-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/mpls/mpls_iptunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c index 6e558a419f60..6c01166f972b 100644 --- a/net/mpls/mpls_iptunnel.c +++ b/net/mpls/mpls_iptunnel.c @@ -28,7 +28,7 @@ #include "internal.h" static const struct nla_policy mpls_iptunnel_policy[MPLS_IPTUNNEL_MAX + 1] = { - [MPLS_IPTUNNEL_DST] = { .type = NLA_U32 }, + [MPLS_IPTUNNEL_DST] = { .len = sizeof(u32) }, [MPLS_IPTUNNEL_TTL] = { .type = NLA_U8 }, }; -- GitLab From f7edbb6415098817533b9024694b2a6c05c74fc1 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 3 Jun 2019 08:53:31 +0200 Subject: [PATCH 0527/1055] iommu/vt-d: Duplicate iommu_resv_region objects per device list [ Upstream commit 5f64ce5411b467f1cfea6c63e2494c22b773582b ] intel_iommu_get_resv_regions() aims to return the list of reserved regions accessible by a given @device. However several devices can access the same reserved memory region and when building the list it is not safe to use a single iommu_resv_region object, whose container is the RMRR. This iommu_resv_region must be duplicated per device reserved region list. Let's remove the struct iommu_resv_region from the RMRR unit and allocate the iommu_resv_region directly in intel_iommu_get_resv_regions(). We hold the dmar_global_lock instead of the rcu-lock to allow sleeping. Fixes: 0659b8dc45a6 ("iommu/vt-d: Implement reserved region get/put callbacks") Signed-off-by: Eric Auger Reviewed-by: Lu Baolu Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/intel-iommu.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 4fbd183d973a..b48666849dbe 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -442,7 +442,6 @@ struct dmar_rmrr_unit { u64 end_address; /* reserved end address */ struct dmar_dev_scope *devices; /* target devices */ int devices_cnt; /* target device count */ - struct iommu_resv_region *resv; /* reserved region handle */ }; struct dmar_atsr_unit { @@ -4171,7 +4170,6 @@ static inline void init_iommu_pm_ops(void) {} int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg) { struct acpi_dmar_reserved_memory *rmrr; - int prot = DMA_PTE_READ|DMA_PTE_WRITE; struct dmar_rmrr_unit *rmrru; size_t length; @@ -4185,22 +4183,16 @@ int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg) rmrru->end_address = rmrr->end_address; length = rmrr->end_address - rmrr->base_address + 1; - rmrru->resv = iommu_alloc_resv_region(rmrr->base_address, length, prot, - IOMMU_RESV_DIRECT); - if (!rmrru->resv) - goto free_rmrru; rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1), ((void *)rmrr) + rmrr->header.length, &rmrru->devices_cnt); if (rmrru->devices_cnt && rmrru->devices == NULL) - goto free_all; + goto free_rmrru; list_add(&rmrru->list, &dmar_rmrr_units); return 0; -free_all: - kfree(rmrru->resv); free_rmrru: kfree(rmrru); out: @@ -4418,7 +4410,6 @@ static void intel_iommu_free_dmars(void) list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) { list_del(&rmrru->list); dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt); - kfree(rmrru->resv); kfree(rmrru); } @@ -5186,22 +5177,33 @@ static void intel_iommu_remove_device(struct device *dev) static void intel_iommu_get_resv_regions(struct device *device, struct list_head *head) { + int prot = DMA_PTE_READ | DMA_PTE_WRITE; struct iommu_resv_region *reg; struct dmar_rmrr_unit *rmrr; struct device *i_dev; int i; - rcu_read_lock(); + down_read(&dmar_global_lock); for_each_rmrr_units(rmrr) { for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt, i, i_dev) { + struct iommu_resv_region *resv; + size_t length; + if (i_dev != device) continue; - list_add_tail(&rmrr->resv->list, head); + length = rmrr->end_address - rmrr->base_address + 1; + resv = iommu_alloc_resv_region(rmrr->base_address, + length, prot, + IOMMU_RESV_DIRECT); + if (!resv) + break; + + list_add_tail(&resv->list, head); } } - rcu_read_unlock(); + up_read(&dmar_global_lock); reg = iommu_alloc_resv_region(IOAPIC_RANGE_START, IOAPIC_RANGE_END - IOAPIC_RANGE_START + 1, @@ -5216,10 +5218,8 @@ static void intel_iommu_put_resv_regions(struct device *dev, { struct iommu_resv_region *entry, *next; - list_for_each_entry_safe(entry, next, head, list) { - if (entry->type == IOMMU_RESV_MSI) - kfree(entry); - } + list_for_each_entry_safe(entry, next, head, list) + kfree(entry); } #ifdef CONFIG_INTEL_IOMMU_SVM -- GitLab From e0f944d4cb3a9e4e8ebebf5379ede31cc3a3fbe2 Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Thu, 13 Jun 2019 11:29:40 +0300 Subject: [PATCH 0528/1055] qed: iWARP - Use READ_ONCE and smp_store_release to access ep->state [ Upstream commit 6117561e1bb30b2fe7f51e1961f34dbedd0bec8a ] Destroy QP waits for it's ep object state to be set to CLOSED before proceeding. ep->state can be updated from a different context. Add smp_store_release/READ_ONCE to synchronize. Fixes: fc4c6065e661 ("qed: iWARP implement disconnect flows") Signed-off-by: Ariel Elior Signed-off-by: Michal Kalderon Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c index bb09f5a9846f..38d0f62bf037 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c @@ -509,7 +509,8 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp) /* Make sure ep is closed before returning and freeing memory. */ if (ep) { - while (ep->state != QED_IWARP_EP_CLOSED && wait_count++ < 200) + while (READ_ONCE(ep->state) != QED_IWARP_EP_CLOSED && + wait_count++ < 200) msleep(100); if (ep->state != QED_IWARP_EP_CLOSED) @@ -991,8 +992,6 @@ qed_iwarp_mpa_complete(struct qed_hwfn *p_hwfn, params.ep_context = ep; - ep->state = QED_IWARP_EP_CLOSED; - switch (fw_return_code) { case RDMA_RETURN_OK: ep->qp->max_rd_atomic_req = ep->cm_info.ord; @@ -1052,6 +1051,10 @@ qed_iwarp_mpa_complete(struct qed_hwfn *p_hwfn, break; } + if (fw_return_code != RDMA_RETURN_OK) + /* paired with READ_ONCE in destroy_qp */ + smp_store_release(&ep->state, QED_IWARP_EP_CLOSED); + ep->event_cb(ep->cb_context, ¶ms); /* on passive side, if there is no associated QP (REJECT) we need to @@ -2069,7 +2072,9 @@ void qed_iwarp_qp_in_error(struct qed_hwfn *p_hwfn, params.status = (fw_return_code == IWARP_QP_IN_ERROR_GOOD_CLOSE) ? 0 : -ECONNRESET; - ep->state = QED_IWARP_EP_CLOSED; + /* paired with READ_ONCE in destroy_qp */ + smp_store_release(&ep->state, QED_IWARP_EP_CLOSED); + spin_lock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); list_del(&ep->list_entry); spin_unlock_bh(&p_hwfn->p_rdma_info->iwarp.iw_lock); @@ -2157,7 +2162,8 @@ qed_iwarp_tcp_connect_unsuccessful(struct qed_hwfn *p_hwfn, params.event = QED_IWARP_EVENT_ACTIVE_COMPLETE; params.ep_context = ep; params.cm_info = &ep->cm_info; - ep->state = QED_IWARP_EP_CLOSED; + /* paired with READ_ONCE in destroy_qp */ + smp_store_release(&ep->state, QED_IWARP_EP_CLOSED); switch (fw_return_code) { case IWARP_CONN_ERROR_TCP_CONNECT_INVALID_PACKET: -- GitLab From 55221779bb3255b1d8e9fd20ed5d5998d65cd6f4 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Tue, 11 Jun 2019 23:45:04 -0500 Subject: [PATCH 0529/1055] powerpc/cacheinfo: add cacheinfo_teardown, cacheinfo_rebuild [ Upstream commit d4aa219a074a5abaf95a756b9f0d190b5c03a945 ] Allow external callers to force the cacheinfo code to release all its references to cache nodes, e.g. before processing device tree updates post-migration, and to rebuild the hierarchy afterward. CPU online/offline must be blocked by callers; enforce this. Fixes: 410bccf97881 ("powerpc/pseries: Partition migration in the kernel") Signed-off-by: Nathan Lynch Reviewed-by: Gautham R. Shenoy Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin --- arch/powerpc/kernel/cacheinfo.c | 21 +++++++++++++++++++++ arch/powerpc/kernel/cacheinfo.h | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c index a8f20e5928e1..9edb45430133 100644 --- a/arch/powerpc/kernel/cacheinfo.c +++ b/arch/powerpc/kernel/cacheinfo.c @@ -865,4 +865,25 @@ void cacheinfo_cpu_offline(unsigned int cpu_id) if (cache) cache_cpu_clear(cache, cpu_id); } + +void cacheinfo_teardown(void) +{ + unsigned int cpu; + + lockdep_assert_cpus_held(); + + for_each_online_cpu(cpu) + cacheinfo_cpu_offline(cpu); +} + +void cacheinfo_rebuild(void) +{ + unsigned int cpu; + + lockdep_assert_cpus_held(); + + for_each_online_cpu(cpu) + cacheinfo_cpu_online(cpu); +} + #endif /* (CONFIG_PPC_PSERIES && CONFIG_SUSPEND) || CONFIG_HOTPLUG_CPU */ diff --git a/arch/powerpc/kernel/cacheinfo.h b/arch/powerpc/kernel/cacheinfo.h index 955f5e999f1b..52bd3fc6642d 100644 --- a/arch/powerpc/kernel/cacheinfo.h +++ b/arch/powerpc/kernel/cacheinfo.h @@ -6,4 +6,8 @@ extern void cacheinfo_cpu_online(unsigned int cpu_id); extern void cacheinfo_cpu_offline(unsigned int cpu_id); +/* Allow migration/suspend to tear down and rebuild the hierarchy. */ +extern void cacheinfo_teardown(void); +extern void cacheinfo_rebuild(void); + #endif /* _PPC_CACHEINFO_H */ -- GitLab From 6a275c6ff76d87d9dd4d59c35413aaa4a6a5c0d4 Mon Sep 17 00:00:00 2001 From: Nathan Lynch Date: Tue, 11 Jun 2019 23:45:06 -0500 Subject: [PATCH 0530/1055] powerpc/pseries/mobility: rebuild cacheinfo hierarchy post-migration [ Upstream commit e610a466d16a086e321f0bd421e2fc75cff28605 ] It's common for the platform to replace the cache device nodes after a migration. Since the cacheinfo code is never informed about this, it never drops its references to the source system's cache nodes, causing it to wind up in an inconsistent state resulting in warnings and oopses as soon as CPU online/offline occurs after the migration, e.g. cache for /cpus/l3-cache@3113(Unified) refers to cache for /cpus/l2-cache@200d(Unified) WARNING: CPU: 15 PID: 86 at arch/powerpc/kernel/cacheinfo.c:176 release_cache+0x1bc/0x1d0 [...] NIP release_cache+0x1bc/0x1d0 LR release_cache+0x1b8/0x1d0 Call Trace: release_cache+0x1b8/0x1d0 (unreliable) cacheinfo_cpu_offline+0x1c4/0x2c0 unregister_cpu_online+0x1b8/0x260 cpuhp_invoke_callback+0x114/0xf40 cpuhp_thread_fun+0x270/0x310 smpboot_thread_fn+0x2c8/0x390 kthread+0x1b8/0x1c0 ret_from_kernel_thread+0x5c/0x68 Using device tree notifiers won't work since we want to rebuild the hierarchy only after all the removals and additions have occurred and the device tree is in a consistent state. Call cacheinfo_teardown() before processing device tree updates, and rebuild the hierarchy afterward. Fixes: 410bccf97881 ("powerpc/pseries: Partition migration in the kernel") Signed-off-by: Nathan Lynch Reviewed-by: Gautham R. Shenoy Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin --- arch/powerpc/platforms/pseries/mobility.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index 9739a055e5f7..2d3668acb6ef 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -23,6 +23,7 @@ #include #include #include "pseries.h" +#include "../../kernel/cacheinfo.h" static struct kobject *mobility_kobj; @@ -359,11 +360,20 @@ void post_mobility_fixup(void) */ cpus_read_lock(); + /* + * It's common for the destination firmware to replace cache + * nodes. Release all of the cacheinfo hierarchy's references + * before updating the device tree. + */ + cacheinfo_teardown(); + rc = pseries_devicetree_update(MIGRATION_SCOPE); if (rc) printk(KERN_ERR "Post-mobility device tree update " "failed: %d\n", rc); + cacheinfo_rebuild(); + cpus_read_unlock(); /* Possibly switch to a new RFI flush type */ -- GitLab From 68925f1521a2f57f7785a9377fe6baeb6ef0f986 Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Tue, 21 May 2019 08:00:30 -0700 Subject: [PATCH 0531/1055] drm/msm/mdp5: Fix mdp5_cfg_init error return [ Upstream commit fc19cbb785d7bbd1a1af26229b5240a3ab332744 ] If mdp5_cfg_init fails because of an unknown major version, a null pointer dereference occurs. This is because the caller of init expects error pointers, but init returns NULL on error. Fix this by returning the expected values on error. Fixes: 2e362e1772b8 (drm/msm/mdp5: introduce mdp5_cfg module) Signed-off-by: Jeffrey Hugo Reviewed-by: Bjorn Andersson Signed-off-by: Rob Clark Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c index 824067d2d427..42f0ecb0cf35 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cfg.c @@ -635,7 +635,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, if (cfg_handler) mdp5_cfg_destroy(cfg_handler); - return NULL; + return ERR_PTR(ret); } static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev) -- GitLab From 9085504b3b57fca32dc54ce56c8499512c60ddeb Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 17 Jun 2019 11:11:10 -0700 Subject: [PATCH 0532/1055] net: netem: fix backlog accounting for corrupted GSO frames [ Upstream commit 177b8007463c4f36c9a2c7ce7aa9875a4cad9bd5 ] When GSO frame has to be corrupted netem uses skb_gso_segment() to produce the list of frames, and re-enqueues the segments one by one. The backlog length has to be adjusted to account for new frames. The current calculation is incorrect, leading to wrong backlog lengths in the parent qdisc (both bytes and packets), and incorrect packet backlog count in netem itself. Parent backlog goes negative, netem's packet backlog counts all non-first segments twice (thus remaining non-zero even after qdisc is emptied). Move the variables used to count the adjustment into local scope to make 100% sure they aren't used at any stage in backports. Fixes: 6071bd1aa13e ("netem: Segment GSO packets on enqueue") Signed-off-by: Jakub Kicinski Reviewed-by: Dirk van der Merwe Acked-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/sched/sch_netem.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 6266121a03f9..ede0a24e67eb 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -431,8 +431,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct netem_skb_cb *cb; struct sk_buff *skb2; struct sk_buff *segs = NULL; - unsigned int len = 0, last_len, prev_len = qdisc_pkt_len(skb); - int nb = 0; + unsigned int prev_len = qdisc_pkt_len(skb); int count = 1; int rc = NET_XMIT_SUCCESS; int rc_drop = NET_XMIT_DROP; @@ -489,6 +488,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, segs = netem_segment(skb, sch, to_free); if (!segs) return rc_drop; + qdisc_skb_cb(segs)->pkt_len = segs->len; } else { segs = skb; } @@ -579,6 +579,11 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, finish_segs: if (segs) { + unsigned int len, last_len; + int nb = 0; + + len = skb->len; + while (segs) { skb2 = segs->next; segs->next = NULL; @@ -594,9 +599,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, } segs = skb2; } - sch->q.qlen += nb; - if (nb > 1) - qdisc_tree_reduce_backlog(sch, 1 - nb, prev_len - len); + qdisc_tree_reduce_backlog(sch, -nb, prev_len - len); } return NET_XMIT_SUCCESS; } -- GitLab From b6668f5207180535ae8ca2e33a80464c9e291c5b Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 18 Jun 2019 20:43:01 +0200 Subject: [PATCH 0533/1055] net/af_iucv: always register net_device notifier [ Upstream commit 06996c1d4088a0d5f3e7789d7f96b4653cc947cc ] Even when running as VM guest (ie pr_iucv != NULL), af_iucv can still open HiperTransport-based connections. For robust operation these connections require the af_iucv_netdev_notifier, so register it unconditionally. Also handle any error that register_netdevice_notifier() returns. Fixes: 9fbd87d41392 ("af_iucv: handle netdev events") Signed-off-by: Julian Wiedmann Reviewed-by: Ursula Braun Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/iucv/af_iucv.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index ca98276c2709..7a9cbc9502d9 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -2446,6 +2446,13 @@ static int afiucv_iucv_init(void) return err; } +static void afiucv_iucv_exit(void) +{ + device_unregister(af_iucv_dev); + driver_unregister(&af_iucv_driver); + pr_iucv->iucv_unregister(&af_iucv_handler, 0); +} + static int __init afiucv_init(void) { int err; @@ -2479,11 +2486,18 @@ static int __init afiucv_init(void) err = afiucv_iucv_init(); if (err) goto out_sock; - } else - register_netdevice_notifier(&afiucv_netdev_notifier); + } + + err = register_netdevice_notifier(&afiucv_netdev_notifier); + if (err) + goto out_notifier; + dev_add_pack(&iucv_packet_type); return 0; +out_notifier: + if (pr_iucv) + afiucv_iucv_exit(); out_sock: sock_unregister(PF_IUCV); out_proto: @@ -2497,12 +2511,11 @@ static int __init afiucv_init(void) static void __exit afiucv_exit(void) { if (pr_iucv) { - device_unregister(af_iucv_dev); - driver_unregister(&af_iucv_driver); - pr_iucv->iucv_unregister(&af_iucv_handler, 0); + afiucv_iucv_exit(); symbol_put(iucv_if); - } else - unregister_netdevice_notifier(&afiucv_netdev_notifier); + } + + unregister_netdevice_notifier(&afiucv_netdev_notifier); dev_remove_pack(&iucv_packet_type); sock_unregister(PF_IUCV); proto_unregister(&iucv_proto); -- GitLab From d999896bec7cd5cedb3d9afc4ea1ff6db041be5b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 20 Jun 2019 12:20:02 +0300 Subject: [PATCH 0534/1055] ASoC: ti: davinci-mcasp: Fix slot mask settings when using multiple AXRs [ Upstream commit fd14f4436fd47d5418023c90e933e66d3645552e ] If multiple serializers are connected in the system and the number of channels will need to use more than one serializer the mask to enable the serializers were left to 0 if tdm_mask is provided Fixes: dd55ff8346a97 ("ASoC: davinci-mcasp: Add set_tdm_slots() support") Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/davinci/davinci-mcasp.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 07bac9ea65c4..e10e03800cce 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -882,14 +882,13 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream, active_slots = hweight32(mcasp->tdm_mask[stream]); active_serializers = (channels + active_slots - 1) / active_slots; - if (active_serializers == 1) { + if (active_serializers == 1) active_slots = channels; - for (i = 0; i < total_slots; i++) { - if ((1 << i) & mcasp->tdm_mask[stream]) { - mask |= (1 << i); - if (--active_slots <= 0) - break; - } + for (i = 0; i < total_slots; i++) { + if ((1 << i) & mcasp->tdm_mask[stream]) { + mask |= (1 << i); + if (--active_slots <= 0) + break; } } } else { -- GitLab From 59010f8ca3b284b9da05f5c2721a95b5275ce639 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 4 Jun 2019 12:23:35 +0800 Subject: [PATCH 0535/1055] rtc: pcf8563: Fix interrupt trigger method [ Upstream commit 65f662cbf829834fa4d94190eb7691e5a9cb92d8 ] The PCF8563 datasheet says the interrupt line is active low and stays active until the events are cleared, i.e. a level trigger interrupt. Fix the flags used to request the interrupt. Fixes: ede3e9d47cca ("drivers/rtc/rtc-pcf8563.c: add alarm support") Signed-off-by: Chen-Yu Tsai Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/rtc-pcf8563.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 8c836c51a508..ef04472dde1d 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -605,7 +605,7 @@ static int pcf8563_probe(struct i2c_client *client, if (client->irq > 0) { err = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf8563_irq, - IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING, + IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW, pcf8563_driver.driver.name, client); if (err) { dev_err(&client->dev, "unable to request IRQ %d\n", -- GitLab From 9a473d3bd98c7c1f717f5bdaab64b74e5b1e8b1b Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 4 Jun 2019 12:23:36 +0800 Subject: [PATCH 0536/1055] rtc: pcf8563: Clear event flags and disable interrupts before requesting irq [ Upstream commit 3572e8aea3bf925dac1dbf86127657c39fe5c254 ] Besides the alarm, the PCF8563 also has a timer triggered interrupt. In cases where the previous system left the timer and interrupts on, or somehow the bits got enabled, the interrupt would keep triggering as the kernel doesn't know about it. Clear both the alarm and timer event flags, and disable the interrupts, before requesting the interrupt line. Fixes: ede3e9d47cca ("drivers/rtc/rtc-pcf8563.c: add alarm support") Fixes: a45d528aab8b ("rtc: pcf8563: clear expired alarm at boot time") Signed-off-by: Chen-Yu Tsai Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/rtc-pcf8563.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index ef04472dde1d..4d0b81f9805f 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -563,7 +563,6 @@ static int pcf8563_probe(struct i2c_client *client, struct pcf8563 *pcf8563; int err; unsigned char buf; - unsigned char alm_pending; dev_dbg(&client->dev, "%s\n", __func__); @@ -587,13 +586,13 @@ static int pcf8563_probe(struct i2c_client *client, return err; } - err = pcf8563_get_alarm_mode(client, NULL, &alm_pending); - if (err) { - dev_err(&client->dev, "%s: read error\n", __func__); + /* Clear flags and disable interrupts */ + buf = 0; + err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf); + if (err < 0) { + dev_err(&client->dev, "%s: write error\n", __func__); return err; } - if (alm_pending) - pcf8563_set_alarm_mode(client, 0); pcf8563->rtc = devm_rtc_device_register(&client->dev, pcf8563_driver.driver.name, -- GitLab From bc99903915ab5d06368c97058e017ae4580b13e5 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 24 Jun 2019 09:09:47 -0700 Subject: [PATCH 0537/1055] drm/msm/a3xx: remove TPL1 regs from snapshot [ Upstream commit f47bee2ba447bebc304111c16ef1e1a73a9744dd ] These regs are write-only, and the hw throws a hissy-fit (ie. reboots) when we try to read them for GPU state snapshot, in response to a GPU hang. It is rather impolite when GPU recovery triggers an insta- reboot, so lets remove the TPL1 registers from the snapshot. Fixes: 7198e6b03155 drm/msm: add a3xx gpu support Signed-off-by: Rob Clark Reviewed-by: Jordan Crouse Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 7791313405b5..c8671b1578c6 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -394,19 +394,17 @@ static const unsigned int a3xx_registers[] = { 0x2200, 0x2212, 0x2214, 0x2217, 0x221a, 0x221a, 0x2240, 0x227e, 0x2280, 0x228b, 0x22c0, 0x22c0, 0x22c4, 0x22ce, 0x22d0, 0x22d8, 0x22df, 0x22e6, 0x22e8, 0x22e9, 0x22ec, 0x22ec, 0x22f0, 0x22f7, - 0x22ff, 0x22ff, 0x2340, 0x2343, 0x2348, 0x2349, 0x2350, 0x2356, - 0x2360, 0x2360, 0x2440, 0x2440, 0x2444, 0x2444, 0x2448, 0x244d, - 0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, 0x2472, 0x2472, - 0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, 0x24e4, 0x24ef, - 0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, 0x2510, 0x2511, - 0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, 0x25ec, 0x25ed, - 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, 0x261a, 0x261a, - 0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, 0x26c4, 0x26ce, - 0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, 0x26ec, 0x26ec, - 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, 0x2748, 0x2749, - 0x2750, 0x2756, 0x2760, 0x2760, 0x300c, 0x300e, 0x301c, 0x301d, - 0x302a, 0x302a, 0x302c, 0x302d, 0x3030, 0x3031, 0x3034, 0x3036, - 0x303c, 0x303c, 0x305e, 0x305f, + 0x22ff, 0x22ff, 0x2340, 0x2343, 0x2440, 0x2440, 0x2444, 0x2444, + 0x2448, 0x244d, 0x2468, 0x2469, 0x246c, 0x246d, 0x2470, 0x2470, + 0x2472, 0x2472, 0x2474, 0x2475, 0x2479, 0x247a, 0x24c0, 0x24d3, + 0x24e4, 0x24ef, 0x2500, 0x2509, 0x250c, 0x250c, 0x250e, 0x250e, + 0x2510, 0x2511, 0x2514, 0x2515, 0x25e4, 0x25e4, 0x25ea, 0x25ea, + 0x25ec, 0x25ed, 0x25f0, 0x25f0, 0x2600, 0x2612, 0x2614, 0x2617, + 0x261a, 0x261a, 0x2640, 0x267e, 0x2680, 0x268b, 0x26c0, 0x26c0, + 0x26c4, 0x26ce, 0x26d0, 0x26d8, 0x26df, 0x26e6, 0x26e8, 0x26e9, + 0x26ec, 0x26ec, 0x26f0, 0x26f7, 0x26ff, 0x26ff, 0x2740, 0x2743, + 0x300c, 0x300e, 0x301c, 0x301d, 0x302a, 0x302a, 0x302c, 0x302d, + 0x3030, 0x3031, 0x3034, 0x3036, 0x303c, 0x303c, 0x305e, 0x305f, ~0 /* sentinel */ }; -- GitLab From 232ac0764ac76ff4f8eef9a8c24a661dbd0a6382 Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Tue, 4 Jun 2019 09:59:53 +0530 Subject: [PATCH 0538/1055] perf/ioctl: Add check for the sample_period value [ Upstream commit 913a90bc5a3a06b1f04c337320e9aeee2328dd77 ] perf_event_open() limits the sample_period to 63 bits. See: 0819b2e30ccb ("perf: Limit perf_event_attr::sample_period to 63 bits") Make ioctl() consistent with it. Also on PowerPC, negative sample_period could cause a recursive PMIs leading to a hang (reported when running perf-fuzzer). Signed-off-by: Ravi Bangoria Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: acme@kernel.org Cc: linuxppc-dev@lists.ozlabs.org Cc: maddy@linux.vnet.ibm.com Cc: mpe@ellerman.id.au Fixes: 0819b2e30ccb ("perf: Limit perf_event_attr::sample_period to 63 bits") Link: https://lkml.kernel.org/r/20190604042953.914-1-ravi.bangoria@linux.ibm.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin --- kernel/events/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/events/core.c b/kernel/events/core.c index ea4f3f7a0c6f..2ac73b4cb8a9 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4762,6 +4762,9 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg) if (perf_event_check_period(event, value)) return -EINVAL; + if (!event->attr.freq && (value & (1ULL << 63))) + return -EINVAL; + event_function_call(event, __perf_event_period, &value); return 0; -- GitLab From f08cd3c7db421905dd1c15b2b2f9a4d0a3c5ab8f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 13 Jun 2019 16:32:32 +0300 Subject: [PATCH 0539/1055] dmaengine: hsu: Revert "set HSU_CH_MTSR to memory width" [ Upstream commit c24a5c735f87d0549060de31367c095e8810b895 ] The commit 080edf75d337 ("dmaengine: hsu: set HSU_CH_MTSR to memory width") has been mistakenly submitted. The further investigations show that the original code does better job since the memory side transfer size has never been configured by DMA users. As per latest revision of documentation: "Channel minimum transfer size (CHnMTSR)... For IOSF UART, maximum value that can be programmed is 64 and minimum value that can be programmed is 1." This reverts commit 080edf75d337d35faa6fc3df99342b10d2848d16. Fixes: 080edf75d337 ("dmaengine: hsu: set HSU_CH_MTSR to memory width") Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/hsu/hsu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index 29d04ca71d52..15525a2b8ebd 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c @@ -64,10 +64,10 @@ static void hsu_dma_chan_start(struct hsu_dma_chan *hsuc) if (hsuc->direction == DMA_MEM_TO_DEV) { bsr = config->dst_maxburst; - mtsr = config->src_addr_width; + mtsr = config->dst_addr_width; } else if (hsuc->direction == DMA_DEV_TO_MEM) { bsr = config->src_maxburst; - mtsr = config->dst_addr_width; + mtsr = config->src_addr_width; } hsu_chan_disable(hsuc); -- GitLab From de2970e92948b7de60ba41f36b05aa1740e77b6a Mon Sep 17 00:00:00 2001 From: Nathan Huckleberry Date: Tue, 11 Jun 2019 14:11:34 -0700 Subject: [PATCH 0540/1055] clk: qcom: Fix -Wunused-const-variable [ Upstream commit da642427bd7710ec4f4140f693f59aa8521a358c ] Clang produces the following warning drivers/clk/qcom/gcc-msm8996.c:133:32: warning: unused variable 'gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div_map' [-Wunused-const-variable] static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div_map[] = { ^drivers/clk/qcom/gcc-msm8996.c:141:27: warning: unused variable 'gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div' [-Wunused-const-variable] static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div[] = { ^ drivers/clk/qcom/gcc-msm8996.c:187:32: warning: unused variable 'gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div_map' [-Wunused-const-variable] static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div_map[] = { ^ drivers/clk/qcom/gcc-msm8996.c:197:27: warning: unused variable 'gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div' [-Wunused-const-variable] static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div[] = { It looks like these were never used. Fixes: b1e010c0730a ("clk: qcom: Add MSM8996 Global Clock Control (GCC) driver") Cc: clang-built-linux@googlegroups.com Link: https://github.com/ClangBuiltLinux/linux/issues/518 Suggested-by: Nathan Chancellor Signed-off-by: Nathan Huckleberry Reviewed-by: Nathan Chancellor Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin --- drivers/clk/qcom/gcc-msm8996.c | 36 ---------------------------------- 1 file changed, 36 deletions(-) diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 7ddec886fcd3..c0b043b1bd24 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c @@ -140,22 +140,6 @@ static const char * const gcc_xo_gpll0_gpll4_gpll0_early_div[] = { "gpll0_early_div" }; -static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div_map[] = { - { P_XO, 0 }, - { P_GPLL0, 1 }, - { P_GPLL2, 2 }, - { P_GPLL3, 3 }, - { P_GPLL0_EARLY_DIV, 6 } -}; - -static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll0_early_div[] = { - "xo", - "gpll0", - "gpll2", - "gpll3", - "gpll0_early_div" -}; - static const struct parent_map gcc_xo_gpll0_gpll1_early_div_gpll1_gpll4_gpll0_early_div_map[] = { { P_XO, 0 }, { P_GPLL0, 1 }, @@ -194,26 +178,6 @@ static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll2_early_gpll0_early "gpll0_early_div" }; -static const struct parent_map gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div_map[] = { - { P_XO, 0 }, - { P_GPLL0, 1 }, - { P_GPLL2, 2 }, - { P_GPLL3, 3 }, - { P_GPLL1, 4 }, - { P_GPLL4, 5 }, - { P_GPLL0_EARLY_DIV, 6 } -}; - -static const char * const gcc_xo_gpll0_gpll2_gpll3_gpll1_gpll4_gpll0_early_div[] = { - "xo", - "gpll0", - "gpll2", - "gpll3", - "gpll1", - "gpll4", - "gpll0_early_div" -}; - static struct clk_fixed_factor xo = { .mult = 1, .div = 1, -- GitLab From 383019e9d2dcb8e8e0cc67f5f0c8552ff8ad67b1 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Wed, 26 Jun 2019 11:27:29 +0100 Subject: [PATCH 0541/1055] nvmem: imx-ocotp: Ensure WAIT bits are preserved when setting timing [ Upstream commit 0493c4792b4eb260441e57f52cc11a9ded48b5a7 ] The i.MX6 and i.MX8 both have a bit-field spanning bits 27:22 called the WAIT field. The WAIT field according to the documentation for both parts "specifies time interval between auto read and write access in one time program. It is given in number of ipg_clk periods." This patch ensures that the relevant field is read and written back to the timing register. Fixes: 0642bac7da42 ("nvmem: imx-ocotp: add write support") Signed-off-by: Bryan O'Donoghue Reviewed-by: Leonard Crestez Signed-off-by: Srinivas Kandagatla Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/nvmem/imx-ocotp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c index 193ca8fd350a..0c8c3b9bb6a7 100644 --- a/drivers/nvmem/imx-ocotp.c +++ b/drivers/nvmem/imx-ocotp.c @@ -199,7 +199,8 @@ static int imx_ocotp_write(void *context, unsigned int offset, void *val, strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1; strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1; - timing = strobe_prog & 0x00000FFF; + timing = readl(priv->base + IMX_OCOTP_ADDR_TIMING) & 0x0FC00000; + timing |= strobe_prog & 0x00000FFF; timing |= (relax << 12) & 0x0000F000; timing |= (strobe_read << 16) & 0x003F0000; -- GitLab From 46942fb18681b3d70441353af7bb39d856ab931f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 29 Jun 2019 11:16:45 -0400 Subject: [PATCH 0542/1055] bnxt_en: Fix ethtool selftest crash under error conditions. [ Upstream commit d27e2ca1166aefd54d9c48fb6647dee8115a5dfc ] After ethtool loopback packet tests, we re-open the nic for the next IRQ test. If the open fails, we must not proceed with the IRQ test or we will crash with NULL pointer dereference. Fix it by checking the bnxt_open_nic() return code before proceeding. Reported-by: Somasundaram Krishnasamy Fixes: 67fea463fd87 ("bnxt_en: Add interrupt test to ethtool -t selftest.") Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index fc8e185718a1..963beaa8fabb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2463,7 +2463,7 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, bool offline = false; u8 test_results = 0; u8 test_mask = 0; - int rc, i; + int rc = 0, i; if (!bp->num_tests || !BNXT_SINGLE_PF(bp)) return; @@ -2521,9 +2521,9 @@ static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest, } bnxt_hwrm_phy_loopback(bp, false); bnxt_half_close_nic(bp); - bnxt_open_nic(bp, false, true); + rc = bnxt_open_nic(bp, false, true); } - if (bnxt_test_irq(bp)) { + if (rc || bnxt_test_irq(bp)) { buf[BNXT_IRQ_TEST_IDX] = 1; etest->flags |= ETH_TEST_FL_FAILED; } -- GitLab From be4a793b10fd11c2a519d6222799b53d8af2c05d Mon Sep 17 00:00:00 2001 From: Kevin Mitchell Date: Wed, 12 Jun 2019 14:52:03 -0700 Subject: [PATCH 0543/1055] iommu/amd: Make iommu_disable safer [ Upstream commit 3ddbe913e55516d3e2165d43d4d5570761769878 ] Make it safe to call iommu_disable during early init error conditions before mmio_base is set, but after the struct amd_iommu has been added to the amd_iommu_list. For example, this happens if firmware fails to fill in mmio_phys in the ACPI table leading to a NULL pointer dereference in iommu_feature_disable. Fixes: 2c0ae1720c09c ('iommu/amd: Convert iommu initialization to state machine') Signed-off-by: Kevin Mitchell Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/amd_iommu_init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 6a3cf4d0bd5e..4d2920988d60 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -420,6 +420,9 @@ static void iommu_enable(struct amd_iommu *iommu) static void iommu_disable(struct amd_iommu *iommu) { + if (!iommu->mmio_base) + return; + /* Disable command buffer */ iommu_feature_disable(iommu, CONTROL_CMDBUF_EN); -- GitLab From 92cbf173ea692cd2111d3cedebe408a68a96d0f6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 21 Jun 2019 15:56:31 +0300 Subject: [PATCH 0544/1055] mfd: intel-lpss: Release IDA resources [ Upstream commit 02f36911c1b41fcd8779fa0c135aab0554333fa5 ] ida instances allocate some internal memory for ->free_bitmap in addition to the base 'struct ida'. Use ida_destroy() to release that memory at module_exit(). Fixes: 4b45efe85263 ("mfd: Add support for Intel Sunrisepoint LPSS devices") Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones Signed-off-by: Sasha Levin --- drivers/mfd/intel-lpss.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index b5c4f8f974aa..9ed573e232c0 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -541,6 +541,7 @@ module_init(intel_lpss_init); static void __exit intel_lpss_exit(void) { + ida_destroy(&intel_lpss_devid_ida); debugfs_remove(intel_lpss_debugfs); } module_exit(intel_lpss_exit); -- GitLab From 37624e6350ed8f773e814311e482fbe6c4d77ca2 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 2 Jul 2019 15:55:28 +0100 Subject: [PATCH 0545/1055] rxrpc: Fix uninitialized error code in rxrpc_send_data_packet() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 3427beb6375d04e9627c67343872e79341a684ea ] With gcc 4.1: net/rxrpc/output.c: In function ‘rxrpc_send_data_packet’: net/rxrpc/output.c:338: warning: ‘ret’ may be used uninitialized in this function Indeed, if the first jump to the send_fragmentable label is made, and the address family is not handled in the switch() statement, ret will be used uninitialized. Fix this by BUG()'ing as is done in other places in rxrpc where internal support for future address families will need adding. It should not be possible to reach this normally as the address families are checked up-front. Fixes: 5a924b8951f835b5 ("rxrpc: Don't store the rxrpc header in the Tx queue sk_buffs") Reported-by: Geert Uytterhoeven Signed-off-by: David Howells Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/rxrpc/output.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 5b67cb5d47f0..edddbacf33bc 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -404,6 +404,9 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb, } break; #endif + + default: + BUG(); } up_write(&conn->params.local->defrag_sem); -- GitLab From 97464364e3e1642315a9f194258b50e6781be139 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 28 Jun 2019 16:59:45 +0200 Subject: [PATCH 0546/1055] devres: allow const resource arguments [ Upstream commit 9dea44c91469512d346e638694c22c30a5273992 ] devm_ioremap_resource() does not currently take 'const' arguments, which results in a warning from the first driver trying to do it anyway: drivers/gpio/gpio-amd-fch.c: In function 'amd_fch_gpio_probe': drivers/gpio/gpio-amd-fch.c:171:49: error: passing argument 2 of 'devm_ioremap_resource' discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] priv->base = devm_ioremap_resource(&pdev->dev, &amd_fch_gpio_iores); ^~~~~~~~~~~~~~~~~~~ Change the prototype to allow it, as there is no real reason not to. Fixes: 9bb2e0452508 ("gpio: amd: Make resource struct const") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20190628150049.1108048-1-arnd@arndb.de Acked-by: Greg Kroah-Hartman Reviwed-By: Enrico Weigelt Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin --- include/linux/device.h | 3 ++- lib/devres.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/device.h b/include/linux/device.h index 66fe271c2544..0b2e67014a83 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -682,7 +682,8 @@ extern unsigned long devm_get_free_pages(struct device *dev, gfp_t gfp_mask, unsigned int order); extern void devm_free_pages(struct device *dev, unsigned long addr); -void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res); +void __iomem *devm_ioremap_resource(struct device *dev, + const struct resource *res); /* allows to add/remove a custom action to devres stack */ int devm_add_action(struct device *dev, void (*action)(void *), void *data); diff --git a/lib/devres.c b/lib/devres.c index 5f2aedd58bc5..40a8b12a8b6b 100644 --- a/lib/devres.c +++ b/lib/devres.c @@ -132,7 +132,8 @@ EXPORT_SYMBOL(devm_iounmap); * if (IS_ERR(base)) * return PTR_ERR(base); */ -void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res) +void __iomem *devm_ioremap_resource(struct device *dev, + const struct resource *res) { resource_size_t size; const char *name; -- GitLab From 192a3c131e58c13987dfdb8e5c4a5d2d03114dd4 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Mon, 24 Jun 2019 19:47:51 +0800 Subject: [PATCH 0547/1055] RDMA/hns: Fixs hw access invalid dma memory error [ Upstream commit ec5bc2cc69b4fc494e04d10fc5226f6f9cf67c56 ] When smmu is enable, if execute the perftest command and then use 'kill -9' to exit, follow this operation repeatedly, the kernel will have a high probability to print the following smmu event: arm-smmu-v3 arm-smmu-v3.1.auto: event 0x10 received: arm-smmu-v3 arm-smmu-v3.1.auto: 0x00007d0000000010 arm-smmu-v3 arm-smmu-v3.1.auto: 0x0000020900000080 arm-smmu-v3 arm-smmu-v3.1.auto: 0x00000000f47cf000 arm-smmu-v3 arm-smmu-v3.1.auto: 0x00000000f47cf000 This is because the hw will periodically refresh the qpc cache until the next reset. This patch fixed it by removing the action that release qpc memory in the 'hns_roce_qp_free' function. Fixes: 9a4435375cd1 ("IB/hns: Add driver files for hns RoCE driver") Signed-off-by: Xi Wang Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/hw/hns/hns_roce_qp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 3a37d26889df..281e9987ffc8 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -241,7 +241,6 @@ void hns_roce_qp_free(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp) if ((hr_qp->ibqp.qp_type) != IB_QPT_GSI) { hns_roce_table_put(hr_dev, &qp_table->irrl_table, hr_qp->qpn); - hns_roce_table_put(hr_dev, &qp_table->qp_table, hr_qp->qpn); } } -- GitLab From 4b8e04d87ab02f5769b0912780cf0c198c4257e9 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Sat, 6 Jul 2019 12:23:41 +0800 Subject: [PATCH 0548/1055] net: pasemi: fix an use-after-free in pasemi_mac_phy_init() [ Upstream commit faf5577f2498cea23011b5c785ef853ded22700b ] The phy_dn variable is still being used in of_phy_connect() after the of_node_put() call, which may result in use-after-free. Fixes: 1dd2d06c0459 ("net: Rework pasemi_mac driver to use of_mdio infrastructure") Signed-off-by: Wen Yang Cc: "David S. Miller" Cc: Thomas Gleixner Cc: Luis Chamberlain Cc: Michael Ellerman Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/pasemi/pasemi_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/pasemi/pasemi_mac.c b/drivers/net/ethernet/pasemi/pasemi_mac.c index 49591d9c2e1b..c9b4ac9d3330 100644 --- a/drivers/net/ethernet/pasemi/pasemi_mac.c +++ b/drivers/net/ethernet/pasemi/pasemi_mac.c @@ -1053,7 +1053,6 @@ static int pasemi_mac_phy_init(struct net_device *dev) dn = pci_device_to_OF_node(mac->pdev); phy_dn = of_parse_phandle(dn, "phy-handle", 0); - of_node_put(phy_dn); mac->link = 0; mac->speed = 0; @@ -1062,6 +1061,7 @@ static int pasemi_mac_phy_init(struct net_device *dev) phydev = of_phy_connect(dev, phy_dn, &pasemi_adjust_link, 0, PHY_INTERFACE_MODE_SGMII); + of_node_put(phy_dn); if (!phydev) { printk(KERN_ERR "%s: Could not attach to phy\n", dev->name); return -ENODEV; -- GitLab From 4077713e39ed3b1672fa833375453800c431b6c2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 2 Jul 2019 10:18:35 +0100 Subject: [PATCH 0549/1055] scsi: libfc: fix null pointer dereference on a null lport [ Upstream commit 41a6bf6529edd10a6def42e3b2c34a7474bcc2f5 ] Currently if lport is null then the null lport pointer is dereference when printing out debug via the FC_LPORT_DB macro. Fix this by using the more generic FC_LIBFC_DBG debug macro instead that does not use lport. Addresses-Coverity: ("Dereference after null check") Fixes: 7414705ea4ae ("libfc: Add runtime debugging with debug_logging module parameter") Signed-off-by: Colin Ian King Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/libfc/fc_exch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 42bcf7f3a0f9..6ba257cbc6d9 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -2603,7 +2603,7 @@ void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp) /* lport lock ? */ if (!lport || lport->state == LPORT_ST_DISABLED) { - FC_LPORT_DBG(lport, "Receiving frames for an lport that " + FC_LIBFC_DBG("Receiving frames for an lport that " "has not been initialized correctly\n"); fc_frame_free(fp); return; -- GitLab From ed45a2de36f8ecadebabe6cbc09607c9fc144aef Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Sat, 13 Jul 2019 11:46:28 +0800 Subject: [PATCH 0550/1055] clk: sunxi-ng: v3s: add the missing PLL_DDR1 [ Upstream commit c5ed9475c22c89d5409402055142372e35d26a3f ] The user manual of V3/V3s/S3 declares a PLL_DDR1, however it's forgot when developing the V3s CCU driver. Add back the missing PLL_DDR1. Fixes: d0f11d14b0bc ("clk: sunxi-ng: add support for V3s CCU") Signed-off-by: Icenowy Zheng Signed-off-by: Maxime Ripard Signed-off-by: Sasha Levin --- drivers/clk/sunxi-ng/ccu-sun8i-v3s.c | 19 +++++++++++++++---- drivers/clk/sunxi-ng/ccu-sun8i-v3s.h | 6 ++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c index 9e3f4088724b..c7f9d974b10d 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c @@ -84,7 +84,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", BIT(28), /* lock */ 0); -static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr_clk, "pll-ddr", +static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr0_clk, "pll-ddr0", "osc24M", 0x020, 8, 5, /* N */ 4, 2, /* K */ @@ -123,6 +123,14 @@ static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph1_clk, "pll-periph1", 2, /* post-div */ 0); +static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_ddr1_clk, "pll-ddr1", + "osc24M", 0x04c, + 8, 7, /* N */ + 0, 2, /* M */ + BIT(31), /* gate */ + BIT(28), /* lock */ + 0); + static const char * const cpu_parents[] = { "osc32k", "osc24M", "pll-cpu", "pll-cpu" }; static SUNXI_CCU_MUX(cpu_clk, "cpu", cpu_parents, @@ -310,7 +318,8 @@ static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M", static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc24M", 0x0cc, BIT(16), 0); -static const char * const dram_parents[] = { "pll-ddr", "pll-periph0-2x" }; +static const char * const dram_parents[] = { "pll-ddr0", "pll-ddr1", + "pll-periph0-2x" }; static SUNXI_CCU_M_WITH_MUX(dram_clk, "dram", dram_parents, 0x0f4, 0, 4, 20, 2, CLK_IS_CRITICAL); @@ -369,10 +378,11 @@ static struct ccu_common *sun8i_v3s_ccu_clks[] = { &pll_audio_base_clk.common, &pll_video_clk.common, &pll_ve_clk.common, - &pll_ddr_clk.common, + &pll_ddr0_clk.common, &pll_periph0_clk.common, &pll_isp_clk.common, &pll_periph1_clk.common, + &pll_ddr1_clk.common, &cpu_clk.common, &axi_clk.common, &ahb1_clk.common, @@ -457,11 +467,12 @@ static struct clk_hw_onecell_data sun8i_v3s_hw_clks = { [CLK_PLL_AUDIO_8X] = &pll_audio_8x_clk.hw, [CLK_PLL_VIDEO] = &pll_video_clk.common.hw, [CLK_PLL_VE] = &pll_ve_clk.common.hw, - [CLK_PLL_DDR] = &pll_ddr_clk.common.hw, + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw, [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw, [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw, [CLK_PLL_ISP] = &pll_isp_clk.common.hw, [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw, + [CLK_PLL_DDR1] = &pll_ddr1_clk.common.hw, [CLK_CPU] = &cpu_clk.common.hw, [CLK_AXI] = &axi_clk.common.hw, [CLK_AHB1] = &ahb1_clk.common.hw, diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.h b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.h index 4a4d36fdad96..a091b7217dfd 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.h +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.h @@ -29,7 +29,7 @@ #define CLK_PLL_AUDIO_8X 5 #define CLK_PLL_VIDEO 6 #define CLK_PLL_VE 7 -#define CLK_PLL_DDR 8 +#define CLK_PLL_DDR0 8 #define CLK_PLL_PERIPH0 9 #define CLK_PLL_PERIPH0_2X 10 #define CLK_PLL_ISP 11 @@ -58,6 +58,8 @@ /* And the GPU module clock is exported */ -#define CLK_NUMBER (CLK_MIPI_CSI + 1) +#define CLK_PLL_DDR1 74 + +#define CLK_NUMBER (CLK_PLL_DDR1 + 1) #endif /* _CCU_SUN8I_H3_H_ */ -- GitLab From 07f604c86825735985d4f1c8a4bd01e76132baa1 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 15 Jul 2019 13:03:48 +0200 Subject: [PATCH 0551/1055] PM: sleep: Fix possible overflow in pm_system_cancel_wakeup() [ Upstream commit 2933954b71f10d392764f95eec0f0aa2d103054b ] It is not actually guaranteed that pm_abort_suspend will be nonzero when pm_system_cancel_wakeup() is called which may lead to subtle issues, so make it use atomic_dec_if_positive() instead of atomic_dec() for the safety sake. Fixes: 33e4f80ee69b ("ACPI / PM: Ignore spurious SCI wakeups from suspend-to-idle") Signed-off-by: Rafael J. Wysocki Acked-by: Thomas Gleixner Signed-off-by: Sasha Levin --- drivers/base/power/wakeup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index df53e2b3296b..877b2a1767a5 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -877,7 +877,7 @@ EXPORT_SYMBOL_GPL(pm_system_wakeup); void pm_system_cancel_wakeup(void) { - atomic_dec(&pm_abort_suspend); + atomic_dec_if_positive(&pm_abort_suspend); } void pm_wakeup_clear(bool reset) -- GitLab From cade65b0a4545b71843dcea2764931f64c5e24bf Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 16 Jul 2019 22:42:18 +0800 Subject: [PATCH 0552/1055] libertas_tf: Use correct channel range in lbtf_geo_init [ Upstream commit 2ec4ad49b98e4a14147d04f914717135eca7c8b1 ] It seems we should use 'range' instead of 'priv->range' in lbtf_geo_init(), because 'range' is the corret one related to current regioncode. Reported-by: Hulk Robot Fixes: 691cdb49388b ("libertas_tf: command helper functions for libertas_tf") Signed-off-by: YueHaibing Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin --- drivers/net/wireless/marvell/libertas_tf/cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/marvell/libertas_tf/cmd.c b/drivers/net/wireless/marvell/libertas_tf/cmd.c index 909ac3685010..2b193f1257a5 100644 --- a/drivers/net/wireless/marvell/libertas_tf/cmd.c +++ b/drivers/net/wireless/marvell/libertas_tf/cmd.c @@ -69,7 +69,7 @@ static void lbtf_geo_init(struct lbtf_private *priv) break; } - for (ch = priv->range.start; ch < priv->range.end; ch++) + for (ch = range->start; ch < range->end; ch++) priv->channels[CHAN_TO_IDX(ch)].flags = 0; } -- GitLab From 8f08d7d4acf11febbb125489c0e123c1d22e8744 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 22 Jul 2019 17:01:23 +0200 Subject: [PATCH 0553/1055] qed: reduce maximum stack frame size [ Upstream commit 7c116e02a4a7575c8c62bfd2106e3e3ec8fb99dc ] clang warns about an overly large stack frame in one function when it decides to inline all __qed_get_vport_*() functions into __qed_get_vport_stats(): drivers/net/ethernet/qlogic/qed/qed_l2.c:1889:13: error: stack frame size of 1128 bytes in function '_qed_get_vport_stats' [-Werror,-Wframe-larger-than=] Use a noinline_for_stack annotation to prevent clang from inlining these, which keeps the maximum stack usage at around half of that in the worst case, similar to what we get with gcc. Fixes: 86622ee75312 ("qed: Move statistics to L2 code") Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/qlogic/qed/qed_l2.c | 34 +++++++++++------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c index 62cde3854a5c..5d7adedac68d 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c @@ -1629,10 +1629,9 @@ static void __qed_get_vport_pstats_addrlen(struct qed_hwfn *p_hwfn, } } -static void __qed_get_vport_pstats(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct qed_eth_stats *p_stats, - u16 statistics_bin) +static noinline_for_stack void +__qed_get_vport_pstats(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_eth_stats *p_stats, u16 statistics_bin) { struct eth_pstorm_per_queue_stat pstats; u32 pstats_addr = 0, pstats_len = 0; @@ -1659,10 +1658,9 @@ static void __qed_get_vport_pstats(struct qed_hwfn *p_hwfn, HILO_64_REGPAIR(pstats.error_drop_pkts); } -static void __qed_get_vport_tstats(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct qed_eth_stats *p_stats, - u16 statistics_bin) +static noinline_for_stack void +__qed_get_vport_tstats(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_eth_stats *p_stats, u16 statistics_bin) { struct tstorm_per_port_stat tstats; u32 tstats_addr, tstats_len; @@ -1705,10 +1703,9 @@ static void __qed_get_vport_ustats_addrlen(struct qed_hwfn *p_hwfn, } } -static void __qed_get_vport_ustats(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct qed_eth_stats *p_stats, - u16 statistics_bin) +static noinline_for_stack +void __qed_get_vport_ustats(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_eth_stats *p_stats, u16 statistics_bin) { struct eth_ustorm_per_queue_stat ustats; u32 ustats_addr = 0, ustats_len = 0; @@ -1747,10 +1744,9 @@ static void __qed_get_vport_mstats_addrlen(struct qed_hwfn *p_hwfn, } } -static void __qed_get_vport_mstats(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct qed_eth_stats *p_stats, - u16 statistics_bin) +static noinline_for_stack void +__qed_get_vport_mstats(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_eth_stats *p_stats, u16 statistics_bin) { struct eth_mstorm_per_queue_stat mstats; u32 mstats_addr = 0, mstats_len = 0; @@ -1776,9 +1772,9 @@ static void __qed_get_vport_mstats(struct qed_hwfn *p_hwfn, HILO_64_REGPAIR(mstats.tpa_coalesced_bytes); } -static void __qed_get_vport_port_stats(struct qed_hwfn *p_hwfn, - struct qed_ptt *p_ptt, - struct qed_eth_stats *p_stats) +static noinline_for_stack void +__qed_get_vport_port_stats(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, + struct qed_eth_stats *p_stats) { struct qed_eth_stats_common *p_common = &p_stats->common; struct port_stats port_stats; -- GitLab From ccb5bd32b590aa439a8376228d0b6b6f883d69d8 Mon Sep 17 00:00:00 2001 From: Ruslan Bilovol Date: Sun, 7 Jul 2019 15:17:19 +0300 Subject: [PATCH 0554/1055] usb: host: xhci-hub: fix extra endianness conversion [ Upstream commit 6269e4c76eacabaea0d0099200ae1a455768d208 ] Don't do extra cpu_to_le32 conversion for put_unaligned_le32 because it is already implemented in this function. Fixes sparse error: xhci-hub.c:1152:44: warning: incorrect type in argument 1 (different base types) xhci-hub.c:1152:44: expected unsigned int [usertype] val xhci-hub.c:1152:44: got restricted __le32 [usertype] Fixes: 395f540 "xhci: support new USB 3.1 hub request to get extended port status" Cc: Mathias Nyman Signed-off-by: Ruslan Bilovol Link: https://lore.kernel.org/r/1562501839-26522-1-git-send-email-ruslan.bilovol@gmail.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/host/xhci-hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index d1363f3fabfa..3bb38d9dc45b 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1118,7 +1118,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, } port_li = readl(port_array[wIndex] + PORTLI); status = xhci_get_ext_port_status(temp, port_li); - put_unaligned_le32(cpu_to_le32(status), &buf[4]); + put_unaligned_le32(status, &buf[4]); } break; case SetPortFeature: -- GitLab From c8d45c212e5066ec20efca6dbe47f88096c33161 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 12 Jul 2019 11:24:09 +0200 Subject: [PATCH 0555/1055] mic: avoid statically declaring a 'struct device'. [ Upstream commit bc83f79bd2119230888fb8574639d5a51b38f903 ] Generally, declaring a platform device as a static variable is a bad idea and can cause all kinds of problems, in particular with the DMA configuration and lifetime rules. A specific problem we hit here is from a bug in clang that warns about certain (otherwise valid) macros when used in static variables: drivers/misc/mic/card/mic_x100.c:285:27: warning: shift count >= width of type [-Wshift-count-overflow] static u64 mic_dma_mask = DMA_BIT_MASK(64); ^~~~~~~~~~~~~~~~ include/linux/dma-mapping.h:141:54: note: expanded from macro 'DMA_BIT_MASK' #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) ^ ~~~ A slightly better way here is to create the platform device dynamically and set the dma mask in the probe function. This avoids the warning and some other problems, but is still not ideal because the device creation should really be separated from the driver, and the fact that the device has no parent means we have to force the dma mask rather than having it set up from the bus that the device is actually on. Fixes: dd8d8d44df64 ("misc: mic: MIC card driver specific changes to enable SCIF") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20190712092426.872625-1-arnd@arndb.de Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/misc/mic/card/mic_x100.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/misc/mic/card/mic_x100.c b/drivers/misc/mic/card/mic_x100.c index b9f0710ffa6b..4007adc666f3 100644 --- a/drivers/misc/mic/card/mic_x100.c +++ b/drivers/misc/mic/card/mic_x100.c @@ -249,6 +249,9 @@ static int __init mic_probe(struct platform_device *pdev) mdrv->dev = &pdev->dev; snprintf(mdrv->name, sizeof(mic_driver_name), mic_driver_name); + /* FIXME: use dma_set_mask_and_coherent() and check result */ + dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + mdev->mmio.pa = MIC_X100_MMIO_BASE; mdev->mmio.len = MIC_X100_MMIO_LEN; mdev->mmio.va = devm_ioremap(&pdev->dev, MIC_X100_MMIO_BASE, @@ -294,18 +297,6 @@ static void mic_platform_shutdown(struct platform_device *pdev) mic_remove(pdev); } -static u64 mic_dma_mask = DMA_BIT_MASK(64); - -static struct platform_device mic_platform_dev = { - .name = mic_driver_name, - .id = 0, - .num_resources = 0, - .dev = { - .dma_mask = &mic_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(64), - }, -}; - static struct platform_driver __refdata mic_platform_driver = { .probe = mic_probe, .remove = mic_remove, @@ -315,6 +306,8 @@ static struct platform_driver __refdata mic_platform_driver = { }, }; +static struct platform_device *mic_platform_dev; + static int __init mic_init(void) { int ret; @@ -328,9 +321,12 @@ static int __init mic_init(void) request_module("mic_x100_dma"); mic_init_card_debugfs(); - ret = platform_device_register(&mic_platform_dev); + + mic_platform_dev = platform_device_register_simple(mic_driver_name, + 0, NULL, 0); + ret = PTR_ERR_OR_ZERO(mic_platform_dev); if (ret) { - pr_err("platform_device_register ret %d\n", ret); + pr_err("platform_device_register_full ret %d\n", ret); goto cleanup_debugfs; } ret = platform_driver_register(&mic_platform_driver); @@ -341,7 +337,7 @@ static int __init mic_init(void) return ret; device_unregister: - platform_device_unregister(&mic_platform_dev); + platform_device_unregister(mic_platform_dev); cleanup_debugfs: mic_exit_card_debugfs(); done: @@ -351,7 +347,7 @@ static int __init mic_init(void) static void __exit mic_exit(void) { platform_driver_unregister(&mic_platform_driver); - platform_device_unregister(&mic_platform_dev); + platform_device_unregister(mic_platform_dev); mic_exit_card_debugfs(); } -- GitLab From 8d3b98c7a9b6019ef93c3838db68f31f4d3c5f60 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 22 Jul 2019 20:47:06 +0200 Subject: [PATCH 0556/1055] x86/kgbd: Use NMI_VECTOR not APIC_DM_NMI [ Upstream commit 2591bc4e8d70b4e1330d327fb7e3921f4e070a51 ] apic->send_IPI_allbutself() takes a vector number as argument. APIC_DM_NMI is clearly not a vector number. It's defined to 0x400 which is outside the vector space. Use NMI_VECTOR instead as that's what it is intended to be. Fixes: 82da3ff89dc2 ("x86: kgdb support") Signed-off-by: Thomas Gleixner Acked-by: Peter Zijlstra (Intel) Link: https://lkml.kernel.org/r/20190722105218.855189979@linutronix.de Signed-off-by: Sasha Levin --- arch/x86/kernel/kgdb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 8e36f249646e..904e18bb38c5 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -438,7 +438,7 @@ static void kgdb_disable_hw_debug(struct pt_regs *regs) */ void kgdb_roundup_cpus(unsigned long flags) { - apic->send_IPI_allbutself(APIC_DM_NMI); + apic->send_IPI_allbutself(NMI_VECTOR); } #endif -- GitLab From c877153dc53dc4abf4d85ce587735bb284fd7f28 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 12 Jul 2019 10:59:24 +0200 Subject: [PATCH 0557/1055] crypto: ccp - Reduce maximum stack usage [ Upstream commit 72c8117adfced37df101c8c0b3f363e0906f83f0 ] Each of the operations in ccp_run_cmd() needs several hundred bytes of kernel stack. Depending on the inlining, these may need separate stack slots that add up to more than the warning limit, as shown in this clang based build: drivers/crypto/ccp/ccp-ops.c:871:12: error: stack frame size of 1164 bytes in function 'ccp_run_aes_cmd' [-Werror,-Wframe-larger-than=] static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) The problem may also happen when there is no warning, e.g. in the ccp_run_cmd()->ccp_run_aes_cmd()->ccp_run_aes_gcm_cmd() call chain with over 2000 bytes. Mark each individual function as 'noinline_for_stack' to prevent this from happening, and move the calls to the two special cases for aes into the top-level function. This will keep the actual combined stack usage to the mimimum: 828 bytes for ccp_run_aes_gcm_cmd() and at most 524 bytes for each of the other cases. Fixes: 63b945091a07 ("crypto: ccp - CCP device driver and interface support") Signed-off-by: Arnd Bergmann Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- drivers/crypto/ccp/ccp-ops.c | 52 +++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index 4b48b8523a40..330853a2702f 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -458,8 +458,8 @@ static int ccp_copy_from_sb(struct ccp_cmd_queue *cmd_q, return ccp_copy_to_from_sb(cmd_q, wa, jobid, sb, byte_swap, true); } -static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, - struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_aes_engine *aes = &cmd->u.aes; struct ccp_dm_workarea key, ctx; @@ -614,8 +614,8 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, return ret; } -static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, - struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_aes_engine *aes = &cmd->u.aes; struct ccp_dm_workarea key, ctx, final_wa, tag; @@ -897,7 +897,8 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, return ret; } -static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_aes_engine *aes = &cmd->u.aes; struct ccp_dm_workarea key, ctx; @@ -907,12 +908,6 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) bool in_place = false; int ret; - if (aes->mode == CCP_AES_MODE_CMAC) - return ccp_run_aes_cmac_cmd(cmd_q, cmd); - - if (aes->mode == CCP_AES_MODE_GCM) - return ccp_run_aes_gcm_cmd(cmd_q, cmd); - if (!((aes->key_len == AES_KEYSIZE_128) || (aes->key_len == AES_KEYSIZE_192) || (aes->key_len == AES_KEYSIZE_256))) @@ -1080,8 +1075,8 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, - struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_xts_aes_engine *xts = &cmd->u.xts; struct ccp_dm_workarea key, ctx; @@ -1280,7 +1275,8 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, return ret; } -static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_des3_engine *des3 = &cmd->u.des3; @@ -1476,7 +1472,8 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_sha_engine *sha = &cmd->u.sha; struct ccp_dm_workarea ctx; @@ -1820,7 +1817,8 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_rsa_engine *rsa = &cmd->u.rsa; struct ccp_dm_workarea exp, src, dst; @@ -1951,8 +1949,8 @@ static int ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, - struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_passthru_engine *pt = &cmd->u.passthru; struct ccp_dm_workarea mask; @@ -2083,7 +2081,8 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, return ret; } -static int ccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q, +static noinline_for_stack int +ccp_run_passthru_nomap_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_passthru_nomap_engine *pt = &cmd->u.passthru_nomap; @@ -2424,7 +2423,8 @@ static int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) return ret; } -static int ccp_run_ecc_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +static noinline_for_stack int +ccp_run_ecc_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) { struct ccp_ecc_engine *ecc = &cmd->u.ecc; @@ -2461,7 +2461,17 @@ int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) switch (cmd->engine) { case CCP_ENGINE_AES: - ret = ccp_run_aes_cmd(cmd_q, cmd); + switch (cmd->u.aes.mode) { + case CCP_AES_MODE_CMAC: + ret = ccp_run_aes_cmac_cmd(cmd_q, cmd); + break; + case CCP_AES_MODE_GCM: + ret = ccp_run_aes_gcm_cmd(cmd_q, cmd); + break; + default: + ret = ccp_run_aes_cmd(cmd_q, cmd); + break; + } break; case CCP_ENGINE_XTS_AES_128: ret = ccp_run_xts_aes_cmd(cmd_q, cmd); -- GitLab From 183eebd4efa7904e6d9e95b8e482f2969f743f66 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 29 Jul 2019 09:14:22 +0200 Subject: [PATCH 0558/1055] ALSA: aoa: onyx: always initialize register read value [ Upstream commit f474808acb3c4b30552d9c59b181244e0300d218 ] A lot of places in the driver use onyx_read_register() without checking the return value, and it's been working OK for ~10 years or so, so probably never fails ... Rather than trying to check the return value everywhere, which would be relatively intrusive, at least make sure we don't use an uninitialized value. Fixes: f3d9478b2ce4 ("[ALSA] snd-aoa: add snd-aoa") Reported-by: Stephen Rothwell Signed-off-by: Johannes Berg Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin --- sound/aoa/codecs/onyx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c index d2d96ca082b7..6224fd3bbf7c 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/onyx.c @@ -74,8 +74,10 @@ static int onyx_read_register(struct onyx *onyx, u8 reg, u8 *value) return 0; } v = i2c_smbus_read_byte_data(onyx->i2c, reg); - if (v < 0) + if (v < 0) { + *value = 0; return -1; + } *value = (u8)v; onyx->cache[ONYX_REG_CONTROL-FIRSTREGISTER] = *value; return 0; -- GitLab From 801dafc3218c23ba1ea39f409b962113604f64bc Mon Sep 17 00:00:00 2001 From: Jon Maloy Date: Tue, 30 Jul 2019 16:23:18 +0200 Subject: [PATCH 0559/1055] tipc: reduce risk of wakeup queue starvation [ Upstream commit 7c5b42055964f587e55bd87ef334c3a27e95d144 ] In commit 365ad353c256 ("tipc: reduce risk of user starvation during link congestion") we allowed senders to add exactly one list of extra buffers to the link backlog queues during link congestion (aka "oversubscription"). However, the criteria for when to stop adding wakeup messages to the input queue when the overload abates is inaccurate, and may cause starvation problems during very high load. Currently, we stop adding wakeup messages after 10 total failed attempts where we find that there is no space left in the backlog queue for a certain importance level. The counter for this is accumulated across all levels, which may lead the algorithm to leave the loop prematurely, although there may still be plenty of space available at some levels. The result is sometimes that messages near the wakeup queue tail are not added to the input queue as they should be. We now introduce a more exact algorithm, where we keep adding wakeup messages to a level as long as the backlog queue has free slots for the corresponding level, and stop at the moment there are no more such slots or when there are no more wakeup messages to dequeue. Fixes: 365ad35 ("tipc: reduce risk of user starvation during link congestion") Reported-by: Tung Nguyen Acked-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/tipc/link.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index da749916faac..82e4e0e152d1 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -811,18 +811,31 @@ static int link_schedule_user(struct tipc_link *l, struct tipc_msg *hdr) */ void link_prepare_wakeup(struct tipc_link *l) { + struct sk_buff_head *wakeupq = &l->wakeupq; + struct sk_buff_head *inputq = l->inputq; struct sk_buff *skb, *tmp; - int imp, i = 0; + struct sk_buff_head tmpq; + int avail[5] = {0,}; + int imp = 0; + + __skb_queue_head_init(&tmpq); - skb_queue_walk_safe(&l->wakeupq, skb, tmp) { + for (; imp <= TIPC_SYSTEM_IMPORTANCE; imp++) + avail[imp] = l->backlog[imp].limit - l->backlog[imp].len; + + skb_queue_walk_safe(wakeupq, skb, tmp) { imp = TIPC_SKB_CB(skb)->chain_imp; - if (l->backlog[imp].len < l->backlog[imp].limit) { - skb_unlink(skb, &l->wakeupq); - skb_queue_tail(l->inputq, skb); - } else if (i++ > 10) { - break; - } + if (avail[imp] <= 0) + continue; + avail[imp]--; + __skb_unlink(skb, wakeupq); + __skb_queue_tail(&tmpq, skb); } + + spin_lock_bh(&inputq->lock); + skb_queue_splice_tail(&tmpq, inputq); + spin_unlock_bh(&inputq->lock); + } void tipc_link_reset(struct tipc_link *l) -- GitLab From 9abc2bb43a47a30ea1ccbf8d27bc8d92604404bd Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 19 Jun 2019 14:29:58 +0200 Subject: [PATCH 0560/1055] ARM: dts: stm32: add missing vdda-supply to adc on stm32h743i-eval [ Upstream commit 493e84c5dc4d703d976b5875f5db22dae08a0782 ] Add missing vdda-supply required by STM32 ADC. Fixes: 090992a9ca54 ("ARM: dts: stm32: enable ADC on stm32h743i-eval board") Signed-off-by: Fabrice Gasnier Signed-off-by: Alexandre Torgue Signed-off-by: Sasha Levin --- arch/arm/boot/dts/stm32h743i-eval.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/stm32h743i-eval.dts b/arch/arm/boot/dts/stm32h743i-eval.dts index 6c07786e7ddb..0d98b2865bd7 100644 --- a/arch/arm/boot/dts/stm32h743i-eval.dts +++ b/arch/arm/boot/dts/stm32h743i-eval.dts @@ -71,6 +71,7 @@ }; &adc_12 { + vdda-supply = <&vdda>; vref-supply = <&vdda>; status = "okay"; adc1: adc@0 { -- GitLab From ed1929a76537c41b212adc93013e46dd3f7b46f9 Mon Sep 17 00:00:00 2001 From: Mark Zhang Date: Wed, 31 Jul 2019 14:40:13 +0300 Subject: [PATCH 0561/1055] net/mlx5: Fix mlx5_ifc_query_lag_out_bits [ Upstream commit ea77388b02270b0af8dc57f668f311235ea068f0 ] Remove the "reserved_at_40" field to match the device specification. Fixes: 84df61ebc69b ("net/mlx5: Add HW interfaces used by LAG") Signed-off-by: Mark Zhang Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Sasha Levin --- include/linux/mlx5/mlx5_ifc.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 1d793d86d55f..6ffa181598e6 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -8671,8 +8671,6 @@ struct mlx5_ifc_query_lag_out_bits { u8 syndrome[0x20]; - u8 reserved_at_40[0x40]; - struct mlx5_ifc_lagc_bits ctx; }; -- GitLab From f996f9ee615bebddcab67e4ebaeb5ce56956d256 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 23 Jul 2019 22:14:29 -0500 Subject: [PATCH 0562/1055] cifs: fix rmmod regression in cifs.ko caused by force_sig changes [ Upstream commit 247bc9470b1eeefc7b58cdf2c39f2866ba651509 ] Fixes: 72abe3bcf091 ("signal/cifs: Fix cifs_put_tcp_session to call send_sig instead of force_sig") The global change from force_sig caused module unloading of cifs.ko to fail (since the cifsd process could not be killed, "rmmod cifs" now would always fail) Signed-off-by: Steve French Reviewed-by: Ronnie Sahlberg CC: Eric W. Biederman Signed-off-by: Sasha Levin --- fs/cifs/connect.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 51bbb1c0b71a..ed4a0352ea90 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -921,6 +921,7 @@ cifs_demultiplex_thread(void *p) mempool_resize(cifs_req_poolp, length + cifs_min_rcv); set_freezable(); + allow_signal(SIGKILL); while (server->tcpStatus != CifsExiting) { if (try_to_freeze()) continue; -- GitLab From 5ea904f9954ee9072114a8d52c951b13bb8ed7bd Mon Sep 17 00:00:00 2001 From: Iuliana Prodan Date: Wed, 31 Jul 2019 16:08:12 +0300 Subject: [PATCH 0563/1055] crypto: caam - free resources in case caam_rng registration failed [ Upstream commit c59a1d41672a89b5cac49db1a472ff889e35a2d2 ] Check the return value of the hardware registration for caam_rng and free resources in case of failure. Fixes: e24f7c9e87d4 ("crypto: caam - hwrng support") Signed-off-by: Iuliana Prodan Reviewed-by: Horia Geanta Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- drivers/crypto/caam/caamrng.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index fde07d4ff019..ff6718a11e9e 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -353,7 +353,10 @@ static int __init caam_rng_init(void) goto free_rng_ctx; dev_info(dev, "registering rng-caam\n"); - return hwrng_register(&caam_rng); + + err = hwrng_register(&caam_rng); + if (!err) + return err; free_rng_ctx: kfree(rng_ctx); -- GitLab From 25f9e3e502a92782b5f9f270ba15b25490f65a77 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 12 Aug 2019 14:29:38 -0400 Subject: [PATCH 0564/1055] ext4: set error return correctly when ext4_htree_store_dirent fails [ Upstream commit 7a14826ede1d714f0bb56de8167c0e519041eeda ] Currently when the call to ext4_htree_store_dirent fails the error return variable 'ret' is is not being set to the error code and variable count is instead, hence the error code is not being returned. Fix this by assigning ret to the error return code. Addresses-Coverity: ("Unused value") Fixes: 8af0f0822797 ("ext4: fix readdir error in the case of inline_data+dir_index") Signed-off-by: Colin Ian King Signed-off-by: Theodore Ts'o Signed-off-by: Sasha Levin --- fs/ext4/inline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 137c752ab985..6064bcb8572b 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -1425,7 +1425,7 @@ int htree_inlinedir_to_tree(struct file *dir_file, err = ext4_htree_store_dirent(dir_file, hinfo->hash, hinfo->minor_hash, de, &tmp_str); if (err) { - count = err; + ret = err; goto out; } count++; -- GitLab From 02a996446ae1b0f09ed9d006578e0ca33196f2c7 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:23:00 +0800 Subject: [PATCH 0565/1055] ASoC: es8328: Fix copy-paste error in es8328_right_line_controls [ Upstream commit 630742c296341a8cfe00dfd941392025ba8dd4e8 ] It seems 'es8328_rline_enum' should be used in es8328_right_line_controls Fixes: 567e4f98922c ("ASoC: add es8328 codec driver") Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815092300.68712-1-yuehaibing@huawei.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/es8328.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index bcdb8914ec16..e2f44fa46262 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c @@ -231,7 +231,7 @@ static const struct soc_enum es8328_rline_enum = ARRAY_SIZE(es8328_line_texts), es8328_line_texts); static const struct snd_kcontrol_new es8328_right_line_controls = - SOC_DAPM_ENUM("Route", es8328_lline_enum); + SOC_DAPM_ENUM("Route", es8328_rline_enum); /* Left Mixer */ static const struct snd_kcontrol_new es8328_left_mixer_controls[] = { -- GitLab From 41c4947ed34f7d9e2ad460c84bd677f178e6f13c Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:01:57 +0800 Subject: [PATCH 0566/1055] ASoC: cs4349: Use PM ops 'cs4349_runtime_pm' [ Upstream commit 9b4275c415acca6264a3d7f1182589959c93d530 ] sound/soc/codecs/cs4349.c:358:32: warning: cs4349_runtime_pm defined but not used [-Wunused-const-variable=] cs4349_runtime_pm ops already defined, it seems we should enable it. Reported-by: Hulk Robot Fixes: e40da86 ("ASoC: cs4349: Add support for Cirrus Logic CS4349") Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190815090157.70036-1-yuehaibing@huawei.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/cs4349.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 0a749c79ef57..1d38e53dc95c 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -380,6 +380,7 @@ static struct i2c_driver cs4349_i2c_driver = { .driver = { .name = "cs4349", .of_match_table = cs4349_of_match, + .pm = &cs4349_runtime_pm, }, .id_table = cs4349_i2c_id, .probe = cs4349_i2c_probe, -- GitLab From b569bda1c5c0b3edfaabf155ec5a239676f86b79 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 15 Aug 2019 17:19:20 +0800 Subject: [PATCH 0567/1055] ASoC: wm8737: Fix copy-paste error in wm8737_snd_controls [ Upstream commit 554b75bde64bcad9662530726d1483f7ef012069 ] sound/soc/codecs/wm8737.c:112:29: warning: high_3d defined but not used [-Wunused-const-variable=] 'high_3d' should be used for 3D High Cut-off. Reported-by: Hulk Robot Fixes: 2a9ae13a2641 ("ASoC: Add initial WM8737 driver") Signed-off-by: YueHaibing Acked-by: Charles Keepax Link: https://lore.kernel.org/r/20190815091920.64480-1-yuehaibing@huawei.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/codecs/wm8737.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index f0cb1c4afe3c..c5a8d758f58b 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -170,7 +170,7 @@ SOC_DOUBLE("Polarity Invert Switch", WM8737_ADC_CONTROL, 5, 6, 1, 0), SOC_SINGLE("3D Switch", WM8737_3D_ENHANCE, 0, 1, 0), SOC_SINGLE("3D Depth", WM8737_3D_ENHANCE, 1, 15, 0), SOC_ENUM("3D Low Cut-off", low_3d), -SOC_ENUM("3D High Cut-off", low_3d), +SOC_ENUM("3D High Cut-off", high_3d), SOC_SINGLE_TLV("3D ADC Volume", WM8737_3D_ENHANCE, 7, 1, 1, adc_tlv), SOC_SINGLE("Noise Gate Switch", WM8737_NOISE_GATE, 0, 1, 0), -- GitLab From 060fc2173afad7e1f13c9b47b3a2d43e2d2afe6c Mon Sep 17 00:00:00 2001 From: Gerd Rausch Date: Thu, 11 Jul 2019 12:15:50 -0700 Subject: [PATCH 0568/1055] net/rds: Add a few missing rds_stat_names entries [ Upstream commit 55c70ca00c982fbc0df4c4d3e31747fb73f4ddb5 ] In a previous commit, fields were added to "struct rds_statistics" but array "rds_stat_names" was not updated accordingly. Please note the inconsistent naming of the string representations that is done in the name of compatibility with the Oracle internal code-base. s_recv_bytes_added_to_socket -> "recv_bytes_added_to_sock" s_recv_bytes_removed_from_socket -> "recv_bytes_freed_fromsock" Fixes: 192a798f5299 ("RDS: add stat for socket recv memory usage") Signed-off-by: Gerd Rausch Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/rds/stats.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/rds/stats.c b/net/rds/stats.c index 73be187d389e..6bbab4d74c4f 100644 --- a/net/rds/stats.c +++ b/net/rds/stats.c @@ -76,6 +76,8 @@ static const char *const rds_stat_names[] = { "cong_update_received", "cong_send_error", "cong_send_blocked", + "recv_bytes_added_to_sock", + "recv_bytes_freed_fromsock", }; void rds_stats_info_copy(struct rds_info_iterator *iter, -- GitLab From 1c5e0766089dceeeff6dde7dec7bb9e25d064a9c Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Sat, 17 Aug 2019 17:04:49 -0400 Subject: [PATCH 0569/1055] bnxt_en: Fix handling FRAG_ERR when NVM_INSTALL_UPDATE cmd fails [ Upstream commit dd2ebf3404c7c295014bc025dea23960960ceb1a ] If FW returns FRAG_ERR in response error code, driver is resending the command only when HWRM command returns success. Fix the code to resend NVM_INSTALL_UPDATE command with DEFRAG install flags, if FW returns FRAG_ERR in its response error code. Fixes: cb4d1d626145 ("bnxt_en: Retry failed NVM_INSTALL_UPDATE with defragmentation flag enabled.") Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 963beaa8fabb..3c78cd1cdd6f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1667,21 +1667,19 @@ static int bnxt_flash_package_from_file(struct net_device *dev, mutex_lock(&bp->hwrm_cmd_lock); hwrm_err = _hwrm_send_message(bp, &install, sizeof(install), INSTALL_PACKAGE_TIMEOUT); - if (hwrm_err) - goto flash_pkg_exit; - - if (resp->error_code) { + if (hwrm_err) { u8 error_code = ((struct hwrm_err_output *)resp)->cmd_err; - if (error_code == NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) { + if (resp->error_code && error_code == + NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) { install.flags |= cpu_to_le16( NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG); hwrm_err = _hwrm_send_message(bp, &install, sizeof(install), INSTALL_PACKAGE_TIMEOUT); - if (hwrm_err) - goto flash_pkg_exit; } + if (hwrm_err) + goto flash_pkg_exit; } if (resp->result) { -- GitLab From cde0dc52e7d462332bdcf7dc22ab6ccc865b4b52 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 16 Aug 2019 12:33:54 -0500 Subject: [PATCH 0570/1055] signal: Allow cifs and drbd to receive their terminating signals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 33da8e7c814f77310250bb54a9db36a44c5de784 ] My recent to change to only use force_sig for a synchronous events wound up breaking signal reception cifs and drbd. I had overlooked the fact that by default kthreads start out with all signals set to SIG_IGN. So a change I thought was safe turned out to have made it impossible for those kernel thread to catch their signals. Reverting the work on force_sig is a bad idea because what the code was doing was very much a misuse of force_sig. As the way force_sig ultimately allowed the signal to happen was to change the signal handler to SIG_DFL. Which after the first signal will allow userspace to send signals to these kernel threads. At least for wake_ack_receiver in drbd that does not appear actively wrong. So correct this problem by adding allow_kernel_signal that will allow signals whose siginfo reports they were sent by the kernel through, but will not allow userspace generated signals, and update cifs and drbd to call allow_kernel_signal in an appropriate place so that their thread can receive this signal. Fixing things this way ensures that userspace won't be able to send signals and cause problems, that it is clear which signals the threads are expecting to receive, and it guarantees that nothing else in the system will be affected. This change was partly inspired by similar cifs and drbd patches that added allow_signal. Reported-by: ronnie sahlberg Reported-by: Christoph Böhmwalder Tested-by: Christoph Böhmwalder Cc: Steve French Cc: Philipp Reisner Cc: David Laight Fixes: 247bc9470b1e ("cifs: fix rmmod regression in cifs.ko caused by force_sig changes") Fixes: 72abe3bcf091 ("signal/cifs: Fix cifs_put_tcp_session to call send_sig instead of force_sig") Fixes: fee109901f39 ("signal/drbd: Use send_sig not force_sig") Fixes: 3cf5d076fb4d ("signal: Remove task parameter from force_sig") Signed-off-by: "Eric W. Biederman" Signed-off-by: Sasha Levin --- drivers/block/drbd/drbd_main.c | 2 ++ fs/cifs/connect.c | 2 +- include/linux/signal.h | 15 ++++++++++++++- kernel/signal.c | 5 +++++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 7ea13b5497fd..b998e3abca7a 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -334,6 +334,8 @@ static int drbd_thread_setup(void *arg) thi->name[0], resource->name); + allow_kernel_signal(DRBD_SIGKILL); + allow_kernel_signal(SIGXCPU); restart: retval = thi->function(thi); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index ed4a0352ea90..f0b1279a7de6 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -921,7 +921,7 @@ cifs_demultiplex_thread(void *p) mempool_resize(cifs_req_poolp, length + cifs_min_rcv); set_freezable(); - allow_signal(SIGKILL); + allow_kernel_signal(SIGKILL); while (server->tcpStatus != CifsExiting) { if (try_to_freeze()) continue; diff --git a/include/linux/signal.h b/include/linux/signal.h index 843bd62b1ead..c4e3eb89a622 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -268,6 +268,9 @@ extern void signal_setup_done(int failed, struct ksignal *ksig, int stepping); extern void exit_signals(struct task_struct *tsk); extern void kernel_sigaction(int, __sighandler_t); +#define SIG_KTHREAD ((__force __sighandler_t)2) +#define SIG_KTHREAD_KERNEL ((__force __sighandler_t)3) + static inline void allow_signal(int sig) { /* @@ -275,7 +278,17 @@ static inline void allow_signal(int sig) * know it'll be handled, so that they don't get converted to * SIGKILL or just silently dropped. */ - kernel_sigaction(sig, (__force __sighandler_t)2); + kernel_sigaction(sig, SIG_KTHREAD); +} + +static inline void allow_kernel_signal(int sig) +{ + /* + * Kernel threads handle their own signals. Let the signal code + * know signals sent by the kernel will be handled, so that they + * don't get silently dropped. + */ + kernel_sigaction(sig, SIG_KTHREAD_KERNEL); } static inline void disallow_signal(int sig) diff --git a/kernel/signal.c b/kernel/signal.c index c9b203875001..8fee1f2eba2f 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -85,6 +85,11 @@ static int sig_task_ignored(struct task_struct *t, int sig, bool force) handler == SIG_DFL && !(force && sig_kernel_only(sig))) return 1; + /* Only allow kernel generated signals to this kthread */ + if (unlikely((t->flags & PF_KTHREAD) && + (handler == SIG_KTHREAD_KERNEL) && !force)) + return true; + return sig_handler_ignored(handler, sig); } -- GitLab From e62abd5b37521c7020d8650dcb753cc32a82df69 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Aug 2019 21:25:17 +0200 Subject: [PATCH 0571/1055] ASoC: sun4i-i2s: RX and TX counter registers are swapped [ Upstream commit cf2c0e1ce9544df42170fb921f12da82dc0cc8d6 ] The RX and TX counters registers offset have been swapped, fix that. Fixes: fa7c0d13cb26 ("ASoC: sunxi: Add Allwinner A10 Digital Audio driver") Signed-off-by: Maxime Ripard Link: https://lore.kernel.org/r/8b26477560ad5fd8f69e037b167c5e61de5c26a3.1566242458.git-series.maxime.ripard@bootlin.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/sunxi/sun4i-i2s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index da0a2083e12a..d2802fd8c1dd 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -80,8 +80,8 @@ #define SUN4I_I2S_CLK_DIV_MCLK_MASK GENMASK(3, 0) #define SUN4I_I2S_CLK_DIV_MCLK(mclk) ((mclk) << 0) -#define SUN4I_I2S_RX_CNT_REG 0x28 -#define SUN4I_I2S_TX_CNT_REG 0x2c +#define SUN4I_I2S_TX_CNT_REG 0x28 +#define SUN4I_I2S_RX_CNT_REG 0x2c #define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 #define SUN4I_I2S_CHAN_SEL(num_chan) (((num_chan) - 1) << 0) -- GitLab From 1b394b564c08798124b9b41b50019d1cf6ec9714 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 20 Aug 2019 16:15:43 +0300 Subject: [PATCH 0572/1055] dmaengine: dw: platform: Switch to acpi_dma_controller_register() [ Upstream commit e7b8514e4d68bec21fc6385fa0a66797ddc34ac9 ] There is a possibility to have registered ACPI DMA controller while it has been gone already. To avoid the potential crash, move to non-managed acpi_dma_controller_register(). Fixes: 42c91ee71d6d ("dw_dmac: add ACPI support") Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20190820131546.75744-8-andriy.shevchenko@linux.intel.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/dw/platform.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 46a519e07195..b408c07662f5 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -87,13 +87,20 @@ static void dw_dma_acpi_controller_register(struct dw_dma *dw) dma_cap_set(DMA_SLAVE, info->dma_cap); info->filter_fn = dw_dma_acpi_filter; - ret = devm_acpi_dma_controller_register(dev, acpi_dma_simple_xlate, - info); + ret = acpi_dma_controller_register(dev, acpi_dma_simple_xlate, info); if (ret) dev_err(dev, "could not register acpi_dma_controller\n"); } + +static void dw_dma_acpi_controller_free(struct dw_dma *dw) +{ + struct device *dev = dw->dma.dev; + + acpi_dma_controller_free(dev); +} #else /* !CONFIG_ACPI */ static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {} +static inline void dw_dma_acpi_controller_free(struct dw_dma *dw) {} #endif /* !CONFIG_ACPI */ #ifdef CONFIG_OF @@ -249,6 +256,9 @@ static int dw_remove(struct platform_device *pdev) { struct dw_dma_chip *chip = platform_get_drvdata(pdev); + if (ACPI_HANDLE(&pdev->dev)) + dw_dma_acpi_controller_free(chip->dw); + if (pdev->dev.of_node) of_dma_controller_free(pdev->dev.of_node); -- GitLab From 9878718005a17512f6fcdcbfc64a2a3837e07bc7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 20 Aug 2019 11:54:46 +0200 Subject: [PATCH 0573/1055] mac80211: minstrel_ht: fix per-group max throughput rate initialization [ Upstream commit 56dd918ff06e3ee24d8067e93ed12b2a39e71394 ] The group number needs to be multiplied by the number of rates per group to get the full rate index Fixes: 5935839ad735 ("mac80211: improve minstrel_ht rate sorting by throughput & probability") Signed-off-by: Felix Fietkau Link: https://lore.kernel.org/r/20190820095449.45255-1-nbd@nbd.name Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/mac80211/rc80211_minstrel_ht.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index e57811e4b91f..7ba4272642c9 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -529,7 +529,7 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) /* (re)Initialize group rate indexes */ for(j = 0; j < MAX_THR_RATES; j++) - tmp_group_tp_rate[j] = group; + tmp_group_tp_rate[j] = MCS_GROUP_RATES * group; for (i = 0; i < MCS_GROUP_RATES; i++) { if (!(mi->supported[group] & BIT(i))) -- GitLab From 4cd97e29c3dd3ef05c92dbae84bb45bceb9ea14b Mon Sep 17 00:00:00 2001 From: Alexandre Kroupski Date: Tue, 20 Aug 2019 08:37:45 -0300 Subject: [PATCH 0574/1055] media: atmel: atmel-isi: fix timeout value for stop streaming [ Upstream commit 623fd246bb40234fe68dd4e7c1f1f081f9c45a3d ] In case of sensor malfunction, stop streaming timeout takes much longer than expected. This is due to conversion of time to jiffies: milliseconds multiplied with HZ (ticks/second) gives out a value of jiffies with 10^3 greater. We need to also divide by 10^3 to obtain the right jiffies value. In other words FRAME_INTERVAL_MILLI_SEC must be in seconds in order to multiply by HZ and get the right jiffies value to add to the current jiffies for the timeout expire time. Fixes: 195ebc43bf76 ("[media] V4L: at91: add Atmel Image Sensor Interface (ISI) support") Signed-off-by: Alexandre Kroupski Reviewed-by: Eugen Hristev Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin --- drivers/media/platform/atmel/atmel-isi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 891fa2505efa..2f962a3418f6 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -496,7 +496,7 @@ static void stop_streaming(struct vb2_queue *vq) spin_unlock_irq(&isi->irqlock); if (!isi->enable_preview_path) { - timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; + timeout = jiffies + (FRAME_INTERVAL_MILLI_SEC * HZ) / 1000; /* Wait until the end of the current frame. */ while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && time_before(jiffies, timeout)) -- GitLab From 6698015a135887a55621e35f65f6b4a448f19e1f Mon Sep 17 00:00:00 2001 From: Bruno Thomsen Date: Thu, 22 Aug 2019 15:19:34 +0200 Subject: [PATCH 0575/1055] rtc: pcf2127: bugfix: read rtc disables watchdog [ Upstream commit 7f43020e3bdb63d65661ed377682702f8b34d3ea ] The previous fix listed bulk read of registers as root cause of accendential disabling of watchdog, since the watchdog counter register (WD_VAL) was zeroed. Fixes: 3769a375ab83 rtc: pcf2127: bulk read only date and time registers. Tested with the same PCF2127 chip as Sean reveled root cause of WD_VAL register value zeroing was caused by reading CTRL2 register which is one of the watchdog feature control registers. So the solution is to not read the first two control registers (CTRL1 and CTRL2) in pcf2127_rtc_read_time as they are not needed anyway. Size of local buf variable is kept to allow easy usage of register defines to improve readability of code. Debug trace line was updated after CTRL1 and CTRL2 are no longer read from the chip. Also replaced magic numbers in buf access with register defines. Signed-off-by: Bruno Thomsen Link: https://lore.kernel.org/r/20190822131936.18772-3-bruno.thomsen@gmail.com Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin --- drivers/rtc/rtc-pcf2127.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 9f1b14bf91ae..367e0f803440 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -52,20 +52,14 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) struct pcf2127 *pcf2127 = dev_get_drvdata(dev); unsigned char buf[10]; int ret; - int i; - for (i = 0; i <= PCF2127_REG_CTRL3; i++) { - ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1 + i, - (unsigned int *)(buf + i)); - if (ret) { - dev_err(dev, "%s: read error\n", __func__); - return ret; - } - } - - ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_SC, - (buf + PCF2127_REG_SC), - ARRAY_SIZE(buf) - PCF2127_REG_SC); + /* + * Avoid reading CTRL2 register as it causes WD_VAL register + * value to reset to 0 which means watchdog is stopped. + */ + ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL3, + (buf + PCF2127_REG_CTRL3), + ARRAY_SIZE(buf) - PCF2127_REG_CTRL3); if (ret) { dev_err(dev, "%s: read error\n", __func__); return ret; @@ -86,14 +80,12 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm) } dev_dbg(dev, - "%s: raw data is cr1=%02x, cr2=%02x, cr3=%02x, " - "sec=%02x, min=%02x, hr=%02x, " + "%s: raw data is cr3=%02x, sec=%02x, min=%02x, hr=%02x, " "mday=%02x, wday=%02x, mon=%02x, year=%02x\n", - __func__, - buf[0], buf[1], buf[2], - buf[3], buf[4], buf[5], - buf[6], buf[7], buf[8], buf[9]); - + __func__, buf[PCF2127_REG_CTRL3], buf[PCF2127_REG_SC], + buf[PCF2127_REG_MN], buf[PCF2127_REG_HR], + buf[PCF2127_REG_DM], buf[PCF2127_REG_DW], + buf[PCF2127_REG_MO], buf[PCF2127_REG_YR]); tm->tm_sec = bcd2bin(buf[PCF2127_REG_SC] & 0x7F); tm->tm_min = bcd2bin(buf[PCF2127_REG_MN] & 0x7F); -- GitLab From 0972c51f346f0be5581620d61afdea6857c08503 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Mon, 29 Jul 2019 14:10:12 -0700 Subject: [PATCH 0576/1055] mips: avoid explicit UB in assignment of mips_io_port_base [ Upstream commit 12051b318bc3ce5b42d6d786191008284b067d83 ] The code in question is modifying a variable declared const through pointer manipulation. Such code is explicitly undefined behavior, and is the lone issue preventing malta_defconfig from booting when built with Clang: If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined. LLVM is removing such assignments. A simple fix is to not declare variables const that you plan on modifying. Limiting the scope would be a better method of preventing unwanted writes to such a variable. Further, the code in question mentions "compiler bugs" without any links to bug reports, so it is difficult to know if the issue is resolved in GCC. The patch was authored in 2006, which would have been GCC 4.0.3 or 4.1.1. The minimal supported version of GCC in the Linux kernel is currently 4.6. For what its worth, there was UB before the commit in question, it just added a barrier and got lucky IRT codegen. I don't think there's any actual compiler bugs related, just runtime bugs due to UB. Link: https://github.com/ClangBuiltLinux/linux/issues/610 Fixes: 966f4406d903 ("[MIPS] Work around bad code generation for .") Reported-by: Nathan Chancellor Debugged-by: Nathan Chancellor Suggested-by: Eli Friedman Signed-off-by: Nick Desaulniers Reviewed-by: Nathan Chancellor Tested-by: Nathan Chancellor Signed-off-by: Paul Burton Cc: ralf@linux-mips.org Cc: jhogan@kernel.org Cc: Maciej W. Rozycki Cc: Hassan Naveed Cc: Stephen Kitt Cc: Serge Semin Cc: Mike Rapoport Cc: Andrew Morton Cc: Michal Hocko Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: clang-built-linux@googlegroups.com Signed-off-by: Sasha Levin --- arch/mips/include/asm/io.h | 14 ++------------ arch/mips/kernel/setup.c | 2 +- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 57b34257be2b..98eb15b0524c 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -60,21 +60,11 @@ * instruction, so the lower 16 bits must be zero. Should be true on * on any sane architecture; generic code does not use this assumption. */ -extern const unsigned long mips_io_port_base; +extern unsigned long mips_io_port_base; -/* - * Gcc will generate code to load the value of mips_io_port_base after each - * function call which may be fairly wasteful in some cases. So we don't - * play quite by the book. We tell gcc mips_io_port_base is a long variable - * which solves the code generation issue. Now we need to violate the - * aliasing rules a little to make initialization possible and finally we - * will need the barrier() to fight side effects of the aliasing chat. - * This trickery will eventually collapse under gcc's optimizer. Oh well. - */ static inline void set_io_port_base(unsigned long base) { - * (unsigned long *) &mips_io_port_base = base; - barrier(); + mips_io_port_base = base; } /* diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 795caa763da3..05ed4ed411c7 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -75,7 +75,7 @@ static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; * mips_io_port_base is the begin of the address space to which x86 style * I/O ports are mapped. */ -const unsigned long mips_io_port_base = -1; +unsigned long mips_io_port_base = -1; EXPORT_SYMBOL(mips_io_port_base); static struct resource code_resource = { .name = "Kernel code", }; -- GitLab From 91f098c085ceb891302fa9707d3da94be6a88524 Mon Sep 17 00:00:00 2001 From: Yong Wu Date: Sat, 24 Aug 2019 11:01:50 +0800 Subject: [PATCH 0577/1055] iommu/mediatek: Fix iova_to_phys PA start for 4GB mode [ Upstream commit 76ce65464fcd2c21db84391572b7938b716aceb0 ] In M4U 4GB mode, the physical address is remapped as below: CPU Physical address: ==================== 0 1G 2G 3G 4G 5G |---A---|---B---|---C---|---D---|---E---| +--I/O--+------------Memory-------------+ IOMMU output physical address: ============================= 4G 5G 6G 7G 8G |---E---|---B---|---C---|---D---| +------------Memory-------------+ The Region 'A'(I/O) can not be mapped by M4U; For Region 'B'/'C'/'D', the bit32 of the CPU physical address always is needed to set, and for Region 'E', the CPU physical address keep as is. something looks like this: CPU PA -> M4U OUTPUT PA 0x4000_0000 0x1_4000_0000 (Add bit32) 0x8000_0000 0x1_8000_0000 ... 0xc000_0000 0x1_c000_0000 ... 0x1_0000_0000 0x1_0000_0000 (No change) Additionally, the iommu consumers always use the CPU phyiscal address. The PA in the iova_to_phys that is got from v7s always is u32, But from the CPU point of view, PA only need add BIT(32) when PA < 0x4000_0000. Fixes: 30e2fccf9512 ("iommu/mediatek: Enlarge the validate PA range for 4GB mode") Signed-off-by: Yong Wu Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/mtk_iommu.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index c30f62700431..0f99e95a1a73 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -115,6 +115,30 @@ struct mtk_iommu_domain { static struct iommu_ops mtk_iommu_ops; +/* + * In M4U 4GB mode, the physical address is remapped as below: + * + * CPU Physical address: + * ==================== + * + * 0 1G 2G 3G 4G 5G + * |---A---|---B---|---C---|---D---|---E---| + * +--I/O--+------------Memory-------------+ + * + * IOMMU output physical address: + * ============================= + * + * 4G 5G 6G 7G 8G + * |---E---|---B---|---C---|---D---| + * +------------Memory-------------+ + * + * The Region 'A'(I/O) can NOT be mapped by M4U; For Region 'B'/'C'/'D', the + * bit32 of the CPU physical address always is needed to set, and for Region + * 'E', the CPU physical address keep as is. + * Additionally, The iommu consumers always use the CPU phyiscal address. + */ +#define MTK_IOMMU_4GB_MODE_REMAP_BASE 0x40000000 + static LIST_HEAD(m4ulist); /* List all the M4U HWs */ #define for_each_m4u(data) list_for_each_entry(data, &m4ulist, list) @@ -404,7 +428,7 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain, pa = dom->iop->iova_to_phys(dom->iop, iova); spin_unlock_irqrestore(&dom->pgtlock, flags); - if (data->enable_4GB) + if (data->enable_4GB && pa < MTK_IOMMU_4GB_MODE_REMAP_BASE) pa |= BIT_ULL(32); return pa; -- GitLab From e37950799ad018334e321c6fcbccdfbc1a909c85 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Aug 2019 22:42:55 +0300 Subject: [PATCH 0578/1055] ahci: Do not export local variable ahci_em_messages [ Upstream commit 60fc35f327e0a9e60b955c0f3c3ed623608d1baa ] The commit ed08d40cdec4 ("ahci: Changing two module params with static and __read_mostly") moved ahci_em_messages to be static while missing the fact of exporting it. WARNING: "ahci_em_messages" [vmlinux] is a static EXPORT_SYMBOL_GPL Drop export for the local variable ahci_em_messages. Fixes: ed08d40cdec4 ("ahci: Changing two module params with static and __read_mostly") Cc: Chuansheng Liu Signed-off-by: Andy Shevchenko Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin --- drivers/ata/libahci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index cda9a0b5bdaa..7473ff46de66 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -191,7 +191,6 @@ struct ata_port_operations ahci_pmp_retry_srst_ops = { EXPORT_SYMBOL_GPL(ahci_pmp_retry_srst_ops); static bool ahci_em_messages __read_mostly = true; -EXPORT_SYMBOL_GPL(ahci_em_messages); module_param(ahci_em_messages, bool, 0444); /* add other LED protocol types when they become supported */ MODULE_PARM_DESC(ahci_em_messages, -- GitLab From abb78b8d946459494af91302e6da94a9f3f9dab2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 30 Aug 2019 18:47:15 -0700 Subject: [PATCH 0579/1055] Partially revert "kfifo: fix kfifo_alloc() and kfifo_init()" [ Upstream commit ab9bb6318b0967671e0c9b6537c1537d51ca4f45 ] Commit dfe2a77fd243 ("kfifo: fix kfifo_alloc() and kfifo_init()") made the kfifo code round the number of elements up. That was good for __kfifo_alloc(), but it's actually wrong for __kfifo_init(). The difference? __kfifo_alloc() will allocate the rounded-up number of elements, but __kfifo_init() uses an allocation done by the caller. We can't just say "use more elements than the caller allocated", and have to round down. The good news? All the normal cases will be using power-of-two arrays anyway, and most users of kfifo's don't use kfifo_init() at all, but one of the helper macros to declare a KFIFO that enforce the proper power-of-two behavior. But it looks like at least ibmvscsis might be affected. The bad news? Will Deacon refers to an old thread and points points out that the memory ordering in kfifo's is questionable. See https://lore.kernel.org/lkml/20181211034032.32338-1-yuleixzhang@tencent.com/ for more. Fixes: dfe2a77fd243 ("kfifo: fix kfifo_alloc() and kfifo_init()") Reported-by: laokz Cc: Stefani Seibold Cc: Andrew Morton Cc: Dan Carpenter Cc: Greg KH Cc: Kees Cook Cc: Will Deacon Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- lib/kfifo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/kfifo.c b/lib/kfifo.c index 90ba1eb1df06..a94227c55551 100644 --- a/lib/kfifo.c +++ b/lib/kfifo.c @@ -82,7 +82,8 @@ int __kfifo_init(struct __kfifo *fifo, void *buffer, { size /= esize; - size = roundup_pow_of_two(size); + if (!is_power_of_2(size)) + size = rounddown_pow_of_two(size); fifo->in = 0; fifo->out = 0; -- GitLab From 8cf42a20d95d975fb46841413ecb6670fe791e3d Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 8 Aug 2019 12:00:18 -0700 Subject: [PATCH 0580/1055] hwmon: (lm75) Fix write operations for negative temperatures [ Upstream commit 7d82fcc9d9e81241778aaa22fda7be753e237d86 ] Writes into limit registers fail if the temperature written is negative. The regmap write operation checks the value range, regmap_write accepts an unsigned int as parameter, and the temperature value passed to regmap_write is kept in a variable declared as long. Negative values are converted large unsigned integers, which fails the range check. Fix by type casting the temperature to u16 when calling regmap_write(). Cc: Iker Perez del Palomar Sustatxa Fixes: e65365fed87f ("hwmon: (lm75) Convert to use regmap") Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/lm75.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 005ffb5ffa92..1737bb5fbaaf 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -165,7 +165,7 @@ static int lm75_write(struct device *dev, enum hwmon_sensor_types type, temp = DIV_ROUND_CLOSEST(temp << (resolution - 8), 1000) << (16 - resolution); - return regmap_write(data->regmap, reg, temp); + return regmap_write(data->regmap, reg, (u16)temp); } static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type, -- GitLab From 0d9754bd7419b466b47723781dd98b3a4c56fbe1 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 1 Aug 2019 14:33:30 -0700 Subject: [PATCH 0581/1055] power: supply: Init device wakeup after device_add() [ Upstream commit 8288022284859acbcc3cf1a073a1e2692d6c2543 ] We may want to use the device pointer in device_init_wakeup() with functions that expect the device to already be added with device_add(). For example, if we were to link the device initializing wakeup to something in sysfs such as a class for wakeups we'll run into an error. It looks like this code was written with the assumption that the device would be added before initializing wakeup due to the order of operations in power_supply_unregister(). Let's change the order of operations so we don't run into problems here. Fixes: 948dcf966228 ("power_supply: Prevent suspend until power supply events are processed") Cc: Greg Kroah-Hartman Cc: Tri Vo Cc: Kalesh Singh Cc: Ravi Chandra Sadineni Cc: Viresh Kumar Signed-off-by: Stephen Boyd Acked-by: Rafael J. Wysocki Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin --- drivers/power/supply/power_supply_core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 3226faebe0a0..0f1a0efd5926 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -891,14 +891,14 @@ __power_supply_register(struct device *parent, } spin_lock_init(&psy->changed_lock); - rc = device_init_wakeup(dev, ws); - if (rc) - goto wakeup_init_failed; - rc = device_add(dev); if (rc) goto device_add_failed; + rc = device_init_wakeup(dev, ws); + if (rc) + goto wakeup_init_failed; + rc = psy_register_thermal(psy); if (rc) goto register_thermal_failed; @@ -935,8 +935,8 @@ __power_supply_register(struct device *parent, psy_unregister_thermal(psy); register_thermal_failed: device_del(dev); -device_add_failed: wakeup_init_failed: +device_add_failed: check_supplies_failed: dev_set_name_failed: put_device(dev); -- GitLab From 236a45c27006a0c73f763240531a19a5fd6a5255 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sun, 1 Sep 2019 12:03:08 +0900 Subject: [PATCH 0582/1055] x86, perf: Fix the dependency of the x86 insn decoder selftest [ Upstream commit 7720804a2ae46c90265a32c81c45fb6f8d2f4e8b ] Since x86 instruction decoder is not only for kprobes, it should be tested when the insn.c is compiled. (e.g. perf is enabled but kprobes is disabled) Signed-off-by: Masami Hiramatsu Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: cbe5c34c8c1f ("x86: Compile insn.c and inat.c only for KPROBES") Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin --- arch/x86/Kconfig.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 6293a8768a91..bec0952c5595 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -189,7 +189,7 @@ config HAVE_MMIOTRACE_SUPPORT config X86_DECODER_SELFTEST bool "x86 instruction decoder selftest" - depends on DEBUG_KERNEL && KPROBES + depends on DEBUG_KERNEL && INSTRUCTION_DECODER depends on !COMPILE_TEST ---help--- Perform x86 instruction decoder selftests at build time. -- GitLab From b6cda623b5b86879d05fae8eb0e2b562a27dc3ce Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 29 Aug 2019 15:28:39 +0300 Subject: [PATCH 0583/1055] staging: greybus: light: fix a couple double frees [ Upstream commit 329101244f214952606359d254ae883b7109e1a5 ] The problem is in gb_lights_request_handler(). If we get a request to change the config then we release the light with gb_lights_light_release() and re-allocated it. However, if the allocation fails part way through then we call gb_lights_light_release() again. This can lead to a couple different double frees where we haven't cleared out the original values: gb_lights_light_v4l2_unregister(light); ... kfree(light->channels); kfree(light->name); I also made a small change to how we set "light->channels_count = 0;". The original code handled this part fine and did not cause a use after free but it was sort of complicated to read. Fixes: 2870b52bae4c ("greybus: lights: add lights implementation") Signed-off-by: Dan Carpenter Acked-by: Rui Miguel Silva Link: https://lore.kernel.org/r/20190829122839.GA20116@mwanda Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/staging/greybus/light.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/staging/greybus/light.c b/drivers/staging/greybus/light.c index 0f538b8c3a07..4e7575147775 100644 --- a/drivers/staging/greybus/light.c +++ b/drivers/staging/greybus/light.c @@ -1103,21 +1103,21 @@ static void gb_lights_channel_release(struct gb_channel *channel) static void gb_lights_light_release(struct gb_light *light) { int i; - int count; light->ready = false; - count = light->channels_count; - if (light->has_flash) gb_lights_light_v4l2_unregister(light); + light->has_flash = false; - for (i = 0; i < count; i++) { + for (i = 0; i < light->channels_count; i++) gb_lights_channel_release(&light->channels[i]); - light->channels_count--; - } + light->channels_count = 0; + kfree(light->channels); + light->channels = NULL; kfree(light->name); + light->name = NULL; } static void gb_lights_release(struct gb_lights *glights) -- GitLab From 4a3d966299aa7009cad9230107b4b0a2188c84e0 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 2 Sep 2019 23:14:56 +0000 Subject: [PATCH 0584/1055] irqdomain: Add the missing assignment of domain->fwnode for named fwnode [ Upstream commit 711419e504ebd68c8f03656616829c8ad7829389 ] Recently device pass-through stops working for Linux VM running on Hyper-V. git-bisect shows the regression is caused by the recent commit 467a3bb97432 ("PCI: hv: Allocate a named fwnode ..."), but the root cause is that the commit d59f6617eef0 forgets to set the domain->fwnode for IRQCHIP_FWNODE_NAMED*, and as a result: 1. The domain->fwnode remains to be NULL. 2. irq_find_matching_fwspec() returns NULL since "h->fwnode == fwnode" is false, and pci_set_bus_msi_domain() sets the Hyper-V PCI root bus's msi_domain to NULL. 3. When the device is added onto the root bus, the device's dev->msi_domain is set to NULL in pci_set_msi_domain(). 4. When a device driver tries to enable MSI-X, pci_msi_setup_msi_irqs() calls arch_setup_msi_irqs(), which uses the native MSI chip (i.e. arch/x86/kernel/apic/msi.c: pci_msi_controller) to set up the irqs, but actually pci_msi_setup_msi_irqs() is supposed to call msi_domain_alloc_irqs() with the hbus->irq_domain, which is created in hv_pcie_init_irq_domain() and is associated with the Hyper-V chip hv_msi_irq_chip. Consequently, the irq line is not properly set up, and the device driver can not receive any interrupt. Fixes: d59f6617eef0 ("genirq: Allow fwnode to carry name information only") Fixes: 467a3bb97432 ("PCI: hv: Allocate a named fwnode instead of an address-based one") Reported-by: Lili Deng Signed-off-by: Dexuan Cui Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/PU1P153MB01694D9AF625AC335C600C5FBFBE0@PU1P153MB0169.APCP153.PROD.OUTLOOK.COM Signed-off-by: Sasha Levin --- kernel/irq/irqdomain.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index ac4644e92b49..0f0e7975a309 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -147,6 +147,7 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size, switch (fwid->type) { case IRQCHIP_FWNODE_NAMED: case IRQCHIP_FWNODE_NAMED_ID: + domain->fwnode = fwnode; domain->name = kstrdup(fwid->name, GFP_KERNEL); if (!domain->name) { kfree(domain); -- GitLab From 950f6f8492deeb68cfe71799b5e1531e35c19463 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 27 Aug 2019 09:16:20 +0100 Subject: [PATCH 0585/1055] bcma: fix incorrect update of BCMA_CORE_PCI_MDIO_DATA [ Upstream commit 420c20be08a4597404d272ae9793b642401146eb ] An earlier commit re-worked the setting of the bitmask and is now assigning v with some bit flags rather than bitwise or-ing them into v, consequently the earlier bit-settings of v are being lost. Fix this by replacing an assignment with the bitwise or instead. Addresses-Coverity: ("Unused value") Fixes: 2be25cac8402 ("bcma: add constants for PCI and use them") Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin --- drivers/bcma/driver_pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index f499a469e66d..12b2cc9a3fbe 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -78,7 +78,7 @@ static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u16 device, u8 address) v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD); } - v = BCMA_CORE_PCI_MDIODATA_START; + v |= BCMA_CORE_PCI_MDIODATA_START; v |= BCMA_CORE_PCI_MDIODATA_READ; v |= BCMA_CORE_PCI_MDIODATA_TA; @@ -121,7 +121,7 @@ static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u16 device, v |= (address << BCMA_CORE_PCI_MDIODATA_REGADDR_SHF_OLD); } - v = BCMA_CORE_PCI_MDIODATA_START; + v |= BCMA_CORE_PCI_MDIODATA_START; v |= BCMA_CORE_PCI_MDIODATA_WRITE; v |= BCMA_CORE_PCI_MDIODATA_TA; v |= data; -- GitLab From c0d6177fda727f29889ad9bab6b9bb7e867d8fed Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 15 Aug 2019 12:58:46 +0100 Subject: [PATCH 0586/1055] iio: dac: ad5380: fix incorrect assignment to val [ Upstream commit b1e18768ef1214c0a8048327918a182cabe09f9d ] Currently the pointer val is being incorrectly incremented instead of the value pointed to by val. Fix this by adding in the missing * indirection operator. Addresses-Coverity: ("Unused value") Fixes: c03f2c536818 ("staging:iio:dac: Add AD5380 driver") Signed-off-by: Colin Ian King Reviewed-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin --- drivers/iio/dac/ad5380.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index 97d2c5111f43..8bf7fc626a9d 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -221,7 +221,7 @@ static int ad5380_read_raw(struct iio_dev *indio_dev, if (ret) return ret; *val >>= chan->scan_type.shift; - val -= (1 << chan->scan_type.realbits) / 2; + *val -= (1 << chan->scan_type.realbits) / 2; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 2 * st->vref; -- GitLab From 763ce5f99060cd589174f3394a83343c8e21f87b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 19 Aug 2019 09:41:39 +0200 Subject: [PATCH 0587/1055] ath9k: dynack: fix possible deadlock in ath_dynack_node_{de}init [ Upstream commit e1aa1a1db3b01c9890e82cf065cee99962ba1ed9 ] Fix following lockdep warning disabling bh in ath_dynack_node_init/ath_dynack_node_deinit [ 75.955878] -------------------------------- [ 75.955880] inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. [ 75.955884] swapper/0/0 [HC0[0]:SC1[3]:HE1:SE0] takes: [ 75.955888] 00000000792a7ee0 (&(&da->qlock)->rlock){+.?.}, at: ath_dynack_sample_ack_ts+0x4d/0xa0 [ath9k_hw] [ 75.955905] {SOFTIRQ-ON-W} state was registered at: [ 75.955912] lock_acquire+0x9a/0x160 [ 75.955917] _raw_spin_lock+0x2c/0x70 [ 75.955927] ath_dynack_node_init+0x2a/0x60 [ath9k_hw] [ 75.955934] ath9k_sta_state+0xec/0x160 [ath9k] [ 75.955976] drv_sta_state+0xb2/0x740 [mac80211] [ 75.956008] sta_info_insert_finish+0x21a/0x420 [mac80211] [ 75.956039] sta_info_insert_rcu+0x12b/0x2c0 [mac80211] [ 75.956069] sta_info_insert+0x7/0x70 [mac80211] [ 75.956093] ieee80211_prep_connection+0x42e/0x730 [mac80211] [ 75.956120] ieee80211_mgd_auth.cold+0xb9/0x15c [mac80211] [ 75.956152] cfg80211_mlme_auth+0x143/0x350 [cfg80211] [ 75.956169] nl80211_authenticate+0x25e/0x2b0 [cfg80211] [ 75.956172] genl_family_rcv_msg+0x198/0x400 [ 75.956174] genl_rcv_msg+0x42/0x90 [ 75.956176] netlink_rcv_skb+0x35/0xf0 [ 75.956178] genl_rcv+0x1f/0x30 [ 75.956180] netlink_unicast+0x154/0x200 [ 75.956182] netlink_sendmsg+0x1bf/0x3d0 [ 75.956186] ___sys_sendmsg+0x2c2/0x2f0 [ 75.956187] __sys_sendmsg+0x44/0x80 [ 75.956190] do_syscall_64+0x55/0x1a0 [ 75.956192] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 75.956194] irq event stamp: 2357092 [ 75.956196] hardirqs last enabled at (2357092): [] _raw_spin_unlock_irqrestore+0x3e/0x50 [ 75.956199] hardirqs last disabled at (2357091): [] _raw_spin_lock_irqsave+0x11/0x80 [ 75.956202] softirqs last enabled at (2357072): [] irq_enter+0x59/0x60 [ 75.956204] softirqs last disabled at (2357073): [] irq_exit+0xae/0xc0 [ 75.956206] other info that might help us debug this: [ 75.956207] Possible unsafe locking scenario: [ 75.956208] CPU0 [ 75.956209] ---- [ 75.956210] lock(&(&da->qlock)->rlock); [ 75.956213] [ 75.956214] lock(&(&da->qlock)->rlock); [ 75.956216] *** DEADLOCK *** [ 75.956217] 1 lock held by swapper/0/0: [ 75.956219] #0: 000000003bb5675c (&(&sc->sc_pcu_lock)->rlock){+.-.}, at: ath9k_tasklet+0x55/0x240 [ath9k] [ 75.956225] stack backtrace: [ 75.956228] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.3.0-rc1-wdn+ #13 [ 75.956229] Hardware name: Dell Inc. Studio XPS 1340/0K183D, BIOS A11 09/08/2009 [ 75.956231] Call Trace: [ 75.956233] [ 75.956236] dump_stack+0x67/0x90 [ 75.956239] mark_lock+0x4c1/0x640 [ 75.956242] ? check_usage_backwards+0x130/0x130 [ 75.956245] ? sched_clock_local+0x12/0x80 [ 75.956247] __lock_acquire+0x484/0x7a0 [ 75.956250] ? __lock_acquire+0x3b9/0x7a0 [ 75.956252] lock_acquire+0x9a/0x160 [ 75.956259] ? ath_dynack_sample_ack_ts+0x4d/0xa0 [ath9k_hw] [ 75.956262] _raw_spin_lock_bh+0x34/0x80 [ 75.956268] ? ath_dynack_sample_ack_ts+0x4d/0xa0 [ath9k_hw] [ 75.956275] ath_dynack_sample_ack_ts+0x4d/0xa0 [ath9k_hw] [ 75.956280] ath_rx_tasklet+0xd09/0xe90 [ath9k] [ 75.956286] ath9k_tasklet+0x102/0x240 [ath9k] [ 75.956288] tasklet_action_common.isra.0+0x6d/0x170 [ 75.956291] __do_softirq+0xcc/0x425 [ 75.956294] irq_exit+0xae/0xc0 [ 75.956296] do_IRQ+0x8a/0x110 [ 75.956298] common_interrupt+0xf/0xf [ 75.956300] [ 75.956303] RIP: 0010:cpuidle_enter_state+0xb2/0x400 [ 75.956308] RSP: 0018:ffffffff82203e70 EFLAGS: 00000202 ORIG_RAX: ffffffffffffffd7 [ 75.956310] RAX: ffffffff82219800 RBX: ffffffff822bd0a0 RCX: 0000000000000000 [ 75.956312] RDX: 0000000000000046 RSI: 0000000000000006 RDI: ffffffff82219800 [ 75.956314] RBP: ffff888155a01c00 R08: 00000011af51aabe R09: 0000000000000000 [ 75.956315] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000002 [ 75.956317] R13: 00000011af51aabe R14: 0000000000000003 R15: ffffffff82219800 [ 75.956321] cpuidle_enter+0x24/0x40 [ 75.956323] do_idle+0x1ac/0x220 [ 75.956326] cpu_startup_entry+0x14/0x20 [ 75.956329] start_kernel+0x482/0x489 [ 75.956332] secondary_startup_64+0xa4/0xb0 Fixes: c774d57fd47c ("ath9k: add dynamic ACK timeout estimation") Signed-off-by: Lorenzo Bianconi Tested-by: Koen Vandeputte Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath9k/dynack.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/dynack.c b/drivers/net/wireless/ath/ath9k/dynack.c index 6e236a485431..71b4888b30e7 100644 --- a/drivers/net/wireless/ath/ath9k/dynack.c +++ b/drivers/net/wireless/ath/ath9k/dynack.c @@ -300,9 +300,9 @@ void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an) an->ackto = ackto; - spin_lock(&da->qlock); + spin_lock_bh(&da->qlock); list_add_tail(&an->list, &da->nodes); - spin_unlock(&da->qlock); + spin_unlock_bh(&da->qlock); } EXPORT_SYMBOL(ath_dynack_node_init); @@ -316,9 +316,9 @@ void ath_dynack_node_deinit(struct ath_hw *ah, struct ath_node *an) { struct ath_dynack *da = &ah->dynack; - spin_lock(&da->qlock); + spin_lock_bh(&da->qlock); list_del(&an->list); - spin_unlock(&da->qlock); + spin_unlock_bh(&da->qlock); } EXPORT_SYMBOL(ath_dynack_node_deinit); -- GitLab From 36803fe500521550b631de05717d5ce22a5a62a2 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Mon, 29 Jul 2019 12:52:15 -0700 Subject: [PATCH 0588/1055] tty: serial: fsl_lpuart: Use appropriate lpuart32_* I/O funcs [ Upstream commit 1da17d7cf8e2c4b60163d54300f72c02f510327c ] When dealing with 32-bit variant of LPUART IP block appropriate I/O helpers have to be used to properly deal with endianness differences. Change all of the offending code to do that. Fixes: a5fa2660d787 ("tty/serial/fsl_lpuart: Add CONSOLE_POLL support for lpuart32.") Signed-off-by: Andrey Smirnov Cc: Stefan Agner Cc: Bhuvanchandra DV Cc: Chris Healy Cc: Cory Tusar Cc: Lucas Stach Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: linux-imx@nxp.com Cc: linux-serial@vger.kernel.org Cc: linux-kernel@vger.kernel.org Link: https://lore.kernel.org/r/20190729195226.8862-14-andrew.smirnov@gmail.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/fsl_lpuart.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index fb2dcb3f8591..16422987ab0f 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -532,26 +532,26 @@ static int lpuart32_poll_init(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); /* Disable Rx & Tx */ - writel(0, sport->port.membase + UARTCTRL); + lpuart32_write(&sport->port, UARTCTRL, 0); - temp = readl(sport->port.membase + UARTFIFO); + temp = lpuart32_read(&sport->port, UARTFIFO); /* Enable Rx and Tx FIFO */ - writel(temp | UARTFIFO_RXFE | UARTFIFO_TXFE, - sport->port.membase + UARTFIFO); + lpuart32_write(&sport->port, UARTFIFO, + temp | UARTFIFO_RXFE | UARTFIFO_TXFE); /* flush Tx and Rx FIFO */ - writel(UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, - sport->port.membase + UARTFIFO); + lpuart32_write(&sport->port, UARTFIFO, + UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH); /* explicitly clear RDRF */ - if (readl(sport->port.membase + UARTSTAT) & UARTSTAT_RDRF) { - readl(sport->port.membase + UARTDATA); - writel(UARTFIFO_RXUF, sport->port.membase + UARTFIFO); + if (lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_RDRF) { + lpuart32_read(&sport->port, UARTDATA); + lpuart32_write(&sport->port, UARTFIFO, UARTFIFO_RXUF); } /* Enable Rx and Tx */ - writel(UARTCTRL_RE | UARTCTRL_TE, sport->port.membase + UARTCTRL); + lpuart32_write(&sport->port, UARTCTRL, UARTCTRL_RE | UARTCTRL_TE); spin_unlock_irqrestore(&sport->port.lock, flags); return 0; @@ -559,18 +559,18 @@ static int lpuart32_poll_init(struct uart_port *port) static void lpuart32_poll_put_char(struct uart_port *port, unsigned char c) { - while (!(readl(port->membase + UARTSTAT) & UARTSTAT_TDRE)) + while (!(lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE)) barrier(); - writel(c, port->membase + UARTDATA); + lpuart32_write(port, UARTDATA, c); } static int lpuart32_poll_get_char(struct uart_port *port) { - if (!(readl(port->membase + UARTSTAT) & UARTSTAT_RDRF)) + if (!(lpuart32_read(port, UARTSTAT) & UARTSTAT_RDRF)) return NO_POLL_CHAR; - return readl(port->membase + UARTDATA); + return lpuart32_read(port, UARTDATA); } #endif -- GitLab From 8b71eb46f20c8d6f235d71ca21db58c4ed5cf503 Mon Sep 17 00:00:00 2001 From: Mao Wenan Date: Thu, 5 Sep 2019 09:57:12 +0800 Subject: [PATCH 0589/1055] net: sonic: return NETDEV_TX_OK if failed to map buffer [ Upstream commit 6e1cdedcf0362fed3aedfe051d46bd7ee2a85fe1 ] NETDEV_TX_BUSY really should only be used by drivers that call netif_tx_stop_queue() at the wrong moment. If dma_map_single() is failed to map tx DMA buffer, it might trigger an infinite loop. This patch use NETDEV_TX_OK instead of NETDEV_TX_BUSY, and change printk to pr_err_ratelimited. Fixes: d9fb9f384292 ("*sonic/natsemi/ns83829: Move the National Semi-conductor drivers") Signed-off-by: Mao Wenan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/natsemi/sonic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c index 23821540ab07..11f472fd5d47 100644 --- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -221,9 +221,9 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE); if (!laddr) { - printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name); + pr_err_ratelimited("%s: failed to map tx DMA buffer.\n", dev->name); dev_kfree_skb(skb); - return NETDEV_TX_BUSY; + return NETDEV_TX_OK; } sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */ -- GitLab From caa4dd3ae27bc135274c39ea5de64e521875e848 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan Date: Tue, 27 Aug 2019 14:13:40 -0700 Subject: [PATCH 0590/1055] scsi: fnic: fix msix interrupt allocation [ Upstream commit 3ec24fb4c035e9cbb2f02a48640a09aa913442a2 ] pci_alloc_irq_vectors() returns number of vectors allocated. Fix the check for error condition. Fixes: cca678dfbad49 ("scsi: fnic: switch to pci_alloc_irq_vectors") Link: https://lore.kernel.org/r/20190827211340.1095-1-gvaradar@cisco.com Signed-off-by: Govindarajulu Varadarajan Acked-by: Satish Kharat Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/fnic/fnic_isr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/fnic/fnic_isr.c b/drivers/scsi/fnic/fnic_isr.c index 4e3a50202e8c..d28088218c36 100644 --- a/drivers/scsi/fnic/fnic_isr.c +++ b/drivers/scsi/fnic/fnic_isr.c @@ -254,7 +254,7 @@ int fnic_set_intr_mode(struct fnic *fnic) int vecs = n + m + o + 1; if (pci_alloc_irq_vectors(fnic->pdev, vecs, vecs, - PCI_IRQ_MSIX) < 0) { + PCI_IRQ_MSIX) == vecs) { fnic->rq_count = n; fnic->raw_wq_count = m; fnic->wq_copy_count = o; @@ -280,7 +280,7 @@ int fnic_set_intr_mode(struct fnic *fnic) fnic->wq_copy_count >= 1 && fnic->cq_count >= 3 && fnic->intr_count >= 1 && - pci_alloc_irq_vectors(fnic->pdev, 1, 1, PCI_IRQ_MSI) < 0) { + pci_alloc_irq_vectors(fnic->pdev, 1, 1, PCI_IRQ_MSI) == 1) { fnic->rq_count = 1; fnic->raw_wq_count = 1; fnic->wq_copy_count = 1; -- GitLab From 0d479ec44e1c4257e69b400bf9ba429105d9e7aa Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 4 Jul 2019 16:24:09 +0100 Subject: [PATCH 0591/1055] Btrfs: fix hang when loading existing inode cache off disk [ Upstream commit 7764d56baa844d7f6206394f21a0e8c1f303c476 ] If we are able to load an existing inode cache off disk, we set the state of the cache to BTRFS_CACHE_FINISHED, but we don't wake up any one waiting for the cache to be available. This means that anyone waiting for the cache to be available, waiting on the condition that either its state is BTRFS_CACHE_FINISHED or its available free space is greather than zero, can hang forever. This could be observed running fstests with MOUNT_OPTIONS="-o inode_cache", in particular test case generic/161 triggered it very frequently for me, producing a trace like the following: [63795.739712] BTRFS info (device sdc): enabling inode map caching [63795.739714] BTRFS info (device sdc): disk space caching is enabled [63795.739716] BTRFS info (device sdc): has skinny extents [64036.653886] INFO: task btrfs-transacti:3917 blocked for more than 120 seconds. [64036.654079] Not tainted 5.2.0-rc4-btrfs-next-50 #1 [64036.654143] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [64036.654232] btrfs-transacti D 0 3917 2 0x80004000 [64036.654239] Call Trace: [64036.654258] ? __schedule+0x3ae/0x7b0 [64036.654271] schedule+0x3a/0xb0 [64036.654325] btrfs_commit_transaction+0x978/0xae0 [btrfs] [64036.654339] ? remove_wait_queue+0x60/0x60 [64036.654395] transaction_kthread+0x146/0x180 [btrfs] [64036.654450] ? btrfs_cleanup_transaction+0x620/0x620 [btrfs] [64036.654456] kthread+0x103/0x140 [64036.654464] ? kthread_create_worker_on_cpu+0x70/0x70 [64036.654476] ret_from_fork+0x3a/0x50 [64036.654504] INFO: task xfs_io:3919 blocked for more than 120 seconds. [64036.654568] Not tainted 5.2.0-rc4-btrfs-next-50 #1 [64036.654617] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [64036.654685] xfs_io D 0 3919 3633 0x00000000 [64036.654691] Call Trace: [64036.654703] ? __schedule+0x3ae/0x7b0 [64036.654716] schedule+0x3a/0xb0 [64036.654756] btrfs_find_free_ino+0xa9/0x120 [btrfs] [64036.654764] ? remove_wait_queue+0x60/0x60 [64036.654809] btrfs_create+0x72/0x1f0 [btrfs] [64036.654822] lookup_open+0x6bc/0x790 [64036.654849] path_openat+0x3bc/0xc00 [64036.654854] ? __lock_acquire+0x331/0x1cb0 [64036.654869] do_filp_open+0x99/0x110 [64036.654884] ? __alloc_fd+0xee/0x200 [64036.654895] ? do_raw_spin_unlock+0x49/0xc0 [64036.654909] ? do_sys_open+0x132/0x220 [64036.654913] do_sys_open+0x132/0x220 [64036.654926] do_syscall_64+0x60/0x1d0 [64036.654933] entry_SYSCALL_64_after_hwframe+0x49/0xbe Fix this by adding a wake_up() call right after setting the cache state to BTRFS_CACHE_FINISHED, at start_caching(), when we are able to load the cache from disk. Fixes: 82d5902d9c681b ("Btrfs: Support reading/writing on disk free ino cache") Reviewed-by: Nikolay Borisov Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/inode-map.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index d02019747d00..7dc2923655d9 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c @@ -159,6 +159,7 @@ static void start_caching(struct btrfs_root *root) spin_lock(&root->ino_cache_lock); root->ino_cache_state = BTRFS_CACHE_FINISHED; spin_unlock(&root->ino_cache_lock); + wake_up(&root->ino_cache_wait); return; } -- GitLab From 2162f5aae4a7feb883739ca92054715f8151bd7a Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 4 Jul 2019 16:24:32 +0100 Subject: [PATCH 0592/1055] Btrfs: fix inode cache waiters hanging on failure to start caching thread [ Upstream commit a68ebe0790fc88b4314d17984a2cf99ce2361901 ] If we fail to start the inode caching thread, we print an error message and disable the inode cache, however we never wake up any waiters, so they hang forever waiting for the caching to finish. Fix this by waking them up and have them fallback to a call to btrfs_find_free_objectid(). Fixes: e60efa84252c05 ("Btrfs: avoid triggering bug_on() when we fail to start inode caching task") Reviewed-by: Nikolay Borisov Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/inode-map.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index 7dc2923655d9..b1c3a4ec76c8 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c @@ -26,6 +26,19 @@ #include "inode-map.h" #include "transaction.h" +static void fail_caching_thread(struct btrfs_root *root) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + + btrfs_warn(fs_info, "failed to start inode caching task"); + btrfs_clear_pending_and_info(fs_info, INODE_MAP_CACHE, + "disabling inode map caching"); + spin_lock(&root->ino_cache_lock); + root->ino_cache_state = BTRFS_CACHE_ERROR; + spin_unlock(&root->ino_cache_lock); + wake_up(&root->ino_cache_wait); +} + static int caching_kthread(void *data) { struct btrfs_root *root = data; @@ -178,11 +191,8 @@ static void start_caching(struct btrfs_root *root) tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu", root->root_key.objectid); - if (IS_ERR(tsk)) { - btrfs_warn(fs_info, "failed to start inode caching task"); - btrfs_clear_pending_and_info(fs_info, INODE_MAP_CACHE, - "disabling inode map caching"); - } + if (IS_ERR(tsk)) + fail_caching_thread(root); } int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid) @@ -200,11 +210,14 @@ int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid) wait_event(root->ino_cache_wait, root->ino_cache_state == BTRFS_CACHE_FINISHED || + root->ino_cache_state == BTRFS_CACHE_ERROR || root->free_ino_ctl->free_space > 0); if (root->ino_cache_state == BTRFS_CACHE_FINISHED && root->free_ino_ctl->free_space == 0) return -ENOSPC; + else if (root->ino_cache_state == BTRFS_CACHE_ERROR) + return btrfs_find_free_objectid(root, objectid); else goto again; } -- GitLab From 510cd98350463b841fdc01065eac4cec180ba9d5 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 4 Jul 2019 16:24:44 +0100 Subject: [PATCH 0593/1055] Btrfs: fix inode cache waiters hanging on path allocation failure [ Upstream commit 9d123a35d7e97bb2139747b16127c9b22b6a593e ] If the caching thread fails to allocate a path, it returns without waking up any cache waiters, leaving them hang forever. Fix this by following the same approach as when we fail to start the caching thread: print an error message, disable inode caching and make the wakers fallback to non-caching mode behaviour (calling btrfs_find_free_objectid()). Fixes: 581bb050941b4f ("Btrfs: Cache free inode numbers in memory") Reviewed-by: Nikolay Borisov Signed-off-by: Filipe Manana Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/inode-map.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index b1c3a4ec76c8..2ae32451fb5b 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c @@ -55,8 +55,10 @@ static int caching_kthread(void *data) return 0; path = btrfs_alloc_path(); - if (!path) + if (!path) { + fail_caching_thread(root); return -ENOMEM; + } /* Since the commit root is read-only, we can safely skip locking. */ path->skip_locking = 1; -- GitLab From a7a67b4e8e8d68d6301d233645a3bfbfba40bc35 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Thu, 15 Aug 2019 14:04:02 -0700 Subject: [PATCH 0594/1055] btrfs: use correct count in btrfs_file_write_iter() [ Upstream commit c09767a8960ca0500fb636bf73686723337debf4 ] generic_write_checks() may modify iov_iter_count(), so we must get the count after the call, not before. Using the wrong one has a couple of consequences: 1. We check a longer range in check_can_nocow() for nowait than we're actually writing. 2. We create extra hole extent maps in btrfs_cont_expand(). As far as I can tell, this is harmless, but I might be missing something. These issues are pretty minor, but let's fix it before something more important trips on it. Fixes: edf064e7c6fe ("btrfs: nowait aio support") Reviewed-by: Josef Bacik Signed-off-by: Omar Sandoval Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/btrfs/file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 97be32da857a..c68ce3412dc1 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1882,7 +1882,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, bool sync = (file->f_flags & O_DSYNC) || IS_SYNC(file->f_mapping->host); ssize_t err; loff_t pos; - size_t count = iov_iter_count(from); + size_t count; loff_t oldsize; int clean_page = 0; @@ -1904,6 +1904,7 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, } pos = iocb->ki_pos; + count = iov_iter_count(from); if (iocb->ki_flags & IOCB_NOWAIT) { /* * We will allocate space in case nodatacow is not set, -- GitLab From 22437abfe204d1797245896a701bc2dc5a90c7ca Mon Sep 17 00:00:00 2001 From: Firo Yang Date: Thu, 8 Aug 2019 04:03:49 +0000 Subject: [PATCH 0595/1055] ixgbe: sync the first fragment unconditionally [ Upstream commit e7ba676c6188d394a0133fc4b9bcd7ee50d54b7f ] In Xen environment, if Xen-swiotlb is enabled, ixgbe driver could possibly allocate a page, DMA memory buffer, for the first fragment which is not suitable for Xen-swiotlb to do DMA operations. Xen-swiotlb have to internally allocate another page for doing DMA operations. This mechanism requires syncing the data from the internal page to the page which ixgbe sends to upper network stack. However, since commit f3213d932173 ("ixgbe: Update driver to make use of DMA attributes in Rx path"), the unmap operation is performed with DMA_ATTR_SKIP_CPU_SYNC. As a result, the sync is not performed. Since the sync isn't performed, the upper network stack could receive a incomplete network packet. By incomplete, it means the linear data on the first fragment(between skb->head and skb->end) is invalid. So we have to copy the data from the internal xen-swiotlb page to the page which ixgbe sends to upper network stack through the sync operation. More details from Alexander Duyck: Specifically since we are mapping the frame with DMA_ATTR_SKIP_CPU_SYNC we have to unmap with that as well. As a result a sync is not performed on an unmap and must be done manually as we skipped it for the first frag. As such we need to always sync before possibly performing a page unmap operation. Fixes: f3213d932173 ("ixgbe: Update driver to make use of DMA attributes in Rx path") Signed-off-by: Firo Yang Reviewed-by: Alexander Duyck Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 0edfd199937d..e4c1e6345edd 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1871,13 +1871,7 @@ static void ixgbe_pull_tail(struct ixgbe_ring *rx_ring, static void ixgbe_dma_sync_frag(struct ixgbe_ring *rx_ring, struct sk_buff *skb) { - /* if the page was released unmap it, else just sync our portion */ - if (unlikely(IXGBE_CB(skb)->page_released)) { - dma_unmap_page_attrs(rx_ring->dev, IXGBE_CB(skb)->dma, - ixgbe_rx_pg_size(rx_ring), - DMA_FROM_DEVICE, - IXGBE_RX_DMA_ATTR); - } else if (ring_uses_build_skb(rx_ring)) { + if (ring_uses_build_skb(rx_ring)) { unsigned long offset = (unsigned long)(skb->data) & ~PAGE_MASK; dma_sync_single_range_for_cpu(rx_ring->dev, @@ -1894,6 +1888,14 @@ static void ixgbe_dma_sync_frag(struct ixgbe_ring *rx_ring, skb_frag_size(frag), DMA_FROM_DEVICE); } + + /* If the page was released, just unmap it. */ + if (unlikely(IXGBE_CB(skb)->page_released)) { + dma_unmap_page_attrs(rx_ring->dev, IXGBE_CB(skb)->dma, + ixgbe_rx_pg_size(rx_ring), + DMA_FROM_DEVICE, + IXGBE_RX_DMA_ATTR); + } } /** -- GitLab From 2c565cc955e6b5f07b97ab074bfbbc37b7682a35 Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Thu, 5 Sep 2019 01:45:54 +0000 Subject: [PATCH 0596/1055] hwmon: (shtc1) fix shtc1 and shtw1 id mask [ Upstream commit fdc7d8e829ec755c5cfb2f5a8d8c0cdfb664f895 ] Fix an error in the bitmaskfor the shtc1 and shtw1 bitmask used to retrieve the chip ID from the ID register. See section 5.7 of the shtw1 or shtc1 datasheet for details. Fixes: 1a539d372edd9832444e7a3daa710c444c014dc9 ("hwmon: add support for Sensirion SHTC1 sensor") Signed-off-by: Dan Robertson Link: https://lore.kernel.org/r/20190905014554.21658-3-dan@dlrobertson.com [groeck: Reordered to be first in series and adjusted accordingly] Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin --- drivers/hwmon/shtc1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/shtc1.c b/drivers/hwmon/shtc1.c index decd7df995ab..2a18539591ea 100644 --- a/drivers/hwmon/shtc1.c +++ b/drivers/hwmon/shtc1.c @@ -38,7 +38,7 @@ static const unsigned char shtc1_cmd_read_id_reg[] = { 0xef, 0xc8 }; /* constants for reading the ID register */ #define SHTC1_ID 0x07 -#define SHTC1_ID_REG_MASK 0x1f +#define SHTC1_ID_REG_MASK 0x3f /* delays for non-blocking i2c commands, both in us */ #define SHTC1_NONBLOCKING_WAIT_TIME_HPM 14400 -- GitLab From 742ca82d31dfaac9bcdf552ca9b555658687c5a0 Mon Sep 17 00:00:00 2001 From: Mao Wenan Date: Wed, 11 Sep 2019 09:36:23 +0800 Subject: [PATCH 0597/1055] net: sonic: replace dev_kfree_skb in sonic_send_packet [ Upstream commit 49f6c90bf6805948b597eabb499e500a47cf24be ] sonic_send_packet will be processed in irq or non-irq context, so it would better use dev_kfree_skb_any instead of dev_kfree_skb. Fixes: d9fb9f384292 ("*sonic/natsemi/ns83829: Move the National Semi-conductor drivers") Signed-off-by: Mao Wenan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/natsemi/sonic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c index 11f472fd5d47..a051dddcbd76 100644 --- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -222,7 +222,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE); if (!laddr) { pr_err_ratelimited("%s: failed to map tx DMA buffer.\n", dev->name); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } -- GitLab From 5c09015c8bcb8599e711bb3db13aa1fc2d0ecdda Mon Sep 17 00:00:00 2001 From: Li Jin Date: Thu, 29 Aug 2019 10:22:27 +0530 Subject: [PATCH 0598/1055] pinctrl: iproc-gpio: Fix incorrect pinconf configurations [ Upstream commit 398a1f50e3c731586182fd52b834103b0aa2f826 ] Fix drive strength for AON/CRMU controller; fix pull-up/down setting for CCM/CDRU controller. Fixes: 616043d58a89 ("pinctrl: Rename gpio driver from cygnus to iproc") Signed-off-by: Li Jin Link: https://lore.kernel.org/r/1567054348-19685-2-git-send-email-srinath.mannam@broadcom.com Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin --- drivers/pinctrl/bcm/pinctrl-iproc-gpio.c | 96 +++++++++++++++++++----- 1 file changed, 77 insertions(+), 19 deletions(-) diff --git a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c index 85a8c97d9dfe..5fe419e468ec 100644 --- a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c +++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c @@ -54,8 +54,12 @@ /* drive strength control for ASIU GPIO */ #define IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58 -/* drive strength control for CCM/CRMU (AON) GPIO */ -#define IPROC_GPIO_DRV0_CTRL_OFFSET 0x00 +/* pinconf for CCM GPIO */ +#define IPROC_GPIO_PULL_DN_OFFSET 0x10 +#define IPROC_GPIO_PULL_UP_OFFSET 0x14 + +/* pinconf for CRMU(aon) GPIO and CCM GPIO*/ +#define IPROC_GPIO_DRV_CTRL_OFFSET 0x00 #define GPIO_BANK_SIZE 0x200 #define NGPIOS_PER_BANK 32 @@ -76,6 +80,12 @@ enum iproc_pinconf_param { IPROC_PINCON_MAX, }; +enum iproc_pinconf_ctrl_type { + IOCTRL_TYPE_AON = 1, + IOCTRL_TYPE_CDRU, + IOCTRL_TYPE_INVALID, +}; + /* * Iproc GPIO core * @@ -100,6 +110,7 @@ struct iproc_gpio { void __iomem *base; void __iomem *io_ctrl; + enum iproc_pinconf_ctrl_type io_ctrl_type; raw_spinlock_t lock; @@ -461,20 +472,44 @@ static const struct pinctrl_ops iproc_pctrl_ops = { static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio, bool disable, bool pull_up) { + void __iomem *base; unsigned long flags; + unsigned int shift; + u32 val_1, val_2; raw_spin_lock_irqsave(&chip->lock, flags); - - if (disable) { - iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, false); + if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) { + base = chip->io_ctrl; + shift = IPROC_GPIO_SHIFT(gpio); + + val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET); + val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET); + if (disable) { + /* no pull-up or pull-down */ + val_1 &= ~BIT(shift); + val_2 &= ~BIT(shift); + } else if (pull_up) { + val_1 |= BIT(shift); + val_2 &= ~BIT(shift); + } else { + val_1 &= ~BIT(shift); + val_2 |= BIT(shift); + } + writel(val_1, base + IPROC_GPIO_PULL_UP_OFFSET); + writel(val_2, base + IPROC_GPIO_PULL_DN_OFFSET); } else { - iproc_set_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio, - pull_up); - iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, true); + if (disable) { + iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, + false); + } else { + iproc_set_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio, + pull_up); + iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, + true); + } } raw_spin_unlock_irqrestore(&chip->lock, flags); - dev_dbg(chip->dev, "gpio:%u set pullup:%d\n", gpio, pull_up); return 0; @@ -483,14 +518,35 @@ static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio, static void iproc_gpio_get_pull(struct iproc_gpio *chip, unsigned gpio, bool *disable, bool *pull_up) { + void __iomem *base; unsigned long flags; + unsigned int shift; + u32 val_1, val_2; raw_spin_lock_irqsave(&chip->lock, flags); - *disable = !iproc_get_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio); - *pull_up = iproc_get_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio); + if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) { + base = chip->io_ctrl; + shift = IPROC_GPIO_SHIFT(gpio); + + val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET) & BIT(shift); + val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET) & BIT(shift); + + *pull_up = val_1 ? true : false; + *disable = (val_1 | val_2) ? false : true; + + } else { + *disable = !iproc_get_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio); + *pull_up = iproc_get_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio); + } raw_spin_unlock_irqrestore(&chip->lock, flags); } +#define DRV_STRENGTH_OFFSET(gpio, bit, type) ((type) == IOCTRL_TYPE_AON ? \ + ((2 - (bit)) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \ + ((type) == IOCTRL_TYPE_CDRU) ? \ + ((bit) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \ + ((bit) * 4 + IPROC_GPIO_REG(gpio, IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET))) + static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio, unsigned strength) { @@ -505,11 +561,8 @@ static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio, if (chip->io_ctrl) { base = chip->io_ctrl; - offset = IPROC_GPIO_DRV0_CTRL_OFFSET; } else { base = chip->base; - offset = IPROC_GPIO_REG(gpio, - IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET); } shift = IPROC_GPIO_SHIFT(gpio); @@ -520,11 +573,11 @@ static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio, raw_spin_lock_irqsave(&chip->lock, flags); strength = (strength / 2) - 1; for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) { + offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type); val = readl(base + offset); val &= ~BIT(shift); val |= ((strength >> i) & 0x1) << shift; writel(val, base + offset); - offset += 4; } raw_spin_unlock_irqrestore(&chip->lock, flags); @@ -541,11 +594,8 @@ static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio, if (chip->io_ctrl) { base = chip->io_ctrl; - offset = IPROC_GPIO_DRV0_CTRL_OFFSET; } else { base = chip->base; - offset = IPROC_GPIO_REG(gpio, - IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET); } shift = IPROC_GPIO_SHIFT(gpio); @@ -553,10 +603,10 @@ static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio, raw_spin_lock_irqsave(&chip->lock, flags); *strength = 0; for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) { + offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type); val = readl(base + offset) & BIT(shift); val >>= shift; *strength += (val << i); - offset += 4; } /* convert to mA */ @@ -734,6 +784,7 @@ static int iproc_gpio_probe(struct platform_device *pdev) u32 ngpios, pinconf_disable_mask = 0; int irq, ret; bool no_pinconf = false; + enum iproc_pinconf_ctrl_type io_ctrl_type = IOCTRL_TYPE_INVALID; /* NSP does not support drive strength config */ if (of_device_is_compatible(dev->of_node, "brcm,iproc-nsp-gpio")) @@ -764,8 +815,15 @@ static int iproc_gpio_probe(struct platform_device *pdev) dev_err(dev, "unable to map I/O memory\n"); return PTR_ERR(chip->io_ctrl); } + if (of_device_is_compatible(dev->of_node, + "brcm,cygnus-ccm-gpio")) + io_ctrl_type = IOCTRL_TYPE_CDRU; + else + io_ctrl_type = IOCTRL_TYPE_AON; } + chip->io_ctrl_type = io_ctrl_type; + if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) { dev_err(&pdev->dev, "missing ngpios DT property\n"); return -ENODEV; -- GitLab From a4f56e03bf2a69548cedaeaa46a691da520cc7d3 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Tue, 10 Sep 2019 16:46:17 +0300 Subject: [PATCH 0599/1055] ath10k: adjust skb length in ath10k_sdio_mbox_rx_packet [ Upstream commit b7139960832eb56fa15d390a4b5c8c5739bd0d1a ] When the FW bundles multiple packets, pkt->act_len may be incorrect as it refers to the first packet only (however, the FW will only bundle packets that fit into the same pkt->alloc_len). Before this patch, the skb length would be set (incorrectly) to pkt->act_len in ath10k_sdio_mbox_rx_packet, and then later manually adjusted in ath10k_sdio_mbox_rx_process_packet. The first problem is that ath10k_sdio_mbox_rx_process_packet does not use proper skb_put commands to adjust the length (it directly changes skb->len), so we end up with a mismatch between skb->head + skb->tail and skb->data + skb->len. This is quite serious, and causes corruptions in the TCP stack, as the stack tries to coalesce packets, and relies on skb->tail being correct (that is, skb_tail_pointer must point to the first byte_after_ the data). Instead of re-adjusting the size in ath10k_sdio_mbox_rx_process_packet, this moves the code to ath10k_sdio_mbox_rx_packet, and also add a bounds check, as skb_put would crash the kernel if not enough space is available. Tested with QCA6174 SDIO with firmware WLAN.RMH.4.4.1-00007-QCARMSWP-1. Fixes: 8530b4e7b22bc3b ("ath10k: sdio: set skb len for all rx packets") Signed-off-by: Nicolas Boichat Signed-off-by: Wen Gong Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin --- drivers/net/wireless/ath/ath10k/sdio.c | 29 +++++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 0a1248ebccf5..f49b21b137c1 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -392,16 +392,11 @@ static int ath10k_sdio_mbox_rx_process_packet(struct ath10k *ar, struct ath10k_htc_hdr *htc_hdr = (struct ath10k_htc_hdr *)skb->data; bool trailer_present = htc_hdr->flags & ATH10K_HTC_FLAG_TRAILER_PRESENT; enum ath10k_htc_ep_id eid; - u16 payload_len; u8 *trailer; int ret; - payload_len = le16_to_cpu(htc_hdr->len); - skb->len = payload_len + sizeof(struct ath10k_htc_hdr); - if (trailer_present) { - trailer = skb->data + sizeof(*htc_hdr) + - payload_len - htc_hdr->trailer_len; + trailer = skb->data + skb->len - htc_hdr->trailer_len; eid = pipe_id_to_eid(htc_hdr->eid); @@ -635,13 +630,31 @@ static int ath10k_sdio_mbox_rx_packet(struct ath10k *ar, { struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); struct sk_buff *skb = pkt->skb; + struct ath10k_htc_hdr *htc_hdr; int ret; ret = ath10k_sdio_readsb(ar, ar_sdio->mbox_info.htc_addr, skb->data, pkt->alloc_len); + if (ret) + goto out; + + /* Update actual length. The original length may be incorrect, + * as the FW will bundle multiple packets as long as their sizes + * fit within the same aligned length (pkt->alloc_len). + */ + htc_hdr = (struct ath10k_htc_hdr *)skb->data; + pkt->act_len = le16_to_cpu(htc_hdr->len) + sizeof(*htc_hdr); + if (pkt->act_len > pkt->alloc_len) { + ath10k_warn(ar, "rx packet too large (%zu > %zu)\n", + pkt->act_len, pkt->alloc_len); + ret = -EMSGSIZE; + goto out; + } + + skb_put(skb, pkt->act_len); + +out: pkt->status = ret; - if (!ret) - skb_put(skb, pkt->act_len); return ret; } -- GitLab From 7f746a04e45c0b7baa0facd3ebba1b02693e33f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Bugge?= Date: Mon, 2 Sep 2019 11:27:31 +0200 Subject: [PATCH 0600/1055] RDMA/cma: Fix false error message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit a6e4d254c19b541a58caced322111084b27a7788 ] In addr_handler(), assuming status == 0 and the device already has been acquired (id_priv->cma_dev != NULL), we get the following incorrect "error" message: RDMA CM: ADDR_ERROR: failed to resolve IP. status 0 Fixes: 498683c6a7ee ("IB/cma: Add debug messages to error flows") Link: https://lore.kernel.org/r/20190902092731.1055757-1-haakon.bugge@oracle.com Signed-off-by: Håkon Bugge Reviewed-by: Jason Gunthorpe Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/core/cma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index fc4630e4acdd..1614f6f3677c 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2789,7 +2789,7 @@ static void addr_handler(int status, struct sockaddr *src_addr, if (status) pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to acquire device. status %d\n", status); - } else { + } else if (status) { pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to resolve IP. status %d\n", status); } -- GitLab From 8bfb051a68c2b0f08ac685296993574e5861bd9b Mon Sep 17 00:00:00 2001 From: Gerd Rausch Date: Thu, 12 Sep 2019 13:49:41 -0700 Subject: [PATCH 0601/1055] net/rds: Fix 'ib_evt_handler_call' element in 'rds_ib_stat_names' [ Upstream commit 05a82481a3024b94db00b8c816bb3d526b5209e0 ] All entries in 'rds_ib_stat_names' are stringified versions of the corresponding "struct rds_ib_statistics" element without the "s_"-prefix. Fix entry 'ib_evt_handler_call' to do the same. Fixes: f4f943c958a2 ("RDS: IB: ack more receive completions to improve performance") Signed-off-by: Gerd Rausch Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/rds/ib_stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rds/ib_stats.c b/net/rds/ib_stats.c index 9252ad126335..ac46d8961b61 100644 --- a/net/rds/ib_stats.c +++ b/net/rds/ib_stats.c @@ -42,7 +42,7 @@ DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_ib_statistics, rds_ib_stats); static const char *const rds_ib_stat_names[] = { "ib_connect_raced", "ib_listen_closed_stale", - "s_ib_evt_handler_call", + "ib_evt_handler_call", "ib_tasklet_call", "ib_tx_cq_event", "ib_tx_ring_full", -- GitLab From 91586b4d9cae8fd12c6e6ae1b1c2c342c88cc95d Mon Sep 17 00:00:00 2001 From: Filippo Sironi Date: Tue, 10 Sep 2019 19:49:21 +0200 Subject: [PATCH 0602/1055] iommu/amd: Wait for completion of IOTLB flush in attach_device [ Upstream commit 0b15e02f0cc4fb34a9160de7ba6db3a4013dc1b7 ] To make sure the domain tlb flush completes before the function returns, explicitly wait for its completion. Signed-off-by: Filippo Sironi Fixes: 42a49f965a8d ("amd-iommu: flush domain tlb when attaching a new device") [joro: Added commit message and fixes tag] Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin --- drivers/iommu/amd_iommu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index d09c24825734..778f167be2d3 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -2160,6 +2160,8 @@ static int attach_device(struct device *dev, */ domain_flush_tlb_pde(domain); + domain_flush_complete(domain); + return ret; } -- GitLab From 39479c6c4695855c5d09fc2290723c8f00098110 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Sep 2019 13:54:30 +0300 Subject: [PATCH 0603/1055] net: aquantia: Fix aq_vec_isr_legacy() return value [ Upstream commit 31aefe14bc9f56566041303d733fda511d3a1c3e ] The irqreturn_t type is an enum or an unsigned int in GCC. That creates to problems because it can't detect if the self->aq_hw_ops->hw_irq_read() call fails and at the end the function always returns IRQ_HANDLED. drivers/net/ethernet/aquantia/atlantic/aq_vec.c:316 aq_vec_isr_legacy() warn: unsigned 'err' is never less than zero. drivers/net/ethernet/aquantia/atlantic/aq_vec.c:329 aq_vec_isr_legacy() warn: always true condition '(err >= 0) => (0-u32max >= 0)' Fixes: 970a2e9864b0 ("net: ethernet: aquantia: Vector operations") Signed-off-by: Dan Carpenter Reviewed-by: Igor Russkikh Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/aquantia/atlantic/aq_vec.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c index 5fecc9a099ef..bb2894a333f2 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c @@ -310,15 +310,13 @@ irqreturn_t aq_vec_isr_legacy(int irq, void *private) { struct aq_vec_s *self = private; u64 irq_mask = 0U; - irqreturn_t err = 0; + int err; - if (!self) { - err = -EINVAL; - goto err_exit; - } + if (!self) + return IRQ_NONE; err = self->aq_hw_ops->hw_irq_read(self->aq_hw, &irq_mask); if (err < 0) - goto err_exit; + return IRQ_NONE; if (irq_mask) { self->aq_hw_ops->hw_irq_disable(self->aq_hw, @@ -326,11 +324,10 @@ irqreturn_t aq_vec_isr_legacy(int irq, void *private) napi_schedule(&self->napi); } else { self->aq_hw_ops->hw_irq_enable(self->aq_hw, 1U); - err = IRQ_NONE; + return IRQ_NONE; } -err_exit: - return err >= 0 ? IRQ_HANDLED : IRQ_NONE; + return IRQ_HANDLED; } cpumask_t *aq_vec_get_affinity_mask(struct aq_vec_s *self) -- GitLab From cb6066a342cd90eb5d2bcd438ccb242bb67e278e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Sep 2019 13:55:32 +0300 Subject: [PATCH 0604/1055] net: hisilicon: Fix signedness bug in hix5hd2_dev_probe() [ Upstream commit 002dfe8085255b7bf1e0758c3d195c5412d35be9 ] The "priv->phy_mode" variable is an enum and in this context GCC will treat it as unsigned to the error handling will never trigger. Fixes: 57c5bc9ad7d7 ("net: hisilicon: add hix5hd2 mac driver") Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c index aab6fb10af94..6adf6831d120 100644 --- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c @@ -1202,7 +1202,7 @@ static int hix5hd2_dev_probe(struct platform_device *pdev) goto err_free_mdio; priv->phy_mode = of_get_phy_mode(node); - if (priv->phy_mode < 0) { + if ((int)priv->phy_mode < 0) { netdev_err(ndev, "not find phy-mode\n"); ret = -EINVAL; goto err_mdiobus; -- GitLab From ba54da52df0d948f9965f2d054df87e72b30dca0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Sep 2019 13:56:04 +0300 Subject: [PATCH 0605/1055] net: broadcom/bcmsysport: Fix signedness in bcm_sysport_probe() [ Upstream commit 25a584955f020d6ec499c513923fb220f3112d2b ] The "priv->phy_interface" variable is an enum and in this context GCC will treat it as unsigned so the error handling will never be triggered. Fixes: 80105befdb4b ("net: systemport: add Broadcom SYSTEMPORT Ethernet MAC driver") Signed-off-by: Dan Carpenter Acked-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/broadcom/bcmsysport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 79018fea7be2..69b2f99b0c19 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -2116,7 +2116,7 @@ static int bcm_sysport_probe(struct platform_device *pdev) priv->phy_interface = of_get_phy_mode(dn); /* Default to GMII interface mode */ - if (priv->phy_interface < 0) + if ((int)priv->phy_interface < 0) priv->phy_interface = PHY_INTERFACE_MODE_GMII; /* In the case of a fixed PHY, the DT node associated -- GitLab From cd885e8726baad6e386c182272bd52ed1612cb7a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Sep 2019 13:58:22 +0300 Subject: [PATCH 0606/1055] net: stmmac: dwmac-meson8b: Fix signedness bug in probe [ Upstream commit f10210517a2f37feea2edf85eb34c98977265c16 ] The "dwmac->phy_mode" is an enum and in this context GCC treats it as an unsigned int so the error handling is never triggered. Fixes: 566e82516253 ("net: stmmac: add a glue driver for the Amlogic Meson 8b / GXBB DWMAC") Signed-off-by: Dan Carpenter Reviewed-by: Martin Blumenstingl Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c index 8be4b32544ef..d71d3c1c85ee 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c @@ -285,7 +285,7 @@ static int meson8b_dwmac_probe(struct platform_device *pdev) dwmac->pdev = pdev; dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node); - if (dwmac->phy_mode < 0) { + if ((int)dwmac->phy_mode < 0) { dev_err(&pdev->dev, "missing phy-mode property\n"); ret = -EINVAL; goto err_remove_config_dt; -- GitLab From 168de4c8560e2ee278709557bf74d1418b18ddf4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Sep 2019 13:59:11 +0300 Subject: [PATCH 0607/1055] net: axienet: fix a signedness bug in probe [ Upstream commit 73e211e11be86715d66bd3c9d38b3c34b05fca9a ] The "lp->phy_mode" is an enum but in this context GCC treats it as an unsigned int so the error handling is never triggered. Fixes: ee06b1728b95 ("net: axienet: add support for standard phy-mode binding") Signed-off-by: Dan Carpenter Reviewed-by: Radhey Shyam Pandey Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 9ccd08a051f6..1152d74433f6 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1574,7 +1574,7 @@ static int axienet_probe(struct platform_device *pdev) } } else { lp->phy_mode = of_get_phy_mode(pdev->dev.of_node); - if (lp->phy_mode < 0) { + if ((int)lp->phy_mode < 0) { ret = -EINVAL; goto free_netdev; } -- GitLab From ed3f1423a1b303aac7aa3f38ab3535397e1e1e42 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Sep 2019 14:01:00 +0300 Subject: [PATCH 0608/1055] of: mdio: Fix a signedness bug in of_phy_get_and_connect() [ Upstream commit d7eb651212fdbafa82d485d8e76095ac3b14c193 ] The "iface" variable is an enum and in this context GCC treats it as an unsigned int so the error handling is never triggered. Fixes: b78624125304 ("of_mdio: Abstract a general interface for phy connect") Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/of/of_mdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 8c1819230ed2..fe26697d3bd7 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -358,7 +358,7 @@ struct phy_device *of_phy_get_and_connect(struct net_device *dev, struct phy_device *phy; iface = of_get_phy_mode(np); - if (iface < 0) + if ((int)iface < 0) return NULL; phy_np = of_parse_phandle(np, "phy-handle", 0); -- GitLab From 3dc236296a368bb3c5571207176d8e547589aadf Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Sep 2019 14:05:54 +0300 Subject: [PATCH 0609/1055] net: ethernet: stmmac: Fix signedness bug in ipq806x_gmac_of_parse() [ Upstream commit 231042181dc9d6122c6faba64e99ccb25f13cc6c ] The "gmac->phy_mode" variable is an enum and in this context GCC will treat it as an unsigned int so the error handling will never be triggered. Fixes: b1c17215d718 ("stmmac: add ipq806x glue layer") Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c index 866444b6c82f..11a4a81b0397 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c @@ -203,7 +203,7 @@ static int ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac) struct device *dev = &gmac->pdev->dev; gmac->phy_mode = of_get_phy_mode(dev->of_node); - if (gmac->phy_mode < 0) { + if ((int)gmac->phy_mode < 0) { dev_err(dev, "missing phy mode property\n"); return -EINVAL; } -- GitLab From ae79af838296f399eb53f555e76e86217695d6da Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 3 Oct 2019 13:57:29 +0200 Subject: [PATCH 0610/1055] nvme: retain split access workaround for capability reads [ Upstream commit 3a8ecc935efabdad106b5e06d07b150c394b4465 ] Commit 7fd8930f26be4 "nvme: add a common helper to read Identify Controller data" has re-introduced an issue that we have attempted to work around in the past, in commit a310acd7a7ea ("NVMe: use split lo_hi_{read,write}q"). The problem is that some PCIe NVMe controllers do not implement 64-bit outbound accesses correctly, which is why the commit above switched to using lo_hi_[read|write]q for all 64-bit BAR accesses occuring in the code. In the mean time, the NVMe subsystem has been refactored, and now calls into the PCIe support layer for NVMe via a .reg_read64() method, which fails to use lo_hi_readq(), and thus reintroduces the problem that the workaround above aimed to address. Given that, at the moment, .reg_read64() is only used to read the capability register [which is known to tolerate split reads], let's switch .reg_read64() to lo_hi_readq() as well. This fixes a boot issue on some ARM boxes with NVMe behind a Synopsys DesignWare PCIe host controller. Fixes: 7fd8930f26be4 ("nvme: add a common helper to read Identify Controller data") Signed-off-by: Ard Biesheuvel Signed-off-by: Sagi Grimberg Signed-off-by: Sasha Levin --- drivers/nvme/host/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index cd11cced3678..3788c053a0b1 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2274,7 +2274,7 @@ static int nvme_pci_reg_write32(struct nvme_ctrl *ctrl, u32 off, u32 val) static int nvme_pci_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val) { - *val = readq(to_nvme_dev(ctrl)->bar + off); + *val = lo_hi_readq(to_nvme_dev(ctrl)->bar + off); return 0; } -- GitLab From fe89f528b519c29e392a4acd71c00753702f27e9 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Sun, 6 Oct 2019 13:08:56 +0200 Subject: [PATCH 0611/1055] net: stmmac: gmac4+: Not all Unicast addresses may be available [ Upstream commit 25683bab09a70542b9f8e3e28f79b3369e56701f ] Some setups may not have all Unicast addresses filters available. Check the number of available filters before trying to setup it. Fixes: 477286b53f55 ("stmmac: add GMAC4 core support") Signed-off-by: Jose Abreu Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 8445af580cb6..e5566c121525 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -438,7 +438,7 @@ static void dwmac4_set_filter(struct mac_device_info *hw, } /* Handle multiple unicast addresses */ - if (netdev_uc_count(dev) > GMAC_MAX_PERFECT_ADDRESSES) { + if (netdev_uc_count(dev) > hw->unicast_filter_entries) { /* Switch to promiscuous mode if more than 128 addrs * are required */ -- GitLab From 05c2aa29d3a4e6d88015cecf04085d4b13ec1ae2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 4 Oct 2019 15:37:05 +0300 Subject: [PATCH 0612/1055] mac80211: accept deauth frames in IBSS mode [ Upstream commit 95697f9907bfe3eab0ef20265a766b22e27dde64 ] We can process deauth frames and all, but we drop them very early in the RX path today - this could never have worked. Fixes: 2cc59e784b54 ("mac80211: reply to AUTH with DEAUTH if sta allocation fails in IBSS") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Link: https://lore.kernel.org/r/20191004123706.15768-2-luca@coelho.fi Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/mac80211/rx.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 4a6b3c7b35e3..31000622376d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3227,9 +3227,18 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP): /* process for all: mesh, mlme, ibss */ break; + case cpu_to_le16(IEEE80211_STYPE_DEAUTH): + if (is_multicast_ether_addr(mgmt->da) && + !is_broadcast_ether_addr(mgmt->da)) + return RX_DROP_MONITOR; + + /* process only for station/IBSS */ + if (sdata->vif.type != NL80211_IFTYPE_STATION && + sdata->vif.type != NL80211_IFTYPE_ADHOC) + return RX_DROP_MONITOR; + break; case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): - case cpu_to_le16(IEEE80211_STYPE_DEAUTH): case cpu_to_le16(IEEE80211_STYPE_DISASSOC): if (is_multicast_ether_addr(mgmt->da) && !is_broadcast_ether_addr(mgmt->da)) -- GitLab From e39340636dd980978224755f7bb641eeb08b88f4 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 6 Oct 2019 14:24:26 -0700 Subject: [PATCH 0613/1055] llc: fix another potential sk_buff leak in llc_ui_sendmsg() [ Upstream commit fc8d5db10cbe1338a52ebc74e7feab9276721774 ] All callers of llc_conn_state_process() except llc_build_and_send_pkt() (via llc_ui_sendmsg() -> llc_ui_send_data()) assume that it always consumes a reference to the skb. Fix this caller to do the same. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Biggers Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/llc/af_llc.c | 34 ++++++++++++++++++++-------------- net/llc/llc_conn.c | 2 ++ net/llc/llc_if.c | 12 ++++++++---- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 2e472d5c3ea4..d552e8819713 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -113,22 +113,26 @@ static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr) * * Send data via reliable llc2 connection. * Returns 0 upon success, non-zero if action did not succeed. + * + * This function always consumes a reference to the skb. */ static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock) { struct llc_sock* llc = llc_sk(sk); - int rc = 0; if (unlikely(llc_data_accept_state(llc->state) || llc->remote_busy_flag || llc->p_flag)) { long timeout = sock_sndtimeo(sk, noblock); + int rc; rc = llc_ui_wait_for_busy_core(sk, timeout); + if (rc) { + kfree_skb(skb); + return rc; + } } - if (unlikely(!rc)) - rc = llc_build_and_send_pkt(sk, skb); - return rc; + return llc_build_and_send_pkt(sk, skb); } static void llc_ui_sk_init(struct socket *sock, struct sock *sk) @@ -900,7 +904,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) DECLARE_SOCKADDR(struct sockaddr_llc *, addr, msg->msg_name); int flags = msg->msg_flags; int noblock = flags & MSG_DONTWAIT; - struct sk_buff *skb; + struct sk_buff *skb = NULL; size_t size = 0; int rc = -EINVAL, copied = 0, hdrlen; @@ -909,10 +913,10 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) lock_sock(sk); if (addr) { if (msg->msg_namelen < sizeof(*addr)) - goto release; + goto out; } else { if (llc_ui_addr_null(&llc->addr)) - goto release; + goto out; addr = &llc->addr; } /* must bind connection to sap if user hasn't done it. */ @@ -920,7 +924,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) /* bind to sap with null dev, exclusive. */ rc = llc_ui_autobind(sock, addr); if (rc) - goto release; + goto out; } hdrlen = llc->dev->hard_header_len + llc_ui_header_len(sk, addr); size = hdrlen + len; @@ -929,12 +933,12 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) copied = size - hdrlen; rc = -EINVAL; if (copied < 0) - goto release; + goto out; release_sock(sk); skb = sock_alloc_send_skb(sk, size, noblock, &rc); lock_sock(sk); if (!skb) - goto release; + goto out; skb->dev = llc->dev; skb->protocol = llc_proto_type(addr->sllc_arphrd); skb_reserve(skb, hdrlen); @@ -944,29 +948,31 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) if (sk->sk_type == SOCK_DGRAM || addr->sllc_ua) { llc_build_and_send_ui_pkt(llc->sap, skb, addr->sllc_mac, addr->sllc_sap); + skb = NULL; goto out; } if (addr->sllc_test) { llc_build_and_send_test_pkt(llc->sap, skb, addr->sllc_mac, addr->sllc_sap); + skb = NULL; goto out; } if (addr->sllc_xid) { llc_build_and_send_xid_pkt(llc->sap, skb, addr->sllc_mac, addr->sllc_sap); + skb = NULL; goto out; } rc = -ENOPROTOOPT; if (!(sk->sk_type == SOCK_STREAM && !addr->sllc_ua)) goto out; rc = llc_ui_send_data(sk, skb, noblock); + skb = NULL; out: - if (rc) { - kfree_skb(skb); -release: + kfree_skb(skb); + if (rc) dprintk("%s: failed sending from %02X to %02X: %d\n", __func__, llc->laddr.lsap, llc->daddr.lsap, rc); - } release_sock(sk); return rc ? : copied; } diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 444c13e752a0..7340f23e16de 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -55,6 +55,8 @@ int sysctl_llc2_busy_timeout = LLC2_BUSY_TIME * HZ; * (executing it's actions and changing state), upper layer will be * indicated or confirmed, if needed. Returns 0 for success, 1 for * failure. The socket lock has to be held before calling this function. + * + * This function always consumes a reference to the skb. */ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) { diff --git a/net/llc/llc_if.c b/net/llc/llc_if.c index 6daf391b3e84..fc4d2bd8816f 100644 --- a/net/llc/llc_if.c +++ b/net/llc/llc_if.c @@ -38,6 +38,8 @@ * closed and -EBUSY when sending data is not permitted in this state or * LLC has send an I pdu with p bit set to 1 and is waiting for it's * response. + * + * This function always consumes a reference to the skb. */ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb) { @@ -46,20 +48,22 @@ int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb) struct llc_sock *llc = llc_sk(sk); if (unlikely(llc->state == LLC_CONN_STATE_ADM)) - goto out; + goto out_free; rc = -EBUSY; if (unlikely(llc_data_accept_state(llc->state) || /* data_conn_refuse */ llc->p_flag)) { llc->failed_data_req = 1; - goto out; + goto out_free; } ev = llc_conn_ev(skb); ev->type = LLC_CONN_EV_TYPE_PRIM; ev->prim = LLC_DATA_PRIM; ev->prim_type = LLC_PRIM_TYPE_REQ; skb->dev = llc->dev; - rc = llc_conn_state_process(sk, skb); -out: + return llc_conn_state_process(sk, skb); + +out_free: + kfree_skb(skb); return rc; } -- GitLab From a8cfe559cb47108cc97353b65d79115cf6bf1b57 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 6 Oct 2019 14:24:27 -0700 Subject: [PATCH 0614/1055] llc: fix sk_buff refcounting in llc_conn_state_process() [ Upstream commit 36453c852816f19947ca482a595dffdd2efa4965 ] If llc_conn_state_process() sees that llc_conn_service() put the skb on a list, it will drop one fewer references to it. This is wrong because the current behavior is that llc_conn_service() never consumes a reference to the skb. The code also makes the number of skb references being dropped conditional on which of ind_prim and cfm_prim are nonzero, yet neither of these affects how many references are *acquired*. So there is extra code that tries to fix this up by sometimes taking another reference. Remove the unnecessary/broken refcounting logic and instead just add an skb_get() before the only two places where an extra reference is actually consumed. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Biggers Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/llc/llc_conn.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 7340f23e16de..7fbc682aff04 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -64,12 +64,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) struct llc_sock *llc = llc_sk(skb->sk); struct llc_conn_state_ev *ev = llc_conn_ev(skb); - /* - * We have to hold the skb, because llc_conn_service will kfree it in - * the sending path and we need to look at the skb->cb, where we encode - * llc_conn_state_ev. - */ - skb_get(skb); ev->ind_prim = ev->cfm_prim = 0; /* * Send event to state machine @@ -77,21 +71,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) rc = llc_conn_service(skb->sk, skb); if (unlikely(rc != 0)) { printk(KERN_ERR "%s: llc_conn_service failed\n", __func__); - goto out_kfree_skb; - } - - if (unlikely(!ev->ind_prim && !ev->cfm_prim)) { - /* indicate or confirm not required */ - if (!skb->next) - goto out_kfree_skb; goto out_skb_put; } - if (unlikely(ev->ind_prim && ev->cfm_prim)) /* Paranoia */ - skb_get(skb); - switch (ev->ind_prim) { case LLC_DATA_PRIM: + skb_get(skb); llc_save_primitive(sk, skb, LLC_DATA_PRIM); if (unlikely(sock_queue_rcv_skb(sk, skb))) { /* @@ -108,6 +93,7 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) * skb->sk pointing to the newly created struct sock in * llc_conn_handler. -acme */ + skb_get(skb); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_state_change(sk); break; @@ -123,7 +109,6 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) sk->sk_state_change(sk); } } - kfree_skb(skb); sock_put(sk); break; case LLC_RESET_PRIM: @@ -132,14 +117,11 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) * RESET is not being notified to upper layers for now */ printk(KERN_INFO "%s: received a reset ind!\n", __func__); - kfree_skb(skb); break; default: - if (ev->ind_prim) { + if (ev->ind_prim) printk(KERN_INFO "%s: received unknown %d prim!\n", __func__, ev->ind_prim); - kfree_skb(skb); - } /* No indication */ break; } @@ -181,15 +163,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) printk(KERN_INFO "%s: received a reset conf!\n", __func__); break; default: - if (ev->cfm_prim) { + if (ev->cfm_prim) printk(KERN_INFO "%s: received unknown %d prim!\n", __func__, ev->cfm_prim); - break; - } - goto out_skb_put; /* No confirmation */ + /* No confirmation */ + break; } -out_kfree_skb: - kfree_skb(skb); out_skb_put: kfree_skb(skb); return rc; -- GitLab From 3134607b52605e595781f5083621bc7eb60e1242 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 7 Oct 2019 17:43:04 +0200 Subject: [PATCH 0615/1055] net: stmmac: fix length of PTP clock's name string [ Upstream commit 5da202c88f8c355ad79bc2e8eb582e6d433060e7 ] The field "name" in struct ptp_clock_info has a fixed size of 16 chars and is used as zero terminated string by clock_name_show() in drivers/ptp/ptp_sysfs.c The current initialization value requires 17 chars to fit also the null termination, and this causes overflow to the next bytes in the struct when the string is read as null terminated: hexdump -C /sys/class/ptp/ptp0/clock_name 00000000 73 74 6d 6d 61 63 5f 70 74 70 5f 63 6c 6f 63 6b |stmmac_ptp_clock| 00000010 a0 ac b9 03 0a |.....| where the extra 4 bytes (excluding the newline) after the string represent the integer 0x03b9aca0 = 62500000 assigned to the field "max_adj" that follows "name" in the same struct. There is no strict requirement for the "name" content and in the comment in ptp_clock_kernel.h it's reported it should just be 'A short "friendly name" to identify the clock'. Replace it with "stmmac ptp". Signed-off-by: Antonio Borneo Fixes: 92ba6888510c ("stmmac: add the support for PTP hw clock driver") Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c index e471a903c654..1c1d6a942822 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c @@ -154,7 +154,7 @@ static int stmmac_enable(struct ptp_clock_info *ptp, /* structure describing a PTP hardware clock */ static const struct ptp_clock_info stmmac_ptp_clock_ops = { .owner = THIS_MODULE, - .name = "stmmac_ptp_clock", + .name = "stmmac ptp", .max_adj = 62500000, .n_alarm = 0, .n_ext_ts = 0, -- GitLab From e891a20643c751e07f1404c6e9e2267391a37f04 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 9 Oct 2019 11:10:52 +0800 Subject: [PATCH 0616/1055] act_mirred: Fix mirred_init_module error handling [ Upstream commit 11c9a7d38af524217efb7a176ad322b97ac2f163 ] If tcf_register_action failed, mirred_device_notifier should be unregistered. Fixes: 3b87956ea645 ("net sched: fix race in mirred device removal") Signed-off-by: YueHaibing Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/sched/act_mirred.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 529bb064c4a4..dcfaa4f9c7c5 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -371,7 +371,11 @@ static int __init mirred_init_module(void) return err; pr_info("Mirror/redirect action on\n"); - return tcf_register_action(&act_mirred_ops, &mirred_net_ops); + err = tcf_register_action(&act_mirred_ops, &mirred_net_ops); + if (err) + unregister_netdevice_notifier(&mirred_device_notifier); + + return err; } static void __exit mirred_cleanup_module(void) -- GitLab From 2ffb5a9b396d7857600fdf94432a94490c0cae71 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 9 Oct 2019 12:55:53 -0700 Subject: [PATCH 0617/1055] net: avoid possible false sharing in sk_leave_memory_pressure() [ Upstream commit 503978aca46124cd714703e180b9c8292ba50ba7 ] As mentioned in https://github.com/google/ktsan/wiki/READ_ONCE-and-WRITE_ONCE#it-may-improve-performance a C compiler can legally transform : if (memory_pressure && *memory_pressure) *memory_pressure = 0; to : if (memory_pressure) *memory_pressure = 0; Fixes: 0604475119de ("tcp: add TCPMemoryPressuresChrono counter") Fixes: 180d8cd942ce ("foundations of per-cgroup memory pressure controlling.") Fixes: 3ab224be6d69 ("[NET] CORE: Introducing new memory accounting interface.") Signed-off-by: Eric Dumazet Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- net/core/sock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/sock.c b/net/core/sock.c index 90ccbbf9e6b0..03ca2f638eb4 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2165,8 +2165,8 @@ static void sk_leave_memory_pressure(struct sock *sk) } else { unsigned long *memory_pressure = sk->sk_prot->memory_pressure; - if (memory_pressure && *memory_pressure) - *memory_pressure = 0; + if (memory_pressure && READ_ONCE(*memory_pressure)) + WRITE_ONCE(*memory_pressure, 0); } } -- GitLab From 681c8c92c4b78e80e0853f8e18861e93069d68e6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 9 Oct 2019 14:51:20 -0700 Subject: [PATCH 0618/1055] net: add {READ|WRITE}_ONCE() annotations on ->rskq_accept_head [ Upstream commit 60b173ca3d1cd1782bd0096dc17298ec242f6fb1 ] reqsk_queue_empty() is called from inet_csk_listen_poll() while other cpus might write ->rskq_accept_head value. Use {READ|WRITE}_ONCE() to avoid compiler tricks and potential KCSAN splats. Fixes: fff1f3001cc5 ("tcp: add a spinlock to protect struct request_sock_queue") Signed-off-by: Eric Dumazet Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/xen/pvcalls-back.c | 2 +- include/net/request_sock.h | 4 ++-- net/ipv4/inet_connection_sock.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/xen/pvcalls-back.c b/drivers/xen/pvcalls-back.c index abd6dbc29ac2..58be15c27b6d 100644 --- a/drivers/xen/pvcalls-back.c +++ b/drivers/xen/pvcalls-back.c @@ -792,7 +792,7 @@ static int pvcalls_back_poll(struct xenbus_device *dev, mappass->reqcopy = *req; icsk = inet_csk(mappass->sock->sk); queue = &icsk->icsk_accept_queue; - data = queue->rskq_accept_head != NULL; + data = READ_ONCE(queue->rskq_accept_head) != NULL; if (data) { mappass->reqcopy.cmd = 0; ret = 0; diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 23e22054aa60..04aa2c7d35c4 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -181,7 +181,7 @@ void reqsk_fastopen_remove(struct sock *sk, struct request_sock *req, static inline bool reqsk_queue_empty(const struct request_sock_queue *queue) { - return queue->rskq_accept_head == NULL; + return READ_ONCE(queue->rskq_accept_head) == NULL; } static inline struct request_sock *reqsk_queue_remove(struct request_sock_queue *queue, @@ -193,7 +193,7 @@ static inline struct request_sock *reqsk_queue_remove(struct request_sock_queue req = queue->rskq_accept_head; if (req) { sk_acceptq_removed(parent); - queue->rskq_accept_head = req->dl_next; + WRITE_ONCE(queue->rskq_accept_head, req->dl_next); if (queue->rskq_accept_head == NULL) queue->rskq_accept_tail = NULL; } diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index f7224c4fc30f..da55ce62fe50 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -936,7 +936,7 @@ struct sock *inet_csk_reqsk_queue_add(struct sock *sk, req->sk = child; req->dl_next = NULL; if (queue->rskq_accept_head == NULL) - queue->rskq_accept_head = req; + WRITE_ONCE(queue->rskq_accept_head, req); else queue->rskq_accept_tail->dl_next = req; queue->rskq_accept_tail = req; -- GitLab From a8e920b22026c4717daee0e16ecee828aecfcb84 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 9 Oct 2019 15:10:15 -0700 Subject: [PATCH 0619/1055] tcp: annotate lockless access to tcp_memory_pressure [ Upstream commit 1f142c17d19a5618d5a633195a46f2c8be9bf232 ] tcp_memory_pressure is read without holding any lock, and its value could be changed on other cpus. Use READ_ONCE() to annotate these lockless reads. The write side is already using atomic ops. Fixes: b8da51ebb1aa ("tcp: introduce tcp_under_memory_pressure()") Signed-off-by: Eric Dumazet Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- include/net/tcp.h | 2 +- net/ipv4/tcp.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 00d10f0e1194..c96302310314 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -289,7 +289,7 @@ static inline bool tcp_under_memory_pressure(const struct sock *sk) mem_cgroup_under_socket_pressure(sk->sk_memcg)) return true; - return tcp_memory_pressure; + return READ_ONCE(tcp_memory_pressure); } /* * The next routines deal with comparing 32 bit unsigned ints diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 8f07655718f3..db1eceda2359 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -328,7 +328,7 @@ void tcp_enter_memory_pressure(struct sock *sk) { unsigned long val; - if (tcp_memory_pressure) + if (READ_ONCE(tcp_memory_pressure)) return; val = jiffies; @@ -343,7 +343,7 @@ void tcp_leave_memory_pressure(struct sock *sk) { unsigned long val; - if (!tcp_memory_pressure) + if (!READ_ONCE(tcp_memory_pressure)) return; val = xchg(&tcp_memory_pressure, 0); if (val) -- GitLab From 35ff594b0da23f442a881154356deadf86e2d3ca Mon Sep 17 00:00:00 2001 From: Jeffrey Hugo Date: Fri, 11 Oct 2019 06:39:39 -0700 Subject: [PATCH 0620/1055] drm/msm/dsi: Implement reset correctly [ Upstream commit 78e31c42261779a01bc73472d0f65f15378e9de3 ] On msm8998, vblank timeouts are observed because the DSI controller is not reset properly, which ends up stalling the MDP. This is because the reset logic is not correct per the hardware documentation. The documentation states that after asserting reset, software should wait some time (no indication of how long), or poll the status register until it returns 0 before deasserting reset. wmb() is insufficient for this purpose since it just ensures ordering, not timing between writes. Since asserting and deasserting reset occurs on the same register, ordering is already guaranteed by the architecture, making the wmb extraneous. Since we would define a timeout for polling the status register to avoid a possible infinite loop, lets just use a static delay of 20 ms, since 16.666 ms is the time available to process one frame at 60 fps. Fixes: a689554ba6ed ("drm/msm: Initial add DSI connector support") Cc: Hai Li Cc: Rob Clark Signed-off-by: Jeffrey Hugo Reviewed-by: Sean Paul [seanpaul renamed RESET_DELAY to DSI_RESET_TOGGLE_DELAY_MS] Signed-off-by: Sean Paul Link: https://patchwork.freedesktop.org/patch/msgid/20191011133939.16551-1-jeffrey.l.hugo@gmail.com Signed-off-by: Sasha Levin --- drivers/gpu/drm/msm/dsi/dsi_host.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index a9a0b56f1fbc..b9cb7c09e05a 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -34,6 +34,8 @@ #include "dsi_cfg.h" #include "msm_kms.h" +#define DSI_RESET_TOGGLE_DELAY_MS 20 + static int dsi_get_version(const void __iomem *base, u32 *major, u32 *minor) { u32 ver; @@ -906,7 +908,7 @@ static void dsi_sw_reset(struct msm_dsi_host *msm_host) wmb(); /* clocks need to be enabled before reset */ dsi_write(msm_host, REG_DSI_RESET, 1); - wmb(); /* make sure reset happen */ + msleep(DSI_RESET_TOGGLE_DELAY_MS); /* make sure reset happen */ dsi_write(msm_host, REG_DSI_RESET, 0); } @@ -1288,7 +1290,7 @@ static void dsi_sw_reset_restore(struct msm_dsi_host *msm_host) /* dsi controller can only be reset while clocks are running */ dsi_write(msm_host, REG_DSI_RESET, 1); - wmb(); /* make sure reset happen */ + msleep(DSI_RESET_TOGGLE_DELAY_MS); /* make sure reset happen */ dsi_write(msm_host, REG_DSI_RESET, 0); wmb(); /* controller out of reset */ dsi_write(msm_host, REG_DSI_CTRL, data0); -- GitLab From 1ca124f27e5083048bb9d8c5a87deca63b1a027e Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Tue, 24 Sep 2019 09:49:18 +0000 Subject: [PATCH 0621/1055] dmaengine: imx-sdma: fix size check for sdma script_number [ Upstream commit bd73dfabdda280fc5f05bdec79b6721b4b2f035f ] Illegal memory will be touch if SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3 (41) exceed the size of structure sdma_script_start_addrs(40), thus cause memory corrupt such as slob block header so that kernel trap into while() loop forever in slob_free(). Please refer to below code piece in imx-sdma.c: for (i = 0; i < sdma->script_number; i++) if (addr_arr[i] > 0) saddr_arr[i] = addr_arr[i]; /* memory corrupt here */ That issue was brought by commit a572460be9cf ("dmaengine: imx-sdma: Add support for version 3 firmware") because SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3 (38->41 3 scripts added) not align with script number added in sdma_script_start_addrs(2 scripts). Fixes: a572460be9cf ("dmaengine: imx-sdma: Add support for version 3 firmware") Cc: stable@vger.kernel Link: https://www.spinics.net/lists/arm-kernel/msg754895.html Signed-off-by: Robin Gong Reported-by: Jurgen Lambrecht Link: https://lore.kernel.org/r/1569347584-3478-1-git-send-email-yibin.gong@nxp.com [vkoul: update the patch title] Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/imx-sdma.c | 8 ++++++++ include/linux/platform_data/dma-imx-sdma.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 0fc12a8783e3..99f3f22ed647 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1441,6 +1441,14 @@ static void sdma_add_scripts(struct sdma_engine *sdma, if (!sdma->script_number) sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; + if (sdma->script_number > sizeof(struct sdma_script_start_addrs) + / sizeof(s32)) { + dev_err(sdma->dev, + "SDMA script number %d not match with firmware.\n", + sdma->script_number); + return; + } + for (i = 0; i < sdma->script_number; i++) if (addr_arr[i] > 0) saddr_arr[i] = addr_arr[i]; diff --git a/include/linux/platform_data/dma-imx-sdma.h b/include/linux/platform_data/dma-imx-sdma.h index 6eaa53cef0bd..30e676b36b24 100644 --- a/include/linux/platform_data/dma-imx-sdma.h +++ b/include/linux/platform_data/dma-imx-sdma.h @@ -51,7 +51,10 @@ struct sdma_script_start_addrs { /* End of v2 array */ s32 zcanfd_2_mcu_addr; s32 zqspi_2_mcu_addr; + s32 mcu_2_ecspi_addr; /* End of v3 array */ + s32 mcu_2_zqspi_addr; + /* End of v4 array */ }; /** -- GitLab From e0f8a42943c46030a40737a02e871186968f0123 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 18 Oct 2019 09:16:57 -0700 Subject: [PATCH 0622/1055] net: netem: fix error path for corrupted GSO frames [ Upstream commit a7fa12d15855904aff1716e1fc723c03ba38c5cc ] To corrupt a GSO frame we first perform segmentation. We then proceed using the first segment instead of the full GSO skb and requeue the rest of the segments as separate packets. If there are any issues with processing the first segment we still want to process the rest, therefore we jump to the finish_segs label. Commit 177b8007463c ("net: netem: fix backlog accounting for corrupted GSO frames") started using the pointer to the first segment in the "rest of segments processing", but as mentioned above the first segment may had already been freed at this point. Backlog corrections for parent qdiscs have to be adjusted. Fixes: 177b8007463c ("net: netem: fix backlog accounting for corrupted GSO frames") Reported-by: kbuild test robot Reported-by: Dan Carpenter Reported-by: Ben Hutchings Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/sched/sch_netem.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index ede0a24e67eb..64c3cfa35736 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -504,6 +504,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) { qdisc_drop(skb, sch, to_free); + skb = NULL; goto finish_segs; } @@ -580,9 +581,10 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, finish_segs: if (segs) { unsigned int len, last_len; - int nb = 0; + int nb; - len = skb->len; + len = skb ? skb->len : 0; + nb = skb ? 1 : 0; while (segs) { skb2 = segs->next; @@ -599,7 +601,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, } segs = skb2; } - qdisc_tree_reduce_backlog(sch, -nb, prev_len - len); + /* Parent qdiscs accounted for 1 skb of size @prev_len */ + qdisc_tree_reduce_backlog(sch, -(nb - 1), -(len - prev_len)); } return NET_XMIT_SUCCESS; } -- GitLab From b630744138cd00215befad571428b38b4b9f219d Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 18 Oct 2019 09:16:58 -0700 Subject: [PATCH 0623/1055] net: netem: correct the parent's backlog when corrupted packet was dropped [ Upstream commit e0ad032e144731a5928f2d75e91c2064ba1a764c ] If packet corruption failed we jump to finish_segs and return NET_XMIT_SUCCESS. Seeing success will make the parent qdisc increment its backlog, that's incorrect - we need to return NET_XMIT_DROP. Fixes: 6071bd1aa13e ("netem: Segment GSO packets on enqueue") Signed-off-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/sched/sch_netem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 64c3cfa35736..328b043edf07 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -603,6 +603,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, } /* Parent qdiscs accounted for 1 skb of size @prev_len */ qdisc_tree_reduce_backlog(sch, -(nb - 1), -(len - prev_len)); + } else if (!skb) { + return NET_XMIT_DROP; } return NET_XMIT_SUCCESS; } -- GitLab From fde9261b5217d48dc19f93610759d7a658237c9a Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Wed, 20 Nov 2019 18:29:13 +0100 Subject: [PATCH 0624/1055] net: qca_spi: Move reset_count to struct qcaspi [ Upstream commit bc19c32904e36548335b35fdce6ce734e20afc0a ] The reset counter is specific for every QCA700x chip. So move this into the private driver struct. Otherwise we get unpredictable reset behavior in setups with multiple QCA700x chips. Fixes: 291ab06ecf67 (net: qualcomm: new Ethernet over SPI driver for QCA7000) Signed-off-by: Stefan Wahren Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/qualcomm/qca_spi.c | 9 ++++----- drivers/net/ethernet/qualcomm/qca_spi.h | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 275fc6f154a7..1c87178fc485 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -475,7 +475,6 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event) u16 signature = 0; u16 spi_config; u16 wrbuf_space = 0; - static u16 reset_count; if (event == QCASPI_EVENT_CPUON) { /* Read signature twice, if not valid @@ -528,13 +527,13 @@ qcaspi_qca7k_sync(struct qcaspi *qca, int event) qca->sync = QCASPI_SYNC_RESET; qca->stats.trig_reset++; - reset_count = 0; + qca->reset_count = 0; break; case QCASPI_SYNC_RESET: - reset_count++; + qca->reset_count++; netdev_dbg(qca->net_dev, "sync: waiting for CPU on, count %u.\n", - reset_count); - if (reset_count >= QCASPI_RESET_TIMEOUT) { + qca->reset_count); + if (qca->reset_count >= QCASPI_RESET_TIMEOUT) { /* reset did not seem to take place, try again */ qca->sync = QCASPI_SYNC_UNKNOWN; qca->stats.reset_timeout++; diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h index fc0e98726b36..719c41227f22 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.h +++ b/drivers/net/ethernet/qualcomm/qca_spi.h @@ -92,6 +92,7 @@ struct qcaspi { unsigned int intr_req; unsigned int intr_svc; + u16 reset_count; #ifdef CONFIG_DEBUG_FS struct dentry *device_root; -- GitLab From 495d767ec747d62fb16b246832b545db1c8f1f8f Mon Sep 17 00:00:00 2001 From: Marc Dionne Date: Thu, 21 Nov 2019 15:37:26 +0000 Subject: [PATCH 0625/1055] afs: Fix large file support [ Upstream commit b485275f1aca8a9da37fd35e4fad673935e827da ] By default s_maxbytes is set to MAX_NON_LFS, which limits the usable file size to 2GB, enforced by the vfs. Commit b9b1f8d5930a ("AFS: write support fixes") added support for the 64-bit fetch and store server operations, but did not change this value. As a result, attempts to write past the 2G mark result in EFBIG errors: $ dd if=/dev/zero of=foo bs=1M count=1 seek=2048 dd: error writing 'foo': File too large Set s_maxbytes to MAX_LFS_FILESIZE. Fixes: b9b1f8d5930a ("AFS: write support fixes") Signed-off-by: Marc Dionne Signed-off-by: David Howells Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin --- fs/afs/super.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/afs/super.c b/fs/afs/super.c index 689173c0a682..f8529ddbd587 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -359,6 +359,7 @@ static int afs_fill_super(struct super_block *sb, /* fill in the superblock */ sb->s_blocksize = PAGE_SIZE; sb->s_blocksize_bits = PAGE_SHIFT; + sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_magic = AFS_FS_MAGIC; sb->s_op = &afs_super_ops; sb->s_xattr = afs_xattr_handlers; -- GitLab From d9d56b8e366ae31bcb4e74056cda11432dc251c1 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Mon, 4 Nov 2019 21:33:50 +0800 Subject: [PATCH 0626/1055] MIPS: Loongson: Fix return value of loongson_hwmon_init [ Upstream commit dece3c2a320b0a6d891da6ff774ab763969b6860 ] When call function hwmon_device_register failed, use the actual return value instead of always -ENOMEM. Fixes: 64f09aa967e1 ("MIPS: Loongson-3: Add CPU Hwmon platform driver") Signed-off-by: Tiezhu Yang Signed-off-by: Paul Burton Cc: Ralf Baechle Cc: James Hogan Cc: Huacai Chen Cc: Jiaxun Yang Cc: linux-mips@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Sasha Levin --- drivers/platform/mips/cpu_hwmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/mips/cpu_hwmon.c b/drivers/platform/mips/cpu_hwmon.c index 322de58eebaf..02484ae9a116 100644 --- a/drivers/platform/mips/cpu_hwmon.c +++ b/drivers/platform/mips/cpu_hwmon.c @@ -158,7 +158,7 @@ static int __init loongson_hwmon_init(void) cpu_hwmon_dev = hwmon_device_register(NULL); if (IS_ERR(cpu_hwmon_dev)) { - ret = -ENOMEM; + ret = PTR_ERR(cpu_hwmon_dev); pr_err("hwmon_device_register fail!\n"); goto fail_hwmon_device_register; } -- GitLab From de67fb88a153da82174e8496166fcb72e337d962 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 1 Nov 2019 16:42:37 -0700 Subject: [PATCH 0627/1055] hv_netvsc: flag software created hash value [ Upstream commit df9f540ca74297a84bafacfa197e9347b20beea5 ] When the driver needs to create a hash value because it was not done at higher level, then the hash should be marked as a software not hardware hash. Fixes: f72860afa2e3 ("hv_netvsc: Exclude non-TCP port numbers from vRSS hashing") Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/hyperv/netvsc_drv.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 9e48855f6407..14451e14d99d 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -282,9 +282,9 @@ static inline u32 netvsc_get_hash( else if (flow.basic.n_proto == htons(ETH_P_IPV6)) hash = jhash2((u32 *)&flow.addrs.v6addrs, 8, hashrnd); else - hash = 0; + return 0; - skb_set_hash(skb, hash, PKT_HASH_TYPE_L3); + __skb_set_sw_hash(skb, hash, false); } return hash; @@ -802,8 +802,7 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, skb->protocol == htons(ETH_P_IP)) netvsc_comp_ipcsum(skb); - /* Do L4 checksum offload if enabled and present. - */ + /* Do L4 checksum offload if enabled and present. */ if (csum_info && (net->features & NETIF_F_RXCSUM)) { if (csum_info->receive.tcp_checksum_succeeded || csum_info->receive.udp_checksum_succeeded) -- GitLab From 00719495ea54c6d40a11ee1785ea2cedc8573042 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 5 Nov 2019 14:11:49 -0800 Subject: [PATCH 0628/1055] net: neigh: use long type to store jiffies delta [ Upstream commit 9d027e3a83f39b819e908e4e09084277a2e45e95 ] A difference of two unsigned long needs long storage. Fixes: c7fb64db001f ("[NETLINK]: Neighbour table configuration and statistics via rtnetlink") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/core/neighbour.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 16ac50b1b9a7..567e431813e5 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1877,8 +1877,8 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl, goto nla_put_failure; { unsigned long now = jiffies; - unsigned int flush_delta = now - tbl->last_flush; - unsigned int rand_delta = now - tbl->last_rand; + long flush_delta = now - tbl->last_flush; + long rand_delta = now - tbl->last_rand; struct neigh_hash_table *nht; struct ndt_config ndc = { .ndtc_key_len = tbl->key_len, -- GitLab From 68b7234958105858d85a5130d73e3f5fe5e70c22 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 8 Nov 2019 05:07:46 -0800 Subject: [PATCH 0629/1055] packet: fix data-race in fanout_flow_is_huge() [ Upstream commit b756ad928d98e5ef0b74af7546a6a31a8dadde00 ] KCSAN reported the following data-race [1] Adding a couple of READ_ONCE()/WRITE_ONCE() should silence it. Since the report hinted about multiple cpus using the history concurrently, I added a test avoiding writing on it if the victim slot already contains the desired value. [1] BUG: KCSAN: data-race in fanout_demux_rollover / fanout_demux_rollover read to 0xffff8880b01786cc of 4 bytes by task 18921 on cpu 1: fanout_flow_is_huge net/packet/af_packet.c:1303 [inline] fanout_demux_rollover+0x33e/0x3f0 net/packet/af_packet.c:1353 packet_rcv_fanout+0x34e/0x490 net/packet/af_packet.c:1453 deliver_skb net/core/dev.c:1888 [inline] dev_queue_xmit_nit+0x15b/0x540 net/core/dev.c:1958 xmit_one net/core/dev.c:3195 [inline] dev_hard_start_xmit+0x3f5/0x430 net/core/dev.c:3215 __dev_queue_xmit+0x14ab/0x1b40 net/core/dev.c:3792 dev_queue_xmit+0x21/0x30 net/core/dev.c:3825 neigh_direct_output+0x1f/0x30 net/core/neighbour.c:1530 neigh_output include/net/neighbour.h:511 [inline] ip6_finish_output2+0x7a2/0xec0 net/ipv6/ip6_output.c:116 __ip6_finish_output net/ipv6/ip6_output.c:142 [inline] __ip6_finish_output+0x2d7/0x330 net/ipv6/ip6_output.c:127 ip6_finish_output+0x41/0x160 net/ipv6/ip6_output.c:152 NF_HOOK_COND include/linux/netfilter.h:294 [inline] ip6_output+0xf2/0x280 net/ipv6/ip6_output.c:175 dst_output include/net/dst.h:436 [inline] ip6_local_out+0x74/0x90 net/ipv6/output_core.c:179 ip6_send_skb+0x53/0x110 net/ipv6/ip6_output.c:1795 udp_v6_send_skb.isra.0+0x3ec/0xa70 net/ipv6/udp.c:1173 udpv6_sendmsg+0x1906/0x1c20 net/ipv6/udp.c:1471 inet6_sendmsg+0x6d/0x90 net/ipv6/af_inet6.c:576 sock_sendmsg_nosec net/socket.c:637 [inline] sock_sendmsg+0x9f/0xc0 net/socket.c:657 ___sys_sendmsg+0x2b7/0x5d0 net/socket.c:2311 __sys_sendmmsg+0x123/0x350 net/socket.c:2413 __do_sys_sendmmsg net/socket.c:2442 [inline] __se_sys_sendmmsg net/socket.c:2439 [inline] __x64_sys_sendmmsg+0x64/0x80 net/socket.c:2439 do_syscall_64+0xcc/0x370 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x44/0xa9 write to 0xffff8880b01786cc of 4 bytes by task 18922 on cpu 0: fanout_flow_is_huge net/packet/af_packet.c:1306 [inline] fanout_demux_rollover+0x3a4/0x3f0 net/packet/af_packet.c:1353 packet_rcv_fanout+0x34e/0x490 net/packet/af_packet.c:1453 deliver_skb net/core/dev.c:1888 [inline] dev_queue_xmit_nit+0x15b/0x540 net/core/dev.c:1958 xmit_one net/core/dev.c:3195 [inline] dev_hard_start_xmit+0x3f5/0x430 net/core/dev.c:3215 __dev_queue_xmit+0x14ab/0x1b40 net/core/dev.c:3792 dev_queue_xmit+0x21/0x30 net/core/dev.c:3825 neigh_direct_output+0x1f/0x30 net/core/neighbour.c:1530 neigh_output include/net/neighbour.h:511 [inline] ip6_finish_output2+0x7a2/0xec0 net/ipv6/ip6_output.c:116 __ip6_finish_output net/ipv6/ip6_output.c:142 [inline] __ip6_finish_output+0x2d7/0x330 net/ipv6/ip6_output.c:127 ip6_finish_output+0x41/0x160 net/ipv6/ip6_output.c:152 NF_HOOK_COND include/linux/netfilter.h:294 [inline] ip6_output+0xf2/0x280 net/ipv6/ip6_output.c:175 dst_output include/net/dst.h:436 [inline] ip6_local_out+0x74/0x90 net/ipv6/output_core.c:179 ip6_send_skb+0x53/0x110 net/ipv6/ip6_output.c:1795 udp_v6_send_skb.isra.0+0x3ec/0xa70 net/ipv6/udp.c:1173 udpv6_sendmsg+0x1906/0x1c20 net/ipv6/udp.c:1471 inet6_sendmsg+0x6d/0x90 net/ipv6/af_inet6.c:576 sock_sendmsg_nosec net/socket.c:637 [inline] sock_sendmsg+0x9f/0xc0 net/socket.c:657 ___sys_sendmsg+0x2b7/0x5d0 net/socket.c:2311 __sys_sendmmsg+0x123/0x350 net/socket.c:2413 __do_sys_sendmmsg net/socket.c:2442 [inline] __se_sys_sendmmsg net/socket.c:2439 [inline] __x64_sys_sendmmsg+0x64/0x80 net/socket.c:2439 do_syscall_64+0xcc/0x370 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Reported by Kernel Concurrency Sanitizer on: CPU: 0 PID: 18922 Comm: syz-executor.3 Not tainted 5.4.0-rc6+ #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Fixes: 3b3a5b0aab5b ("packet: rollover huge flows before small flows") Signed-off-by: Eric Dumazet Cc: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- net/packet/af_packet.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index e788f9c7c398..46b7fac82775 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1337,15 +1337,21 @@ static void packet_sock_destruct(struct sock *sk) static bool fanout_flow_is_huge(struct packet_sock *po, struct sk_buff *skb) { - u32 rxhash; + u32 *history = po->rollover->history; + u32 victim, rxhash; int i, count = 0; rxhash = skb_get_hash(skb); for (i = 0; i < ROLLOVER_HLEN; i++) - if (po->rollover->history[i] == rxhash) + if (READ_ONCE(history[i]) == rxhash) count++; - po->rollover->history[prandom_u32() % ROLLOVER_HLEN] = rxhash; + victim = prandom_u32() % ROLLOVER_HLEN; + + /* Avoid dirtying the cache line if possible */ + if (READ_ONCE(history[victim]) != rxhash) + WRITE_ONCE(history[victim], rxhash); + return count > (ROLLOVER_HLEN >> 1); } -- GitLab From 7effc7cf857317e78fdaa9111243ee9d24a8e80f Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Thu, 7 Nov 2019 11:30:42 +0100 Subject: [PATCH 0630/1055] mmc: sdio: fix wl1251 vendor id [ Upstream commit e5db673e7fe2f971ec82039a28dc0811c2100e87 ] v4.11-rc1 did introduce a patch series that rearranged the sdio quirks into a header file. Unfortunately this did forget to handle SDIO_VENDOR_ID_TI differently between wl1251 and wl1271 with the result that although the wl1251 was found on the sdio bus, the firmware did not load any more and there was no interface registration. This patch defines separate constants to be used by sdio quirks and drivers. Fixes: 884f38607897 ("mmc: core: move some sdio IDs out of quirks file") Signed-off-by: H. Nikolaus Schaller Cc: # v4.11+ Signed-off-by: Ulf Hansson Signed-off-by: Sasha Levin --- include/linux/mmc/sdio_ids.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 0a7abe8a407f..68bbbd9edc08 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -67,6 +67,8 @@ #define SDIO_VENDOR_ID_TI 0x0097 #define SDIO_DEVICE_ID_TI_WL1271 0x4076 +#define SDIO_VENDOR_ID_TI_WL1251 0x104c +#define SDIO_DEVICE_ID_TI_WL1251 0x9066 #define SDIO_VENDOR_ID_STE 0x0020 #define SDIO_DEVICE_ID_STE_CW1200 0x2280 -- GitLab From 8c17dd4b587bed444f1ea58bfc9bd90f44bf9db3 Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Thu, 7 Nov 2019 11:30:43 +0100 Subject: [PATCH 0631/1055] mmc: core: fix wl1251 sdio quirks [ Upstream commit 16568b4a4f0c34bd35cfadac63303c7af7812764 ] wl1251 and wl1271 have different vendor id and device id. So we need to handle both with sdio quirks. Fixes: 884f38607897 ("mmc: core: move some sdio IDs out of quirks file") Signed-off-by: H. Nikolaus Schaller Cc: # v4.11+ Signed-off-by: Ulf Hansson Signed-off-by: Sasha Levin --- drivers/mmc/core/quirks.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mmc/core/quirks.h b/drivers/mmc/core/quirks.h index 5153577754f0..09897abb79ed 100644 --- a/drivers/mmc/core/quirks.h +++ b/drivers/mmc/core/quirks.h @@ -119,7 +119,14 @@ static const struct mmc_fixup mmc_ext_csd_fixups[] = { END_FIXUP }; + static const struct mmc_fixup sdio_fixup_methods[] = { + SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251, + add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), + + SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251, + add_quirk, MMC_QUIRK_DISABLE_CD), + SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), -- GitLab From beb22d9386c3eab7938f6920e01768e98a3924e9 Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Wed, 2 Oct 2019 16:52:37 -0500 Subject: [PATCH 0632/1055] affs: fix a memory leak in affs_remount [ Upstream commit 450c3d4166837c496ebce03650c08800991f2150 ] In affs_remount if data is provided it is duplicated into new_opts. The allocated memory for new_opts is only released if parse_options fails. There's a bit of history behind new_options, originally there was save/replace options on the VFS layer so the 'data' passed must not change (thus strdup), this got cleaned up in later patches. But not completely. There's no reason to do the strdup in cases where the filesystem does not need to reuse the 'data' again, because strsep would modify it directly. Fixes: c8f33d0bec99 ("affs: kstrdup() memory handling") Signed-off-by: Navid Emamdoost [ update changelog ] Signed-off-by: David Sterba Signed-off-by: Sasha Levin --- fs/affs/super.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/fs/affs/super.c b/fs/affs/super.c index 884bedab7266..789a1c7db5d8 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -559,14 +559,9 @@ affs_remount(struct super_block *sb, int *flags, char *data) int root_block; unsigned long mount_flags; int res = 0; - char *new_opts; char volume[32]; char *prefix = NULL; - new_opts = kstrdup(data, GFP_KERNEL); - if (data && !new_opts) - return -ENOMEM; - pr_debug("%s(flags=0x%x,opts=\"%s\")\n", __func__, *flags, data); sync_filesystem(sb); @@ -577,7 +572,6 @@ affs_remount(struct super_block *sb, int *flags, char *data) &blocksize, &prefix, volume, &mount_flags)) { kfree(prefix); - kfree(new_opts); return -EINVAL; } -- GitLab From e3ba33cc5a94f5469865263bbb99c8ad3631ea3f Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Mon, 18 Nov 2019 15:38:02 +0800 Subject: [PATCH 0633/1055] dmaengine: ti: edma: fix missed failure handling [ Upstream commit 340049d453682a9fe8d91fe794dd091730f4bb25 ] When devm_kcalloc fails, it forgets to call edma_free_slot. Replace direct return with failure handler to fix it. Fixes: 1be5336bc7ba ("dmaengine: edma: New device tree binding") Signed-off-by: Chuhong Yuan Link: https://lore.kernel.org/r/20191118073802.28424-1-hslester96@gmail.com Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin --- drivers/dma/edma.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 519c24465dea..57a49fe713fd 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -2340,8 +2340,10 @@ static int edma_probe(struct platform_device *pdev) ecc->tc_list = devm_kcalloc(dev, ecc->num_tc, sizeof(*ecc->tc_list), GFP_KERNEL); - if (!ecc->tc_list) - return -ENOMEM; + if (!ecc->tc_list) { + ret = -ENOMEM; + goto err_reg1; + } for (i = 0;; i++) { ret = of_parse_phandle_with_fixed_args(node, "ti,tptcs", -- GitLab From 75262c4cc870f6ccf29d33d8758a826dc735e3cf Mon Sep 17 00:00:00 2001 From: Sam Bobroff Date: Mon, 18 Nov 2019 10:53:53 +1100 Subject: [PATCH 0634/1055] drm/radeon: fix bad DMA from INTERRUPT_CNTL2 [ Upstream commit 62d91dd2851e8ae2ca552f1b090a3575a4edf759 ] The INTERRUPT_CNTL2 register expects a valid DMA address, but is currently set with a GPU MC address. This can cause problems on systems that detect the resulting DMA read from an invalid address (found on a Power8 guest). Instead, use the DMA address of the dummy page because it will always be safe. Fixes: d8f60cfc9345 ("drm/radeon/kms: Add support for interrupts on r6xx/r7xx chips (v3)") Fixes: 25a857fbe973 ("drm/radeon/kms: add support for interrupts on SI") Fixes: a59781bbe528 ("drm/radeon: add support for interrupts on CIK (v5)") Signed-off-by: Sam Bobroff Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin --- drivers/gpu/drm/radeon/cik.c | 4 ++-- drivers/gpu/drm/radeon/r600.c | 4 ++-- drivers/gpu/drm/radeon/si.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index ce8b353b5753..ba31c7674fcd 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -7012,8 +7012,8 @@ static int cik_irq_init(struct radeon_device *rdev) } /* setup interrupt control */ - /* XXX this should actually be a bus address, not an MC address. same on older asics */ - WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8); + /* set dummy read address to dummy page address */ + WREG32(INTERRUPT_CNTL2, rdev->dummy_page.addr >> 8); interrupt_cntl = RREG32(INTERRUPT_CNTL); /* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index e06e2d8feab3..a724bb87cfad 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3690,8 +3690,8 @@ int r600_irq_init(struct radeon_device *rdev) } /* setup interrupt control */ - /* set dummy read address to ring address */ - WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8); + /* set dummy read address to dummy page address */ + WREG32(INTERRUPT_CNTL2, rdev->dummy_page.addr >> 8); interrupt_cntl = RREG32(INTERRUPT_CNTL); /* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 1907c950d76f..1144cafea9ac 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -5993,8 +5993,8 @@ static int si_irq_init(struct radeon_device *rdev) } /* setup interrupt control */ - /* set dummy read address to ring address */ - WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8); + /* set dummy read address to dummy page address */ + WREG32(INTERRUPT_CNTL2, rdev->dummy_page.addr >> 8); interrupt_cntl = RREG32(INTERRUPT_CNTL); /* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN -- GitLab From 602cfd269e9cf2fa1c2242985ac0406834389402 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Tue, 19 Nov 2019 12:03:31 +0000 Subject: [PATCH 0635/1055] arm64: dts: juno: Fix UART frequency [ Upstream commit 39a1a8941b27c37f79508426e27a2ec29829d66c ] Older versions of the Juno *SoC* TRM [1] recommended that the UART clock source should be 7.2738 MHz, whereas the *system* TRM [2] stated a more correct value of 7.3728 MHz. Somehow the wrong value managed to end up in our DT. Doing a prime factorisation, a modulo divide by 115200 and trying to buy a 7.2738 MHz crystal at your favourite electronics dealer suggest that the old value was actually a typo. The actual UART clock is driven by a PLL, configured via a parameter in some board.txt file in the firmware, which reads 7.37 MHz (sic!). Fix this to correct the baud rate divisor calculation on the Juno board. [1] http://infocenter.arm.com/help/topic/com.arm.doc.ddi0515b.b/DDI0515B_b_juno_arm_development_platform_soc_trm.pdf [2] http://infocenter.arm.com/help/topic/com.arm.doc.100113_0000_07_en/arm_versatile_express_juno_development_platform_(v2m_juno)_technical_reference_manual_100113_0000_07_en.pdf Fixes: 71f867ec130e ("arm64: Add Juno board device tree.") Signed-off-by: Andre Przywara Acked-by: Liviu Dudau Signed-off-by: Sudeep Holla Signed-off-by: Sasha Levin --- arch/arm64/boot/dts/arm/juno-clocks.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/arm/juno-clocks.dtsi b/arch/arm64/boot/dts/arm/juno-clocks.dtsi index e5e265dfa902..2870b5eeb198 100644 --- a/arch/arm64/boot/dts/arm/juno-clocks.dtsi +++ b/arch/arm64/boot/dts/arm/juno-clocks.dtsi @@ -8,10 +8,10 @@ */ / { /* SoC fixed clocks */ - soc_uartclk: refclk7273800hz { + soc_uartclk: refclk7372800hz { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <7273800>; + clock-frequency = <7372800>; clock-output-names = "juno:uartclk"; }; -- GitLab From 30987a4fd901be1a688feaf4b672d825ceffcd1c Mon Sep 17 00:00:00 2001 From: Max Gurtovoy Date: Tue, 26 Feb 2019 12:22:11 +0200 Subject: [PATCH 0636/1055] IB/iser: Fix dma_nents type definition [ Upstream commit c1545f1a200f4adc4ef8dd534bf33e2f1aa22c2f ] The retured value from ib_dma_map_sg saved in dma_nents variable. To avoid future mismatch between types, define dma_nents as an integer instead of unsigned. Fixes: 57b26497fabe ("IB/iser: Pass the correct number of entries for dma mapped SGL") Reported-by: Dan Carpenter Reviewed-by: Israel Rukshin Signed-off-by: Max Gurtovoy Acked-by: Sagi Grimberg Reviewed-by: Dan Carpenter Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin --- drivers/infiniband/ulp/iser/iscsi_iser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index c1ae4aeae2f9..46dfc6ae9d1c 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -197,7 +197,7 @@ struct iser_data_buf { struct scatterlist *sg; int size; unsigned long data_len; - unsigned int dma_nents; + int dma_nents; }; /* fwd declarations */ -- GitLab From 7c662630d94fc07da206a8423bfbf9c2330bb2c8 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 21 Nov 2019 09:10:49 +0100 Subject: [PATCH 0637/1055] serial: stm32: fix clearing interrupt error flags [ Upstream commit 1250ed7114a977cdc2a67a0c09d6cdda63970eb9 ] The interrupt clear flag register is a "write 1 to clear" register. So, only writing ones allows to clear flags: - Replace buggy stm32_clr_bits() by a simple write to clear error flags - Replace useless read/modify/write stm32_set_bits() routine by a simple write to clear TC (transfer complete) flag. Fixes: 4f01d833fdcd ("serial: stm32: fix rx error handling") Signed-off-by: Fabrice Gasnier Cc: stable Link: https://lore.kernel.org/r/1574323849-1909-1-git-send-email-fabrice.gasnier@st.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/tty/serial/stm32-usart.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index f8f3f8fafd9f..1e854e1851fb 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -132,8 +132,8 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) * cleared by the sequence [read SR - read DR]. */ if ((sr & USART_SR_ERR_MASK) && ofs->icr != UNDEF_REG) - stm32_clr_bits(port, ofs->icr, USART_ICR_ORECF | - USART_ICR_PECF | USART_ICR_FECF); + writel_relaxed(sr & USART_SR_ERR_MASK, + port->membase + ofs->icr); c = stm32_get_char(port, &sr, &stm32_port->last_res); port->icount.rx++; @@ -302,7 +302,7 @@ static void stm32_transmit_chars(struct uart_port *port) if (ofs->icr == UNDEF_REG) stm32_clr_bits(port, ofs->isr, USART_SR_TC); else - stm32_set_bits(port, ofs->icr, USART_ICR_TCCF); + writel_relaxed(USART_ICR_TCCF, port->membase + ofs->icr); if (stm32_port->tx_ch) stm32_transmit_chars_dma(port); -- GitLab From 4127249099b796b1fd5c74562ce94b94cda38553 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sat, 1 Dec 2018 11:53:10 +1100 Subject: [PATCH 0638/1055] m68k: Call timer_interrupt() with interrupts disabled [ Upstream commit 1efdd4bd254311498123a15fa0acd565f454da97 ] Some platforms execute their timer handler with the interrupt priority level set below 6. That means the handler could be interrupted by another driver and this could lead to re-entry of the timer core. Avoid this by use of local_irq_save/restore for timer interrupt dispatch. This provides mutual exclusion around the timer interrupt flag access which is needed later in this series for the clocksource conversion. Reported-by: Thomas Gleixner Link: http://lkml.kernel.org/r/alpine.DEB.2.21.1811131407120.2697@nanos.tec.linutronix.de Signed-off-by: Finn Thain Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin --- arch/m68k/amiga/cia.c | 9 +++++++++ arch/m68k/atari/ataints.c | 4 ++-- arch/m68k/atari/time.c | 15 ++++++++++++++- arch/m68k/bvme6000/config.c | 20 ++++++++++---------- arch/m68k/hp300/time.c | 10 ++++++++-- arch/m68k/mac/via.c | 17 +++++++++++++++++ arch/m68k/mvme147/config.c | 18 ++++++++++-------- arch/m68k/mvme16x/config.c | 21 +++++++++++---------- arch/m68k/q40/q40ints.c | 19 +++++++++++-------- arch/m68k/sun3/sun3ints.c | 3 +++ arch/m68k/sun3x/time.c | 16 ++++++++++------ 11 files changed, 105 insertions(+), 47 deletions(-) diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c index 2081b8cd5591..b9aee983e6f4 100644 --- a/arch/m68k/amiga/cia.c +++ b/arch/m68k/amiga/cia.c @@ -88,10 +88,19 @@ static irqreturn_t cia_handler(int irq, void *dev_id) struct ciabase *base = dev_id; int mach_irq; unsigned char ints; + unsigned long flags; + /* Interrupts get disabled while the timer irq flag is cleared and + * the timer interrupt serviced. + */ mach_irq = base->cia_irq; + local_irq_save(flags); ints = cia_set_irq(base, CIA_ICR_ALL); amiga_custom.intreq = base->int_mask; + if (ints & 1) + generic_handle_irq(mach_irq); + local_irq_restore(flags); + mach_irq++, ints >>= 1; for (; ints; mach_irq++, ints >>= 1) { if (ints & 1) generic_handle_irq(mach_irq); diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index 3d2b63bedf05..56f02ea2c248 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c @@ -142,7 +142,7 @@ struct mfptimerbase { .name = "MFP Timer D" }; -static irqreturn_t mfptimer_handler(int irq, void *dev_id) +static irqreturn_t mfp_timer_d_handler(int irq, void *dev_id) { struct mfptimerbase *base = dev_id; int mach_irq; @@ -344,7 +344,7 @@ void __init atari_init_IRQ(void) st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6; /* request timer D dispatch handler */ - if (request_irq(IRQ_MFP_TIMD, mfptimer_handler, IRQF_SHARED, + if (request_irq(IRQ_MFP_TIMD, mfp_timer_d_handler, IRQF_SHARED, stmfp_base.name, &stmfp_base)) pr_err("Couldn't register %s interrupt\n", stmfp_base.name); diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c index c549b48174ec..972181c1fe4b 100644 --- a/arch/m68k/atari/time.c +++ b/arch/m68k/atari/time.c @@ -24,6 +24,18 @@ DEFINE_SPINLOCK(rtc_lock); EXPORT_SYMBOL_GPL(rtc_lock); +static irqreturn_t mfp_timer_c_handler(int irq, void *dev_id) +{ + irq_handler_t timer_routine = dev_id; + unsigned long flags; + + local_irq_save(flags); + timer_routine(0, NULL); + local_irq_restore(flags); + + return IRQ_HANDLED; +} + void __init atari_sched_init(irq_handler_t timer_routine) { @@ -32,7 +44,8 @@ atari_sched_init(irq_handler_t timer_routine) /* start timer C, div = 1:100 */ st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60; /* install interrupt service routine for MFP Timer C */ - if (request_irq(IRQ_MFP_TIMC, timer_routine, 0, "timer", timer_routine)) + if (request_irq(IRQ_MFP_TIMC, mfp_timer_c_handler, 0, "timer", + timer_routine)) pr_err("Couldn't register timer interrupt\n"); } diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c index 2cfff4765040..0e602c32b246 100644 --- a/arch/m68k/bvme6000/config.c +++ b/arch/m68k/bvme6000/config.c @@ -45,11 +45,6 @@ extern int bvme6000_set_clock_mmss (unsigned long); extern void bvme6000_reset (void); void bvme6000_set_vectors (void); -/* Save tick handler routine pointer, will point to xtime_update() in - * kernel/timer/timekeeping.c, called via bvme6000_process_int() */ - -static irq_handler_t tick_handler; - int __init bvme6000_parse_bootinfo(const struct bi_record *bi) { @@ -159,12 +154,18 @@ irqreturn_t bvme6000_abort_int (int irq, void *dev_id) static irqreturn_t bvme6000_timer_int (int irq, void *dev_id) { + irq_handler_t timer_routine = dev_id; + unsigned long flags; volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE; - unsigned char msr = rtc->msr & 0xc0; + unsigned char msr; + local_irq_save(flags); + msr = rtc->msr & 0xc0; rtc->msr = msr | 0x20; /* Ack the interrupt */ + timer_routine(0, NULL); + local_irq_restore(flags); - return tick_handler(irq, dev_id); + return IRQ_HANDLED; } /* @@ -183,9 +184,8 @@ void bvme6000_sched_init (irq_handler_t timer_routine) rtc->msr = 0; /* Ensure timer registers accessible */ - tick_handler = timer_routine; - if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0, - "timer", bvme6000_timer_int)) + if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0, "timer", + timer_routine)) panic ("Couldn't register timer int"); rtc->t1cr_omr = 0x04; /* Mode 2, ext clk */ diff --git a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c index 289d928a46cb..d30b03ea93a2 100644 --- a/arch/m68k/hp300/time.c +++ b/arch/m68k/hp300/time.c @@ -38,13 +38,19 @@ static irqreturn_t hp300_tick(int irq, void *dev_id) { + irq_handler_t timer_routine = dev_id; + unsigned long flags; unsigned long tmp; - irq_handler_t vector = dev_id; + + local_irq_save(flags); in_8(CLOCKBASE + CLKSR); asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE)); + timer_routine(0, NULL); + local_irq_restore(flags); + /* Turn off the network and SCSI leds */ blinken_leds(0, 0xe0); - return vector(irq, NULL); + return IRQ_HANDLED; } u32 hp300_gettimeoffset(void) diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index 7334245abf26..863806e6775a 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -398,6 +398,8 @@ void via_nubus_irq_shutdown(int irq) * via6522.c :-), disable/pending masks added. */ +#define VIA_TIMER_1_INT BIT(6) + void via1_irq(struct irq_desc *desc) { int irq_num; @@ -407,6 +409,21 @@ void via1_irq(struct irq_desc *desc) if (!events) return; + irq_num = IRQ_MAC_TIMER_1; + irq_bit = VIA_TIMER_1_INT; + if (events & irq_bit) { + unsigned long flags; + + local_irq_save(flags); + via1[vIFR] = irq_bit; + generic_handle_irq(irq_num); + local_irq_restore(flags); + + events &= ~irq_bit; + if (!events) + return; + } + irq_num = VIA1_SOURCE_BASE; irq_bit = 1; do { diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c index 8778612d1f31..78ae803c833e 100644 --- a/arch/m68k/mvme147/config.c +++ b/arch/m68k/mvme147/config.c @@ -46,11 +46,6 @@ extern void mvme147_reset (void); static int bcd2int (unsigned char b); -/* Save tick handler routine pointer, will point to xtime_update() in - * kernel/time/timekeeping.c, called via mvme147_process_int() */ - -irq_handler_t tick_handler; - int __init mvme147_parse_bootinfo(const struct bi_record *bi) { @@ -106,16 +101,23 @@ void __init config_mvme147(void) static irqreturn_t mvme147_timer_int (int irq, void *dev_id) { + irq_handler_t timer_routine = dev_id; + unsigned long flags; + + local_irq_save(flags); m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR; m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1; - return tick_handler(irq, dev_id); + timer_routine(0, NULL); + local_irq_restore(flags); + + return IRQ_HANDLED; } void mvme147_sched_init (irq_handler_t timer_routine) { - tick_handler = timer_routine; - if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, 0, "timer 1", NULL)) + if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, 0, "timer 1", + timer_routine)) pr_err("Couldn't register timer interrupt\n"); /* Init the clock with a value */ diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c index 6fa06d4d16bf..3116dd576bb3 100644 --- a/arch/m68k/mvme16x/config.c +++ b/arch/m68k/mvme16x/config.c @@ -51,11 +51,6 @@ extern void mvme16x_reset (void); int bcd2int (unsigned char b); -/* Save tick handler routine pointer, will point to xtime_update() in - * kernel/time/timekeeping.c, called via mvme16x_process_int() */ - -static irq_handler_t tick_handler; - unsigned short mvme16x_config; EXPORT_SYMBOL(mvme16x_config); @@ -354,8 +349,15 @@ static irqreturn_t mvme16x_abort_int (int irq, void *dev_id) static irqreturn_t mvme16x_timer_int (int irq, void *dev_id) { - *(volatile unsigned char *)0xfff4201b |= 8; - return tick_handler(irq, dev_id); + irq_handler_t timer_routine = dev_id; + unsigned long flags; + + local_irq_save(flags); + *(volatile unsigned char *)0xfff4201b |= 8; + timer_routine(0, NULL); + local_irq_restore(flags); + + return IRQ_HANDLED; } void mvme16x_sched_init (irq_handler_t timer_routine) @@ -363,14 +365,13 @@ void mvme16x_sched_init (irq_handler_t timer_routine) uint16_t brdno = be16_to_cpu(mvme_bdid.brdno); int irq; - tick_handler = timer_routine; /* Using PCCchip2 or MC2 chip tick timer 1 */ *(volatile unsigned long *)0xfff42008 = 0; *(volatile unsigned long *)0xfff42004 = 10000; /* 10ms */ *(volatile unsigned char *)0xfff42017 |= 3; *(volatile unsigned char *)0xfff4201b = 0x16; - if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0, - "timer", mvme16x_timer_int)) + if (request_irq(MVME16x_IRQ_TIMER, mvme16x_timer_int, 0, "timer", + timer_routine)) panic ("Couldn't register timer int"); if (brdno == 0x0162 || brdno == 0x172) diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c index 3e7603202977..1c696906c159 100644 --- a/arch/m68k/q40/q40ints.c +++ b/arch/m68k/q40/q40ints.c @@ -127,10 +127,10 @@ void q40_mksound(unsigned int hz, unsigned int ticks) sound_ticks = ticks << 1; } -static irq_handler_t q40_timer_routine; - -static irqreturn_t q40_timer_int (int irq, void * dev) +static irqreturn_t q40_timer_int(int irq, void *dev_id) { + irq_handler_t timer_routine = dev_id; + ql_ticks = ql_ticks ? 0 : 1; if (sound_ticks) { unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL; @@ -139,8 +139,13 @@ static irqreturn_t q40_timer_int (int irq, void * dev) *DAC_RIGHT=sval; } - if (!ql_ticks) - q40_timer_routine(irq, dev); + if (!ql_ticks) { + unsigned long flags; + + local_irq_save(flags); + timer_routine(0, NULL); + local_irq_restore(flags); + } return IRQ_HANDLED; } @@ -148,11 +153,9 @@ void q40_sched_init (irq_handler_t timer_routine) { int timer_irq; - q40_timer_routine = timer_routine; timer_irq = Q40_IRQ_FRAME; - if (request_irq(timer_irq, q40_timer_int, 0, - "timer", q40_timer_int)) + if (request_irq(timer_irq, q40_timer_int, 0, "timer", timer_routine)) panic("Couldn't register timer int"); master_outb(-1, FRAME_CLEAR_REG); diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c index 6bbca30c9188..a5824abb4a39 100644 --- a/arch/m68k/sun3/sun3ints.c +++ b/arch/m68k/sun3/sun3ints.c @@ -61,8 +61,10 @@ static irqreturn_t sun3_int7(int irq, void *dev_id) static irqreturn_t sun3_int5(int irq, void *dev_id) { + unsigned long flags; unsigned int cnt; + local_irq_save(flags); #ifdef CONFIG_SUN3 intersil_clear(); #endif @@ -76,6 +78,7 @@ static irqreturn_t sun3_int5(int irq, void *dev_id) cnt = kstat_irqs_cpu(irq, 0); if (!(cnt % 20)) sun3_leds(led_pattern[cnt % 160 / 20]); + local_irq_restore(flags); return IRQ_HANDLED; } diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c index 7a2c53d9f779..48b43903253e 100644 --- a/arch/m68k/sun3x/time.c +++ b/arch/m68k/sun3x/time.c @@ -78,15 +78,19 @@ u32 sun3x_gettimeoffset(void) } #if 0 -static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t sun3x_timer_tick(int irq, void *dev_id) { - void (*vector)(int, void *, struct pt_regs *) = dev_id; + irq_handler_t timer_routine = dev_id; + unsigned long flags; - /* Clear the pending interrupt - pulse the enable line low */ - disable_irq(5); - enable_irq(5); + local_irq_save(flags); + /* Clear the pending interrupt - pulse the enable line low */ + disable_irq(5); + enable_irq(5); + timer_routine(0, NULL); + local_irq_restore(flags); - vector(irq, NULL, regs); + return IRQ_HANDLED; } #endif -- GitLab From 9a95f25269bd9257ab9fba7bb14355d50b5f39ec Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 27 Jan 2020 14:46:54 +0100 Subject: [PATCH 0639/1055] Linux 4.14.168 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b538e6170f73..1e74ba09cdda 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 167 +SUBLEVEL = 168 EXTRAVERSION = NAME = Petit Gorille -- GitLab From a637b674ce4beb5f9d34b68cb0eb3e009c1e8b88 Mon Sep 17 00:00:00 2001 From: Alistair Delva Date: Tue, 28 Jan 2020 12:35:12 -0800 Subject: [PATCH 0640/1055] ANDROID: cuttlefish_defconfig: Enable CONFIG_BTT Without this, the virtio_pmem driver does not seem to work. Bug: 146400078 Change-Id: I2689aa4739b83a0a5a0e9930dc50b57e4f612525 Signed-off-by: Alistair Delva --- 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 d0a8c06670c1..7fd46d9c1629 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -422,7 +422,6 @@ CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_LIBNVDIMM=y # CONFIG_ND_BLK is not set -# CONFIG_BTT is not set CONFIG_ARM_SCPI_PROTOCOL=y # CONFIG_ARM_SCPI_POWER_DOMAIN is not set CONFIG_EXT4_FS=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 022325173f80..ca27bedba3bf 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -436,7 +436,6 @@ CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_LIBNVDIMM=y # CONFIG_ND_BLK is not set -# CONFIG_BTT is not set # CONFIG_FIRMWARE_MEMMAP is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y -- GitLab From 318babce66a62d8bc8d5434909a044b89ab3a53e Mon Sep 17 00:00:00 2001 From: Eugene Zemtsov Date: Mon, 18 Nov 2019 20:21:06 -0800 Subject: [PATCH 0641/1055] ANDROID: Initial commit of Incremental FS Fully working incremental fs filesystem Signed-off-by: Eugene Zemtsov Signed-off-by: Paul Lawrence Bug: 133435829 Change-Id: I14741a61ce7891a0f9054e70f026917712cbef78 --- fs/Kconfig | 1 + fs/Makefile | 1 + fs/incfs/Kconfig | 18 + fs/incfs/Makefile | 9 + fs/incfs/compat.h | 33 + fs/incfs/data_mgmt.c | 1142 ++++++++ fs/incfs/data_mgmt.h | 339 +++ fs/incfs/format.c | 696 +++++ fs/incfs/format.h | 349 +++ fs/incfs/integrity.c | 217 ++ fs/incfs/integrity.h | 72 + fs/incfs/internal.h | 21 + fs/incfs/main.c | 103 + fs/incfs/vfs.c | 2203 +++++++++++++++ fs/incfs/vfs.h | 13 + include/uapi/linux/incrementalfs.h | 244 ++ .../selftests/filesystems/incfs/Makefile | 16 + .../selftests/filesystems/incfs/config | 1 + .../selftests/filesystems/incfs/incfs_test.c | 2420 +++++++++++++++++ .../selftests/filesystems/incfs/utils.c | 377 +++ .../selftests/filesystems/incfs/utils.h | 59 + 21 files changed, 8334 insertions(+) create mode 100644 fs/incfs/Kconfig create mode 100644 fs/incfs/Makefile create mode 100644 fs/incfs/compat.h create mode 100644 fs/incfs/data_mgmt.c create mode 100644 fs/incfs/data_mgmt.h create mode 100644 fs/incfs/format.c create mode 100644 fs/incfs/format.h create mode 100644 fs/incfs/integrity.c create mode 100644 fs/incfs/integrity.h create mode 100644 fs/incfs/internal.h create mode 100644 fs/incfs/main.c create mode 100644 fs/incfs/vfs.c create mode 100644 fs/incfs/vfs.h create mode 100644 include/uapi/linux/incrementalfs.h create mode 100644 tools/testing/selftests/filesystems/incfs/Makefile create mode 100644 tools/testing/selftests/filesystems/incfs/config create mode 100644 tools/testing/selftests/filesystems/incfs/incfs_test.c create mode 100644 tools/testing/selftests/filesystems/incfs/utils.c create mode 100644 tools/testing/selftests/filesystems/incfs/utils.h diff --git a/fs/Kconfig b/fs/Kconfig index 6da435421744..1c1ed36c36c2 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -106,6 +106,7 @@ source "fs/quota/Kconfig" source "fs/autofs4/Kconfig" source "fs/fuse/Kconfig" source "fs/overlayfs/Kconfig" +source "fs/incfs/Kconfig" menu "Caches" diff --git a/fs/Makefile b/fs/Makefile index 3204be31dad1..580e49be1219 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -111,6 +111,7 @@ obj-$(CONFIG_ADFS_FS) += adfs/ obj-$(CONFIG_FUSE_FS) += fuse/ obj-$(CONFIG_OVERLAY_FS) += overlayfs/ obj-$(CONFIG_ORANGEFS_FS) += orangefs/ +obj-$(CONFIG_INCREMENTAL_FS) += incfs/ obj-$(CONFIG_UDF_FS) += udf/ obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ obj-$(CONFIG_OMFS_FS) += omfs/ diff --git a/fs/incfs/Kconfig b/fs/incfs/Kconfig new file mode 100644 index 000000000000..d860c07664c3 --- /dev/null +++ b/fs/incfs/Kconfig @@ -0,0 +1,18 @@ +config INCREMENTAL_FS + tristate "Incremental file system support" + depends on BLOCK + select DECOMPRESS_LZ4 + select CRC32 + select CRYPTO + select CRYPTO_SHA256 + select X509_CERTIFICATE_PARSER + select ASYMMETRIC_KEY_TYPE + select ASYMMETRIC_PUBLIC_KEY_SUBTYPE + select PKCS7_MESSAGE_PARSER + help + Incremental FS is a read-only virtual file system that facilitates execution + of programs while their binaries are still being lazily downloaded over the + network, USB or pigeon post. + + To compile this file system support as a module, choose M here: the + module will be called incrementalfs. diff --git a/fs/incfs/Makefile b/fs/incfs/Makefile new file mode 100644 index 000000000000..8d734bf91ecd --- /dev/null +++ b/fs/incfs/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_INCREMENTAL_FS) += incrementalfs.o + +incrementalfs-y := \ + data_mgmt.o \ + format.o \ + integrity.o \ + main.o \ + vfs.o diff --git a/fs/incfs/compat.h b/fs/incfs/compat.h new file mode 100644 index 000000000000..f6fd9b2b3cb2 --- /dev/null +++ b/fs/incfs/compat.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ +#ifndef _INCFS_COMPAT_H +#define _INCFS_COMPAT_H + +#include +#include + +typedef unsigned int __poll_t; + +#ifndef u64_to_user_ptr +#define u64_to_user_ptr(x) ( \ +{ \ + typecheck(u64, x); \ + (void __user *)(uintptr_t)x; \ +} \ +) +#endif + +#ifndef lru_to_page +#define lru_to_page(head) (list_entry((head)->prev, struct page, lru)) +#endif + +#define readahead_gfp_mask(x) \ + (mapping_gfp_mask(x) | __GFP_NORETRY | __GFP_NOWARN) + +#ifndef SB_ACTIVE +#define SB_ACTIVE MS_ACTIVE +#endif + +#endif /* _INCFS_COMPAT_H */ diff --git a/fs/incfs/data_mgmt.c b/fs/incfs/data_mgmt.c new file mode 100644 index 000000000000..25ea1099946d --- /dev/null +++ b/fs/incfs/data_mgmt.c @@ -0,0 +1,1142 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "data_mgmt.h" +#include "format.h" +#include "integrity.h" + +struct mount_info *incfs_alloc_mount_info(struct super_block *sb, + struct mount_options *options, + struct path *backing_dir_path) +{ + struct mount_info *mi = NULL; + int error = 0; + + mi = kzalloc(sizeof(*mi), GFP_NOFS); + if (!mi) + return ERR_PTR(-ENOMEM); + + mi->mi_sb = sb; + mi->mi_options = *options; + mi->mi_backing_dir_path = *backing_dir_path; + mi->mi_owner = get_current_cred(); + path_get(&mi->mi_backing_dir_path); + mutex_init(&mi->mi_dir_struct_mutex); + mutex_init(&mi->mi_pending_reads_mutex); + init_waitqueue_head(&mi->mi_pending_reads_notif_wq); + INIT_LIST_HEAD(&mi->mi_reads_list_head); + + if (options->read_log_pages != 0) { + size_t buf_size = PAGE_SIZE * options->read_log_pages; + + spin_lock_init(&mi->mi_log.rl_writer_lock); + init_waitqueue_head(&mi->mi_log.ml_notif_wq); + + mi->mi_log.rl_size = buf_size / sizeof(*mi->mi_log.rl_ring_buf); + mi->mi_log.rl_ring_buf = kzalloc(buf_size, GFP_NOFS); + if (!mi->mi_log.rl_ring_buf) { + error = -ENOMEM; + goto err; + } + } + + return mi; + +err: + incfs_free_mount_info(mi); + return ERR_PTR(error); +} + +void incfs_free_mount_info(struct mount_info *mi) +{ + if (!mi) + return; + + dput(mi->mi_index_dir); + path_put(&mi->mi_backing_dir_path); + mutex_destroy(&mi->mi_dir_struct_mutex); + mutex_destroy(&mi->mi_pending_reads_mutex); + put_cred(mi->mi_owner); + kfree(mi->mi_log.rl_ring_buf); + kfree(mi); +} + +static void data_file_segment_init(struct data_file_segment *segment) +{ + init_waitqueue_head(&segment->new_data_arrival_wq); + mutex_init(&segment->blockmap_mutex); + INIT_LIST_HEAD(&segment->reads_list_head); +} + +static void data_file_segment_destroy(struct data_file_segment *segment) +{ + mutex_destroy(&segment->blockmap_mutex); +} + +struct data_file *incfs_open_data_file(struct mount_info *mi, struct file *bf) +{ + struct data_file *df = NULL; + struct backing_file_context *bfc = NULL; + int md_records; + u64 size; + int error = 0; + int i; + + if (!bf || !mi) + return ERR_PTR(-EFAULT); + + if (!S_ISREG(bf->f_inode->i_mode)) + return ERR_PTR(-EBADF); + + bfc = incfs_alloc_bfc(bf); + if (IS_ERR(bfc)) + return ERR_CAST(bfc); + + df = kzalloc(sizeof(*df), GFP_NOFS); + if (!df) { + error = -ENOMEM; + goto out; + } + + df->df_backing_file_context = bfc; + df->df_mount_info = mi; + for (i = 0; i < ARRAY_SIZE(df->df_segments); i++) + data_file_segment_init(&df->df_segments[i]); + + error = mutex_lock_interruptible(&bfc->bc_mutex); + if (error) + goto out; + error = incfs_read_file_header(bfc, &df->df_metadata_off, + &df->df_id, &size); + mutex_unlock(&bfc->bc_mutex); + + if (error) + goto out; + + df->df_size = size; + if (size > 0) + df->df_block_count = get_blocks_count_for_size(size); + + md_records = incfs_scan_metadata_chain(df); + if (md_records < 0) + error = md_records; + +out: + if (error) { + incfs_free_bfc(bfc); + df->df_backing_file_context = NULL; + incfs_free_data_file(df); + return ERR_PTR(error); + } + return df; +} + +void incfs_free_data_file(struct data_file *df) +{ + int i; + + if (!df) + return; + + incfs_free_mtree(df->df_hash_tree); + for (i = 0; i < ARRAY_SIZE(df->df_segments); i++) + data_file_segment_destroy(&df->df_segments[i]); + incfs_free_bfc(df->df_backing_file_context); + kfree(df); +} + +int make_inode_ready_for_data_ops(struct mount_info *mi, + struct inode *inode, + struct file *backing_file) +{ + struct inode_info *node = get_incfs_node(inode); + struct data_file *df = NULL; + int err = 0; + + inode_lock(inode); + if (S_ISREG(inode->i_mode)) { + if (!node->n_file) { + df = incfs_open_data_file(mi, backing_file); + + if (IS_ERR(df)) + err = PTR_ERR(df); + else + node->n_file = df; + } + } else + err = -EBADF; + inode_unlock(inode); + return err; +} + +struct dir_file *incfs_open_dir_file(struct mount_info *mi, struct file *bf) +{ + struct dir_file *dir = NULL; + + if (!S_ISDIR(bf->f_inode->i_mode)) + return ERR_PTR(-EBADF); + + dir = kzalloc(sizeof(*dir), GFP_NOFS); + if (!dir) + return ERR_PTR(-ENOMEM); + + dir->backing_dir = get_file(bf); + dir->mount_info = mi; + return dir; +} + +void incfs_free_dir_file(struct dir_file *dir) +{ + if (!dir) + return; + if (dir->backing_dir) + fput(dir->backing_dir); + kfree(dir); +} + +static ssize_t decompress(struct mem_range src, struct mem_range dst) +{ + int result = LZ4_decompress_safe(src.data, dst.data, src.len, dst.len); + + if (result < 0) + return -EBADMSG; + + return result; +} + +static void log_block_read(struct mount_info *mi, incfs_uuid_t *id, + int block_index, bool timed_out) +{ + struct read_log *log = &mi->mi_log; + struct read_log_state state; + s64 now_us = ktime_to_us(ktime_get()); + struct read_log_record record = { + .file_id = *id, + .block_index = block_index, + .timed_out = timed_out, + .timestamp_us = now_us + }; + + if (log->rl_size == 0) + return; + + spin_lock(&log->rl_writer_lock); + state = READ_ONCE(log->rl_state); + log->rl_ring_buf[state.next_index] = record; + if (++state.next_index == log->rl_size) { + state.next_index = 0; + ++state.current_pass_no; + } + WRITE_ONCE(log->rl_state, state); + spin_unlock(&log->rl_writer_lock); + + wake_up_all(&log->ml_notif_wq); +} + +static int validate_hash_tree(struct file *bf, struct data_file *df, + int block_index, struct mem_range data, u8 *buf) +{ + u8 digest[INCFS_MAX_HASH_SIZE] = {}; + struct mtree *tree = NULL; + struct ondisk_signature *sig = NULL; + struct mem_range calc_digest_rng; + struct mem_range saved_digest_rng; + struct mem_range root_hash_rng; + int digest_size; + int hash_block_index = block_index; + int hash_per_block; + int lvl = 0; + int res; + + tree = df->df_hash_tree; + sig = df->df_signature; + if (!tree || !sig) + return 0; + + digest_size = tree->alg->digest_size; + hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size; + calc_digest_rng = range(digest, digest_size); + res = incfs_calc_digest(tree->alg, data, calc_digest_rng); + if (res) + return res; + + for (lvl = 0; lvl < tree->depth; lvl++) { + loff_t lvl_off = tree->hash_level_suboffset[lvl] + + sig->mtree_offset; + loff_t hash_block_off = lvl_off + + round_down(hash_block_index * digest_size, + INCFS_DATA_FILE_BLOCK_SIZE); + size_t hash_off_in_block = hash_block_index * digest_size + % INCFS_DATA_FILE_BLOCK_SIZE; + struct mem_range buf_range = range(buf, + INCFS_DATA_FILE_BLOCK_SIZE); + ssize_t read_res = incfs_kread(bf, buf, + INCFS_DATA_FILE_BLOCK_SIZE, hash_block_off); + + if (read_res < 0) + return read_res; + if (read_res != INCFS_DATA_FILE_BLOCK_SIZE) + return -EIO; + + saved_digest_rng = range(buf + hash_off_in_block, digest_size); + if (!incfs_equal_ranges(calc_digest_rng, saved_digest_rng)) { + int i; + bool zero = true; + + pr_debug("incfs: Hash mismatch lvl:%d blk:%d\n", + lvl, block_index); + for (i = 0; i < saved_digest_rng.len; ++i) + if (saved_digest_rng.data[i]) { + zero = false; + break; + } + + if (zero) + pr_debug("incfs: Note saved_digest all zero - did you forget to load the hashes?\n"); + return -EBADMSG; + } + + res = incfs_calc_digest(tree->alg, buf_range, calc_digest_rng); + if (res) + return res; + hash_block_index /= hash_per_block; + } + + root_hash_rng = range(tree->root_hash, digest_size); + if (!incfs_equal_ranges(calc_digest_rng, root_hash_rng)) { + pr_debug("incfs: Root hash mismatch blk:%d\n", block_index); + return -EBADMSG; + } + return 0; +} + +static int revalidate_signature(struct file *bf, struct data_file *df) +{ + struct ondisk_signature *sig = df->df_signature; + struct mem_range root_hash = {}; + int result = 0; + u8 *sig_buf = NULL; + u8 *add_data_buf = NULL; + ssize_t read_res; + + /* File has no signature. */ + if (!sig || !df->df_hash_tree || sig->sig_size == 0) + return 0; + + /* Signature has already been validated. */ + if (df->df_signature_validated) + return 0; + + add_data_buf = kzalloc(sig->add_data_size, GFP_NOFS); + if (!add_data_buf) { + result = -ENOMEM; + goto out; + } + + read_res = incfs_kread(bf, add_data_buf, sig->add_data_size, + sig->add_data_offset); + if (read_res < 0) { + result = read_res; + goto out; + } + if (read_res != sig->add_data_size) { + result = -EIO; + goto out; + } + + sig_buf = kzalloc(sig->sig_size, GFP_NOFS); + if (!sig_buf) { + result = -ENOMEM; + goto out; + } + + read_res = incfs_kread(bf, sig_buf, sig->sig_size, sig->sig_offset); + if (read_res < 0) { + result = read_res; + goto out; + } + if (read_res != sig->sig_size) { + result = -EIO; + goto out; + } + + root_hash = range(df->df_hash_tree->root_hash, + df->df_hash_tree->alg->digest_size); + + result = incfs_validate_pkcs7_signature( + range(sig_buf, sig->sig_size), + root_hash, + range(add_data_buf, sig->add_data_size)); + + if (result == 0) + df->df_signature_validated = true; +out: + kfree(sig_buf); + kfree(add_data_buf); + return result; +} + +static struct data_file_segment *get_file_segment(struct data_file *df, + int block_index) +{ + int seg_idx = block_index % ARRAY_SIZE(df->df_segments); + + return &df->df_segments[seg_idx]; +} + +static bool is_data_block_present(struct data_file_block *block) +{ + return (block->db_backing_file_data_offset != 0) && + (block->db_stored_size != 0); +} + +static int get_data_file_block(struct data_file *df, int index, + struct data_file_block *res_block) +{ + struct incfs_blockmap_entry bme = {}; + struct backing_file_context *bfc = NULL; + loff_t blockmap_off = 0; + u16 flags = 0; + int error = 0; + + if (!df || !res_block) + return -EFAULT; + + blockmap_off = df->df_blockmap_off; + bfc = df->df_backing_file_context; + + if (index < 0 || index >= df->df_block_count || blockmap_off == 0) + return -EINVAL; + + error = incfs_read_blockmap_entry(bfc, index, blockmap_off, &bme); + if (error) + return error; + + flags = le16_to_cpu(bme.me_flags); + res_block->db_backing_file_data_offset = + le16_to_cpu(bme.me_data_offset_hi); + res_block->db_backing_file_data_offset <<= 32; + res_block->db_backing_file_data_offset |= + le32_to_cpu(bme.me_data_offset_lo); + res_block->db_stored_size = le16_to_cpu(bme.me_data_size); + res_block->db_comp_alg = (flags & INCFS_BLOCK_COMPRESSED_LZ4) ? + COMPRESSION_LZ4 : + COMPRESSION_NONE; + return 0; +} + +static bool is_read_done(struct pending_read *read) +{ + return atomic_read_acquire(&read->done) != 0; +} + +static void set_read_done(struct pending_read *read) +{ + atomic_set_release(&read->done, 1); +} + +/* + * Notifies a given data file about pending read from a given block. + * Returns a new pending read entry. + */ +static struct pending_read *add_pending_read(struct data_file *df, + int block_index) +{ + struct pending_read *result = NULL; + struct data_file_segment *segment = NULL; + struct mount_info *mi = NULL; + + WARN_ON(!df); + segment = get_file_segment(df, block_index); + mi = df->df_mount_info; + + WARN_ON(!segment); + WARN_ON(!mi); + + result = kzalloc(sizeof(*result), GFP_NOFS); + if (!result) + return NULL; + + result->file_id = df->df_id; + result->block_index = block_index; + result->timestamp_us = ktime_to_us(ktime_get()); + + mutex_lock(&mi->mi_pending_reads_mutex); + + result->serial_number = ++mi->mi_last_pending_read_number; + mi->mi_pending_reads_count++; + + list_add(&result->mi_reads_list, &mi->mi_reads_list_head); + list_add(&result->segment_reads_list, &segment->reads_list_head); + mutex_unlock(&mi->mi_pending_reads_mutex); + + wake_up_all(&mi->mi_pending_reads_notif_wq); + return result; +} + +/* Notifies a given data file that pending read is completed. */ +static void remove_pending_read(struct data_file *df, struct pending_read *read) +{ + struct mount_info *mi = NULL; + + if (!df || !read) { + WARN_ON(!df); + WARN_ON(!read); + return; + } + + mi = df->df_mount_info; + + mutex_lock(&mi->mi_pending_reads_mutex); + list_del(&read->mi_reads_list); + list_del(&read->segment_reads_list); + + mi->mi_pending_reads_count--; + mutex_unlock(&mi->mi_pending_reads_mutex); + + kfree(read); +} + +static void notify_pending_reads(struct mount_info *mi, + struct data_file_segment *segment, + int index) +{ + struct pending_read *entry = NULL; + + /* Notify pending reads waiting for this block. */ + mutex_lock(&mi->mi_pending_reads_mutex); + list_for_each_entry(entry, &segment->reads_list_head, + segment_reads_list) { + if (entry->block_index == index) + set_read_done(entry); + } + mutex_unlock(&mi->mi_pending_reads_mutex); + wake_up_all(&segment->new_data_arrival_wq); +} + +static int wait_for_data_block(struct data_file *df, int block_index, + int timeout_ms, + struct data_file_block *res_block) +{ + struct data_file_block block = {}; + struct data_file_segment *segment = NULL; + struct pending_read *read = NULL; + struct mount_info *mi = NULL; + int error = 0; + int wait_res = 0; + + if (!df || !res_block) + return -EFAULT; + + if (block_index < 0 || block_index >= df->df_block_count) + return -EINVAL; + + if (df->df_blockmap_off <= 0) + return -ENODATA; + + segment = get_file_segment(df, block_index); + WARN_ON(!segment); + + error = mutex_lock_interruptible(&segment->blockmap_mutex); + if (error) + return error; + + /* Look up the given block */ + error = get_data_file_block(df, block_index, &block); + + /* If it's not found, create a pending read */ + if (!error && !is_data_block_present(&block) && timeout_ms != 0) + read = add_pending_read(df, block_index); + + mutex_unlock(&segment->blockmap_mutex); + if (error) + return error; + + /* If the block was found, just return it. No need to wait. */ + if (is_data_block_present(&block)) { + *res_block = block; + return 0; + } + + mi = df->df_mount_info; + + if (timeout_ms == 0) { + log_block_read(mi, &df->df_id, block_index, + true /*timed out*/); + return -ETIME; + } + + if (!read) + return -ENOMEM; + + /* Wait for notifications about block's arrival */ + wait_res = + wait_event_interruptible_timeout(segment->new_data_arrival_wq, + (is_read_done(read)), + msecs_to_jiffies(timeout_ms)); + + /* Woke up, the pending read is no longer needed. */ + remove_pending_read(df, read); + read = NULL; + + if (wait_res == 0) { + /* Wait has timed out */ + log_block_read(mi, &df->df_id, block_index, + true /*timed out*/); + return -ETIME; + } + if (wait_res < 0) { + /* + * Only ERESTARTSYS is really expected here when a signal + * comes while we wait. + */ + return wait_res; + } + + error = mutex_lock_interruptible(&segment->blockmap_mutex); + if (error) + return error; + + /* + * Re-read block's info now, it has just arrived and + * should be available. + */ + error = get_data_file_block(df, block_index, &block); + if (!error) { + if (is_data_block_present(&block)) + *res_block = block; + else { + /* + * Somehow wait finished successfully bug block still + * can't be found. It's not normal. + */ + pr_warn("incfs:Wait succeeded, but block not found.\n"); + error = -ENODATA; + } + } + + mutex_unlock(&segment->blockmap_mutex); + return error; +} + +ssize_t incfs_read_data_file_block(struct mem_range dst, struct data_file *df, + int index, int timeout_ms, + struct mem_range tmp) +{ + loff_t pos; + ssize_t result; + size_t bytes_to_read; + struct mount_info *mi = NULL; + struct file *bf = NULL; + struct data_file_block block = {}; + + if (!dst.data || !df) + return -EFAULT; + + if (tmp.len < 2 * INCFS_DATA_FILE_BLOCK_SIZE) + return -ERANGE; + + mi = df->df_mount_info; + bf = df->df_backing_file_context->bc_file; + + result = wait_for_data_block(df, index, timeout_ms, &block); + if (result < 0) + goto out; + + pos = block.db_backing_file_data_offset; + if (block.db_comp_alg == COMPRESSION_NONE) { + bytes_to_read = min(dst.len, block.db_stored_size); + result = incfs_kread(bf, dst.data, bytes_to_read, pos); + + /* Some data was read, but not enough */ + if (result >= 0 && result != bytes_to_read) + result = -EIO; + } else { + bytes_to_read = min(tmp.len, block.db_stored_size); + result = incfs_kread(bf, tmp.data, bytes_to_read, pos); + if (result == bytes_to_read) { + result = + decompress(range(tmp.data, bytes_to_read), dst); + if (result < 0) { + const char *name = + bf->f_path.dentry->d_name.name; + + pr_warn_once("incfs: Decompression error. %s", + name); + } + } else if (result >= 0) { + /* Some data was read, but not enough */ + result = -EIO; + } + } + + if (result > 0) { + int err = validate_hash_tree(bf, df, index, dst, tmp.data); + + if (err < 0) + result = err; + } + + if (result > 0) { + int err = revalidate_signature(bf, df); + + if (err < 0) + result = err; + } + + if (result >= 0) + log_block_read(mi, &df->df_id, index, false /*timed out*/); + +out: + return result; +} + +int incfs_process_new_data_block(struct data_file *df, + struct incfs_new_data_block *block, u8 *data) +{ + struct mount_info *mi = NULL; + struct backing_file_context *bfc = NULL; + struct data_file_segment *segment = NULL; + struct data_file_block existing_block = {}; + u16 flags = 0; + int error = 0; + + if (!df || !block) + return -EFAULT; + + bfc = df->df_backing_file_context; + mi = df->df_mount_info; + + if (block->block_index >= df->df_block_count) + return -ERANGE; + + segment = get_file_segment(df, block->block_index); + if (!segment) + return -EFAULT; + if (block->compression == COMPRESSION_LZ4) + flags |= INCFS_BLOCK_COMPRESSED_LZ4; + + error = mutex_lock_interruptible(&segment->blockmap_mutex); + if (error) + return error; + + error = get_data_file_block(df, block->block_index, &existing_block); + if (error) + goto unlock; + if (is_data_block_present(&existing_block)) { + /* Block is already present, nothing to do here */ + goto unlock; + } + + error = mutex_lock_interruptible(&bfc->bc_mutex); + if (!error) { + error = incfs_write_data_block_to_backing_file( + bfc, range(data, block->data_len), block->block_index, + df->df_blockmap_off, flags); + mutex_unlock(&bfc->bc_mutex); + } + if (!error) + notify_pending_reads(mi, segment, block->block_index); + +unlock: + mutex_unlock(&segment->blockmap_mutex); + if (error) + pr_debug("incfs: %s %d error: %d\n", __func__, + block->block_index, error); + return error; +} + +int incfs_read_file_signature(struct data_file *df, struct mem_range dst) +{ + struct file *bf = df->df_backing_file_context->bc_file; + struct ondisk_signature *sig; + int read_res = 0; + + if (!dst.data) + return -EFAULT; + + sig = df->df_signature; + if (!sig) + return 0; + + if (dst.len < sig->sig_size) + return -E2BIG; + + read_res = incfs_kread(bf, dst.data, sig->sig_size, sig->sig_offset); + + if (read_res < 0) + return read_res; + + if (read_res != sig->sig_size) + return -EIO; + + return read_res; +} + +int incfs_process_new_hash_block(struct data_file *df, + struct incfs_new_data_block *block, u8 *data) +{ + struct backing_file_context *bfc = NULL; + struct mount_info *mi = NULL; + struct mtree *hash_tree = NULL; + struct ondisk_signature *sig = NULL; + loff_t hash_area_base = 0; + loff_t hash_area_size = 0; + int error = 0; + + if (!df || !block) + return -EFAULT; + + if (!(block->flags & INCFS_BLOCK_FLAGS_HASH)) + return -EINVAL; + + bfc = df->df_backing_file_context; + mi = df->df_mount_info; + + if (!df) + return -ENOENT; + + hash_tree = df->df_hash_tree; + sig = df->df_signature; + if (!hash_tree || !sig || sig->mtree_offset == 0) + return -ENOTSUPP; + + hash_area_base = sig->mtree_offset; + hash_area_size = sig->mtree_size; + if (hash_area_size < block->block_index * INCFS_DATA_FILE_BLOCK_SIZE + + block->data_len) { + /* Hash block goes beyond dedicated hash area of this file. */ + return -ERANGE; + } + + error = mutex_lock_interruptible(&bfc->bc_mutex); + if (!error) + error = incfs_write_hash_block_to_backing_file( + bfc, range(data, block->data_len), block->block_index, + hash_area_base); + mutex_unlock(&bfc->bc_mutex); + return error; +} + +static int process_blockmap_md(struct incfs_blockmap *bm, + struct metadata_handler *handler) +{ + struct data_file *df = handler->context; + int error = 0; + loff_t base_off = le64_to_cpu(bm->m_base_offset); + u32 block_count = le32_to_cpu(bm->m_block_count); + + if (!df) + return -EFAULT; + + if (df->df_block_count != block_count) + return -EBADMSG; + + df->df_blockmap_off = base_off; + return error; +} + +static int process_file_attr_md(struct incfs_file_attr *fa, + struct metadata_handler *handler) +{ + struct data_file *df = handler->context; + u16 attr_size = le16_to_cpu(fa->fa_size); + + if (!df) + return -EFAULT; + + if (attr_size > INCFS_MAX_FILE_ATTR_SIZE) + return -E2BIG; + + df->n_attr.fa_value_offset = le64_to_cpu(fa->fa_offset); + df->n_attr.fa_value_size = attr_size; + df->n_attr.fa_crc = le32_to_cpu(fa->fa_crc); + + return 0; +} + +static int process_file_signature_md(struct incfs_file_signature *sg, + struct metadata_handler *handler) +{ + struct data_file *df = handler->context; + struct mtree *hash_tree = NULL; + struct ondisk_signature *signature = NULL; + int error = 0; + loff_t base_tree_off = le64_to_cpu(sg->sg_hash_tree_offset); + u32 tree_size = le32_to_cpu(sg->sg_hash_tree_size); + loff_t sig_off = le64_to_cpu(sg->sg_sig_offset); + u32 sig_size = le32_to_cpu(sg->sg_sig_size); + loff_t add_data_off = le64_to_cpu(sg->sg_add_data_offset); + u32 add_data_size = le32_to_cpu(sg->sg_add_data_size); + + if (!df) + return -ENOENT; + + signature = kzalloc(sizeof(*signature), GFP_NOFS); + if (!signature) { + error = -ENOMEM; + goto out; + } + + signature->add_data_offset = add_data_off; + signature->add_data_size = add_data_size; + signature->sig_offset = sig_off; + signature->sig_size = sig_size; + signature->mtree_offset = base_tree_off; + signature->mtree_size = tree_size; + + hash_tree = incfs_alloc_mtree(sg->sg_hash_alg, df->df_block_count, + range(sg->sg_root_hash, sizeof(sg->sg_root_hash))); + if (IS_ERR(hash_tree)) { + error = PTR_ERR(hash_tree); + hash_tree = NULL; + goto out; + } + if (hash_tree->hash_tree_area_size != tree_size) { + error = -EINVAL; + goto out; + } + if (tree_size > 0 && handler->md_record_offset <= base_tree_off) { + error = -EINVAL; + goto out; + } + if (handler->md_record_offset <= signature->add_data_offset || + handler->md_record_offset <= signature->sig_offset) { + error = -EINVAL; + goto out; + } + df->df_hash_tree = hash_tree; + df->df_signature = signature; +out: + if (error) { + incfs_free_mtree(hash_tree); + kfree(signature); + } + + return error; +} + +int incfs_scan_metadata_chain(struct data_file *df) +{ + struct metadata_handler *handler = NULL; + int result = 0; + int records_count = 0; + int error = 0; + struct backing_file_context *bfc = NULL; + + if (!df || !df->df_backing_file_context) + return -EFAULT; + + bfc = df->df_backing_file_context; + + handler = kzalloc(sizeof(*handler), GFP_NOFS); + if (!handler) + return -ENOMEM; + + /* No writing to the backing file while it's being scanned. */ + error = mutex_lock_interruptible(&bfc->bc_mutex); + if (error) + goto out; + + /* Reading superblock */ + handler->md_record_offset = df->df_metadata_off; + handler->context = df; + handler->handle_blockmap = process_blockmap_md; + handler->handle_file_attr = process_file_attr_md; + handler->handle_signature = process_file_signature_md; + + pr_debug("incfs: Starting reading incfs-metadata records at offset %lld\n", + handler->md_record_offset); + while (handler->md_record_offset > 0) { + error = incfs_read_next_metadata_record(bfc, handler); + if (error) { + pr_warn("incfs: Error during reading incfs-metadata record. Offset: %lld Record #%d Error code: %d\n", + handler->md_record_offset, records_count + 1, + -error); + break; + } + records_count++; + } + if (error) { + pr_debug("incfs: Error %d after reading %d incfs-metadata records.\n", + -error, records_count); + result = error; + } else { + pr_debug("incfs: Finished reading %d incfs-metadata records.\n", + records_count); + result = records_count; + } + mutex_unlock(&bfc->bc_mutex); +out: + kfree(handler); + return result; +} + +/* + * Quickly checks if there are pending reads with a serial number larger + * than a given one. + */ +bool incfs_fresh_pending_reads_exist(struct mount_info *mi, int last_number) +{ + bool result = false; + + mutex_lock(&mi->mi_pending_reads_mutex); + result = (mi->mi_last_pending_read_number > last_number) && + (mi->mi_pending_reads_count > 0); + mutex_unlock(&mi->mi_pending_reads_mutex); + return result; +} + +int incfs_collect_pending_reads(struct mount_info *mi, int sn_lowerbound, + struct incfs_pending_read_info *reads, + int reads_size) +{ + int reported_reads = 0; + struct pending_read *entry = NULL; + + if (!mi) + return -EFAULT; + + if (reads_size <= 0) + return 0; + + mutex_lock(&mi->mi_pending_reads_mutex); + + if (mi->mi_last_pending_read_number <= sn_lowerbound + || mi->mi_pending_reads_count == 0) + goto unlock; + + list_for_each_entry(entry, &mi->mi_reads_list_head, mi_reads_list) { + if (entry->serial_number <= sn_lowerbound) + continue; + + reads[reported_reads].file_id = entry->file_id; + reads[reported_reads].block_index = entry->block_index; + reads[reported_reads].serial_number = entry->serial_number; + reads[reported_reads].timestamp_us = entry->timestamp_us; + /* reads[reported_reads].kind = INCFS_READ_KIND_PENDING; */ + + reported_reads++; + if (reported_reads >= reads_size) + break; + } + +unlock: + mutex_unlock(&mi->mi_pending_reads_mutex); + + return reported_reads; +} + +struct read_log_state incfs_get_log_state(struct mount_info *mi) +{ + struct read_log *log = &mi->mi_log; + struct read_log_state result; + + spin_lock(&log->rl_writer_lock); + result = READ_ONCE(log->rl_state); + spin_unlock(&log->rl_writer_lock); + return result; +} + +static u64 calc_record_count(const struct read_log_state *state, int rl_size) +{ + return state->current_pass_no * (u64)rl_size + state->next_index; +} + +int incfs_get_uncollected_logs_count(struct mount_info *mi, + struct read_log_state state) +{ + struct read_log *log = &mi->mi_log; + + u64 count = calc_record_count(&log->rl_state, log->rl_size) - + calc_record_count(&state, log->rl_size); + return min_t(int, count, log->rl_size); +} + +static void fill_pending_read_from_log_record( + struct incfs_pending_read_info *dest, const struct read_log_record *src, + struct read_log_state *state, u64 log_size) +{ + dest->file_id = src->file_id; + dest->block_index = src->block_index; + dest->serial_number = + state->current_pass_no * log_size + state->next_index; + dest->timestamp_us = src->timestamp_us; +} + +int incfs_collect_logged_reads(struct mount_info *mi, + struct read_log_state *reader_state, + struct incfs_pending_read_info *reads, + int reads_size) +{ + struct read_log *log = &mi->mi_log; + struct read_log_state live_state = incfs_get_log_state(mi); + u64 read_count = calc_record_count(reader_state, log->rl_size); + u64 written_count = calc_record_count(&live_state, log->rl_size); + int dst_idx; + + if (reader_state->next_index >= log->rl_size || + read_count > written_count) + return -ERANGE; + + if (read_count == written_count) + return 0; + + if (read_count > written_count) { + /* This reader is somehow ahead of the writer. */ + pr_debug("incfs: Log reader is ahead of writer\n"); + *reader_state = live_state; + } + + if (written_count - read_count > log->rl_size) { + /* + * Reading pointer is too far behind, + * start from the record following the write pointer. + */ + pr_debug("incfs: read pointer is behind, moving: %u/%u -> %u/%u / %u\n", + (u32)reader_state->next_index, + (u32)reader_state->current_pass_no, + (u32)live_state.next_index, + (u32)live_state.current_pass_no - 1, (u32)log->rl_size); + + *reader_state = (struct read_log_state){ + .next_index = live_state.next_index, + .current_pass_no = live_state.current_pass_no - 1, + }; + } + + for (dst_idx = 0; dst_idx < reads_size; dst_idx++) { + if (reader_state->next_index == live_state.next_index && + reader_state->current_pass_no == live_state.current_pass_no) + break; + + fill_pending_read_from_log_record( + &reads[dst_idx], + &log->rl_ring_buf[reader_state->next_index], + reader_state, log->rl_size); + + reader_state->next_index++; + if (reader_state->next_index == log->rl_size) { + reader_state->next_index = 0; + reader_state->current_pass_no++; + } + } + return dst_idx; +} + +bool incfs_equal_ranges(struct mem_range lhs, struct mem_range rhs) +{ + if (lhs.len != rhs.len) + return false; + return memcmp(lhs.data, rhs.data, lhs.len) == 0; +} diff --git a/fs/incfs/data_mgmt.h b/fs/incfs/data_mgmt.h new file mode 100644 index 000000000000..82ccab3be4bb --- /dev/null +++ b/fs/incfs/data_mgmt.h @@ -0,0 +1,339 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ +#ifndef _INCFS_DATA_MGMT_H +#define _INCFS_DATA_MGMT_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "internal.h" + +#define SEGMENTS_PER_FILE 3 + +struct read_log_record { + u32 block_index : 31; + + u32 timed_out : 1; + + u64 timestamp_us; + + incfs_uuid_t file_id; +} __packed; + +struct read_log_state { + /* Next slot in rl_ring_buf to write to. */ + u32 next_index; + + /* Current number of writer pass over rl_ring_buf */ + u32 current_pass_no; +}; + +/* A ring buffer to save records about data blocks which were recently read. */ +struct read_log { + struct read_log_record *rl_ring_buf; + + struct read_log_state rl_state; + + spinlock_t rl_writer_lock; + + int rl_size; + + /* + * A queue of waiters who want to be notified about reads. + */ + wait_queue_head_t ml_notif_wq; +}; + +struct mount_options { + unsigned int read_timeout_ms; + unsigned int readahead_pages; + unsigned int read_log_pages; + unsigned int read_log_wakeup_count; + bool no_backing_file_cache; + bool no_backing_file_readahead; +}; + +struct mount_info { + struct super_block *mi_sb; + + struct path mi_backing_dir_path; + + struct dentry *mi_index_dir; + + const struct cred *mi_owner; + + struct mount_options mi_options; + + /* This mutex is to be taken before create, rename, delete */ + struct mutex mi_dir_struct_mutex; + + /* + * A queue of waiters who want to be notified about new pending reads. + */ + wait_queue_head_t mi_pending_reads_notif_wq; + + /* + * Protects: + * - reads_list_head + * - mi_pending_reads_count + * - mi_last_pending_read_number + * - data_file_segment.reads_list_head + */ + struct mutex mi_pending_reads_mutex; + + /* List of active pending_read objects */ + struct list_head mi_reads_list_head; + + /* Total number of items in reads_list_head */ + int mi_pending_reads_count; + + /* + * Last serial number that was assigned to a pending read. + * 0 means no pending reads have been seen yet. + */ + int mi_last_pending_read_number; + + /* Temporary buffer for read logger. */ + struct read_log mi_log; +}; + +struct data_file_block { + loff_t db_backing_file_data_offset; + + size_t db_stored_size; + + enum incfs_compression_alg db_comp_alg; +}; + +struct pending_read { + incfs_uuid_t file_id; + + s64 timestamp_us; + + atomic_t done; + + int block_index; + + int serial_number; + + struct list_head mi_reads_list; + + struct list_head segment_reads_list; +}; + +struct data_file_segment { + wait_queue_head_t new_data_arrival_wq; + + /* Protects reads and writes from the blockmap */ + /* Good candidate for read/write mutex */ + struct mutex blockmap_mutex; + + /* List of active pending_read objects belonging to this segment */ + /* Protected by mount_info.pending_reads_mutex */ + struct list_head reads_list_head; +}; + +/* + * Extra info associated with a file. Just a few bytes set by a user. + */ +struct file_attr { + loff_t fa_value_offset; + + size_t fa_value_size; + + u32 fa_crc; +}; + + +struct data_file { + struct backing_file_context *df_backing_file_context; + + struct mount_info *df_mount_info; + + incfs_uuid_t df_id; + + /* + * Array of segments used to reduce lock contention for the file. + * Segment is chosen for a block depends on the block's index. + */ + struct data_file_segment df_segments[SEGMENTS_PER_FILE]; + + /* Base offset of the first metadata record. */ + loff_t df_metadata_off; + + /* Base offset of the block map. */ + loff_t df_blockmap_off; + + /* File size in bytes */ + loff_t df_size; + + int df_block_count; /* File size in DATA_FILE_BLOCK_SIZE blocks */ + + struct file_attr n_attr; + + struct mtree *df_hash_tree; + + struct ondisk_signature *df_signature; + + /* True, if file signature has already been validated. */ + bool df_signature_validated; +}; + +struct dir_file { + struct mount_info *mount_info; + + struct file *backing_dir; +}; + +struct inode_info { + struct mount_info *n_mount_info; /* A mount, this file belongs to */ + + struct inode *n_backing_inode; + + struct data_file *n_file; + + struct inode n_vfs_inode; +}; + +struct dentry_info { + struct path backing_path; +}; + +struct mount_info *incfs_alloc_mount_info(struct super_block *sb, + struct mount_options *options, + struct path *backing_dir_path); + +void incfs_free_mount_info(struct mount_info *mi); + +struct data_file *incfs_open_data_file(struct mount_info *mi, struct file *bf); +void incfs_free_data_file(struct data_file *df); + +int incfs_scan_metadata_chain(struct data_file *df); + +struct dir_file *incfs_open_dir_file(struct mount_info *mi, struct file *bf); +void incfs_free_dir_file(struct dir_file *dir); + +ssize_t incfs_read_data_file_block(struct mem_range dst, struct data_file *df, + int index, int timeout_ms, + struct mem_range tmp); + +int incfs_read_file_signature(struct data_file *df, struct mem_range dst); + +int incfs_process_new_data_block(struct data_file *df, + struct incfs_new_data_block *block, u8 *data); + +int incfs_process_new_hash_block(struct data_file *df, + struct incfs_new_data_block *block, u8 *data); + + +bool incfs_fresh_pending_reads_exist(struct mount_info *mi, int last_number); + +/* + * Collects pending reads and saves them into the array (reads/reads_size). + * Only reads with serial_number > sn_lowerbound are reported. + * Returns how many reads were saved into the array. + */ +int incfs_collect_pending_reads(struct mount_info *mi, int sn_lowerbound, + struct incfs_pending_read_info *reads, + int reads_size); + +int incfs_collect_logged_reads(struct mount_info *mi, + struct read_log_state *start_state, + struct incfs_pending_read_info *reads, + int reads_size); +struct read_log_state incfs_get_log_state(struct mount_info *mi); +int incfs_get_uncollected_logs_count(struct mount_info *mi, + struct read_log_state state); + +static inline struct inode_info *get_incfs_node(struct inode *inode) +{ + if (!inode) + return NULL; + + if (inode->i_sb->s_magic != INCFS_MAGIC_NUMBER) { + /* This inode doesn't belong to us. */ + pr_warn_once("incfs: %s on an alien inode.", __func__); + return NULL; + } + + return container_of(inode, struct inode_info, n_vfs_inode); +} + +static inline struct data_file *get_incfs_data_file(struct file *f) +{ + struct inode_info *node = NULL; + + if (!f) + return NULL; + + if (!S_ISREG(f->f_inode->i_mode)) + return NULL; + + node = get_incfs_node(f->f_inode); + if (!node) + return NULL; + + return node->n_file; +} + +static inline struct dir_file *get_incfs_dir_file(struct file *f) +{ + if (!f) + return NULL; + + if (!S_ISDIR(f->f_inode->i_mode)) + return NULL; + + return (struct dir_file *)f->private_data; +} + +/* + * Make sure that inode_info.n_file is initialized and inode can be used + * for reading and writing data from/to the backing file. + */ +int make_inode_ready_for_data_ops(struct mount_info *mi, + struct inode *inode, + struct file *backing_file); + +static inline struct dentry_info *get_incfs_dentry(const struct dentry *d) +{ + if (!d) + return NULL; + + return (struct dentry_info *)d->d_fsdata; +} + +static inline void get_incfs_backing_path(const struct dentry *d, + struct path *path) +{ + struct dentry_info *di = get_incfs_dentry(d); + + if (!di) { + *path = (struct path) {}; + return; + } + + *path = di->backing_path; + path_get(path); +} + +static inline int get_blocks_count_for_size(u64 size) +{ + if (size == 0) + return 0; + return 1 + (size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; +} + +bool incfs_equal_ranges(struct mem_range lhs, struct mem_range rhs); + +#endif /* _INCFS_DATA_MGMT_H */ diff --git a/fs/incfs/format.c b/fs/incfs/format.c new file mode 100644 index 000000000000..27498b9c3d34 --- /dev/null +++ b/fs/incfs/format.c @@ -0,0 +1,696 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 Google LLC + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "compat.h" +#include "format.h" + +struct backing_file_context *incfs_alloc_bfc(struct file *backing_file) +{ + struct backing_file_context *result = NULL; + + result = kzalloc(sizeof(*result), GFP_NOFS); + if (!result) + return ERR_PTR(-ENOMEM); + + result->bc_file = get_file(backing_file); + mutex_init(&result->bc_mutex); + return result; +} + +void incfs_free_bfc(struct backing_file_context *bfc) +{ + if (!bfc) + return; + + if (bfc->bc_file) + fput(bfc->bc_file); + + mutex_destroy(&bfc->bc_mutex); + kfree(bfc); +} + +loff_t incfs_get_end_offset(struct file *f) +{ + /* + * This function assumes that file size and the end-offset + * are the same. This is not always true. + */ + return i_size_read(file_inode(f)); +} + +/* + * Truncate the tail of the file to the given length. + * Used to rollback partially successful multistep writes. + */ +static int truncate_backing_file(struct backing_file_context *bfc, + loff_t new_end) +{ + struct inode *inode = NULL; + struct dentry *dentry = NULL; + loff_t old_end = 0; + struct iattr attr; + int result = 0; + + if (!bfc) + return -EFAULT; + + LOCK_REQUIRED(bfc->bc_mutex); + + if (!bfc->bc_file) + return -EFAULT; + + old_end = incfs_get_end_offset(bfc->bc_file); + if (old_end == new_end) + return 0; + if (old_end < new_end) + return -EINVAL; + + inode = bfc->bc_file->f_inode; + dentry = bfc->bc_file->f_path.dentry; + + attr.ia_size = new_end; + attr.ia_valid = ATTR_SIZE; + + inode_lock(inode); + result = notify_change(dentry, &attr, NULL); + inode_unlock(inode); + + return result; +} + +/* Append a given number of zero bytes to the end of the backing file. */ +static int append_zeros(struct backing_file_context *bfc, size_t len) +{ + loff_t file_size = 0; + loff_t new_last_byte_offset = 0; + int res = 0; + + if (!bfc) + return -EFAULT; + + if (len == 0) + return 0; + + LOCK_REQUIRED(bfc->bc_mutex); + + /* + * Allocate only one byte at the new desired end of the file. + * It will increase file size and create a zeroed area of + * a given size. + */ + file_size = incfs_get_end_offset(bfc->bc_file); + new_last_byte_offset = file_size + len - 1; + res = vfs_fallocate(bfc->bc_file, 0, new_last_byte_offset, 1); + if (res) + return res; + + res = vfs_fsync_range(bfc->bc_file, file_size, file_size + len, 1); + return res; +} + +static int write_to_bf(struct backing_file_context *bfc, const void *buf, + size_t count, loff_t pos, bool sync) +{ + ssize_t res = 0; + + res = incfs_kwrite(bfc->bc_file, buf, count, pos); + if (res < 0) + return res; + if (res != count) + return -EIO; + + if (sync) + return vfs_fsync_range(bfc->bc_file, pos, pos + count, 1); + + return 0; +} + +static u32 calc_md_crc(struct incfs_md_header *record) +{ + u32 result = 0; + __le32 saved_crc = record->h_record_crc; + __le64 saved_md_offset = record->h_next_md_offset; + size_t record_size = min_t(size_t, le16_to_cpu(record->h_record_size), + INCFS_MAX_METADATA_RECORD_SIZE); + + /* Zero fields which needs to be excluded from CRC calculation. */ + record->h_record_crc = 0; + record->h_next_md_offset = 0; + result = crc32(0, record, record_size); + + /* Restore excluded fields. */ + record->h_record_crc = saved_crc; + record->h_next_md_offset = saved_md_offset; + + return result; +} + +/* + * Append a given metadata record to the backing file and update a previous + * record to add the new record the the metadata list. + */ +static int append_md_to_backing_file(struct backing_file_context *bfc, + struct incfs_md_header *record) +{ + int result = 0; + loff_t record_offset; + loff_t file_pos; + __le64 new_md_offset; + size_t record_size; + + if (!bfc || !record) + return -EFAULT; + + if (bfc->bc_last_md_record_offset < 0) + return -EINVAL; + + LOCK_REQUIRED(bfc->bc_mutex); + + record_size = le16_to_cpu(record->h_record_size); + file_pos = incfs_get_end_offset(bfc->bc_file); + record->h_prev_md_offset = bfc->bc_last_md_record_offset; + record->h_next_md_offset = 0; + record->h_record_crc = cpu_to_le32(calc_md_crc(record)); + + /* Write the metadata record to the end of the backing file */ + record_offset = file_pos; + new_md_offset = cpu_to_le64(record_offset); + result = write_to_bf(bfc, record, record_size, file_pos, true); + if (result) + return result; + + /* Update next metadata offset in a previous record or a superblock. */ + if (bfc->bc_last_md_record_offset) { + /* + * Find a place in the previous md record where new record's + * offset needs to be saved. + */ + file_pos = bfc->bc_last_md_record_offset + + offsetof(struct incfs_md_header, h_next_md_offset); + } else { + /* + * No metadata yet, file a place to update in the + * file_header. + */ + file_pos = offsetof(struct incfs_file_header, + fh_first_md_offset); + } + result = write_to_bf(bfc, &new_md_offset, sizeof(new_md_offset), + file_pos, true); + if (result) + return result; + + bfc->bc_last_md_record_offset = record_offset; + return result; +} + +/* + * Reserve 0-filled space for the blockmap body, and append + * incfs_blockmap metadata record pointing to it. + */ +int incfs_write_blockmap_to_backing_file(struct backing_file_context *bfc, + u32 block_count, loff_t *map_base_off) +{ + struct incfs_blockmap blockmap = {}; + int result = 0; + loff_t file_end = 0; + size_t map_size = block_count * sizeof(struct incfs_blockmap_entry); + + if (!bfc) + return -EFAULT; + + blockmap.m_header.h_md_entry_type = INCFS_MD_BLOCK_MAP; + blockmap.m_header.h_record_size = cpu_to_le16(sizeof(blockmap)); + blockmap.m_header.h_next_md_offset = cpu_to_le64(0); + blockmap.m_block_count = cpu_to_le32(block_count); + + LOCK_REQUIRED(bfc->bc_mutex); + + /* Reserve 0-filled space for the blockmap body in the backing file. */ + file_end = incfs_get_end_offset(bfc->bc_file); + result = append_zeros(bfc, map_size); + if (result) + return result; + + /* Write blockmap metadata record pointing to the body written above. */ + blockmap.m_base_offset = cpu_to_le64(file_end); + result = append_md_to_backing_file(bfc, &blockmap.m_header); + if (result) { + /* Error, rollback file changes */ + truncate_backing_file(bfc, file_end); + } else if (map_base_off) { + *map_base_off = file_end; + } + + return result; +} + +/* + * Write file attribute data and metadata record to the backing file. + */ +int incfs_write_file_attr_to_backing_file(struct backing_file_context *bfc, + struct mem_range value, struct incfs_file_attr *attr) +{ + struct incfs_file_attr file_attr = {}; + int result = 0; + u32 crc = 0; + loff_t value_offset = 0; + + if (!bfc) + return -EFAULT; + + if (value.len > INCFS_MAX_FILE_ATTR_SIZE) + return -ENOSPC; + + LOCK_REQUIRED(bfc->bc_mutex); + + crc = crc32(0, value.data, value.len); + value_offset = incfs_get_end_offset(bfc->bc_file); + file_attr.fa_header.h_md_entry_type = INCFS_MD_FILE_ATTR; + file_attr.fa_header.h_record_size = cpu_to_le16(sizeof(file_attr)); + file_attr.fa_header.h_next_md_offset = cpu_to_le64(0); + file_attr.fa_size = cpu_to_le16((u16)value.len); + file_attr.fa_offset = cpu_to_le64(value_offset); + file_attr.fa_crc = cpu_to_le64(crc); + + result = write_to_bf(bfc, value.data, value.len, value_offset, true); + if (result) + return result; + + result = append_md_to_backing_file(bfc, &file_attr.fa_header); + if (result) { + /* Error, rollback file changes */ + truncate_backing_file(bfc, value_offset); + } else if (attr) { + *attr = file_attr; + } + + return result; +} + +int incfs_write_signature_to_backing_file(struct backing_file_context *bfc, + u8 hash_alg, u32 tree_size, + struct mem_range root_hash, struct mem_range add_data, + struct mem_range sig) +{ + struct incfs_file_signature sg = {}; + int result = 0; + loff_t rollback_pos = 0; + loff_t tree_area_pos = 0; + size_t alignment = 0; + + if (!bfc) + return -EFAULT; + if (root_hash.len > sizeof(sg.sg_root_hash)) + return -E2BIG; + + LOCK_REQUIRED(bfc->bc_mutex); + + rollback_pos = incfs_get_end_offset(bfc->bc_file); + + sg.sg_header.h_md_entry_type = INCFS_MD_SIGNATURE; + sg.sg_header.h_record_size = cpu_to_le16(sizeof(sg)); + sg.sg_header.h_next_md_offset = cpu_to_le64(0); + sg.sg_hash_alg = hash_alg; + if (sig.data != NULL && sig.len > 0) { + loff_t pos = incfs_get_end_offset(bfc->bc_file); + + sg.sg_sig_size = cpu_to_le32(sig.len); + sg.sg_sig_offset = cpu_to_le64(pos); + + result = write_to_bf(bfc, sig.data, sig.len, pos, false); + if (result) + goto err; + } + + if (add_data.len > 0) { + loff_t pos = incfs_get_end_offset(bfc->bc_file); + + sg.sg_add_data_size = cpu_to_le32(add_data.len); + sg.sg_add_data_offset = cpu_to_le64(pos); + + result = write_to_bf(bfc, add_data.data, + add_data.len, pos, false); + if (result) + goto err; + } + + tree_area_pos = incfs_get_end_offset(bfc->bc_file); + if (hash_alg && tree_size > 0) { + if (tree_size > 5 * INCFS_DATA_FILE_BLOCK_SIZE) { + /* + * If hash tree is big enough, it makes sense to + * align in the backing file for faster access. + */ + loff_t offset = round_up(tree_area_pos, PAGE_SIZE); + + alignment = offset - tree_area_pos; + tree_area_pos = offset; + } + + /* + * If root hash is not the only hash in the tree. + * reserve 0-filled space for the tree. + */ + result = append_zeros(bfc, tree_size + alignment); + if (result) + goto err; + + sg.sg_hash_tree_size = cpu_to_le32(tree_size); + sg.sg_hash_tree_offset = cpu_to_le64(tree_area_pos); + } + memcpy(sg.sg_root_hash, root_hash.data, root_hash.len); + + /* Write a hash tree metadata record pointing to the hash tree above. */ + result = append_md_to_backing_file(bfc, &sg.sg_header); +err: + if (result) { + /* Error, rollback file changes */ + truncate_backing_file(bfc, rollback_pos); + } + return result; +} + +/* + * Write a backing file header + * It should always be called only on empty file. + * incfs_super_block.s_first_md_offset is 0 for now, but will be updated + * once first metadata record is added. + */ +int incfs_write_fh_to_backing_file(struct backing_file_context *bfc, + incfs_uuid_t *uuid, u64 file_size) +{ + struct incfs_file_header fh = {}; + loff_t file_pos = 0; + + if (!bfc) + return -EFAULT; + + fh.fh_magic = cpu_to_le64(INCFS_MAGIC_NUMBER); + fh.fh_version = cpu_to_le64(INCFS_FORMAT_CURRENT_VER); + fh.fh_header_size = cpu_to_le16(sizeof(fh)); + fh.fh_first_md_offset = cpu_to_le64(0); + fh.fh_data_block_size = cpu_to_le16(INCFS_DATA_FILE_BLOCK_SIZE); + + fh.fh_file_size = cpu_to_le64(file_size); + fh.fh_uuid = *uuid; + + LOCK_REQUIRED(bfc->bc_mutex); + + file_pos = incfs_get_end_offset(bfc->bc_file); + if (file_pos != 0) + return -EEXIST; + + return write_to_bf(bfc, &fh, sizeof(fh), file_pos, true); +} + +/* Write a given data block and update file's blockmap to point it. */ +int incfs_write_data_block_to_backing_file(struct backing_file_context *bfc, + struct mem_range block, int block_index, + loff_t bm_base_off, u16 flags) +{ + struct incfs_blockmap_entry bm_entry = {}; + int result = 0; + loff_t data_offset = 0; + loff_t bm_entry_off = + bm_base_off + sizeof(struct incfs_blockmap_entry) * block_index; + + if (!bfc) + return -EFAULT; + + if (block.len >= (1 << 16) || block_index < 0) + return -EINVAL; + + LOCK_REQUIRED(bfc->bc_mutex); + + data_offset = incfs_get_end_offset(bfc->bc_file); + if (data_offset <= bm_entry_off) { + /* Blockmap entry is beyond the file's end. It is not normal. */ + return -EINVAL; + } + + /* Write the block data at the end of the backing file. */ + result = write_to_bf(bfc, block.data, block.len, data_offset, false); + if (result) + return result; + + /* Update the blockmap to point to the newly written data. */ + bm_entry.me_data_offset_lo = cpu_to_le32((u32)data_offset); + bm_entry.me_data_offset_hi = cpu_to_le16((u16)(data_offset >> 32)); + bm_entry.me_data_size = cpu_to_le16((u16)block.len); + bm_entry.me_flags = cpu_to_le16(flags); + + result = write_to_bf(bfc, &bm_entry, sizeof(bm_entry), + bm_entry_off, false); + return result; +} + +int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc, + struct mem_range block, + int block_index, loff_t hash_area_off) +{ + loff_t data_offset = 0; + loff_t file_end = 0; + + + if (!bfc) + return -EFAULT; + + LOCK_REQUIRED(bfc->bc_mutex); + + data_offset = hash_area_off + block_index * INCFS_DATA_FILE_BLOCK_SIZE; + file_end = incfs_get_end_offset(bfc->bc_file); + if (data_offset + block.len > file_end) { + /* Block is located beyond the file's end. It is not normal. */ + return -EINVAL; + } + + return write_to_bf(bfc, block.data, block.len, data_offset, false); +} + +/* Initialize a new image in a given backing file. */ +int incfs_make_empty_backing_file(struct backing_file_context *bfc, + incfs_uuid_t *uuid, u64 file_size) +{ + int result = 0; + + if (!bfc || !bfc->bc_file) + return -EFAULT; + + result = mutex_lock_interruptible(&bfc->bc_mutex); + if (result) + goto out; + + result = truncate_backing_file(bfc, 0); + if (result) + goto out; + + result = incfs_write_fh_to_backing_file(bfc, uuid, file_size); +out: + mutex_unlock(&bfc->bc_mutex); + return result; +} + +int incfs_read_blockmap_entry(struct backing_file_context *bfc, int block_index, + loff_t bm_base_off, + struct incfs_blockmap_entry *bm_entry) +{ + return incfs_read_blockmap_entries(bfc, bm_entry, block_index, 1, + bm_base_off); +} + +int incfs_read_blockmap_entries(struct backing_file_context *bfc, + struct incfs_blockmap_entry *entries, + int start_index, int blocks_number, + loff_t bm_base_off) +{ + loff_t bm_entry_off = + bm_base_off + sizeof(struct incfs_blockmap_entry) * start_index; + const size_t bytes_to_read = sizeof(struct incfs_blockmap_entry) + * blocks_number; + int result = 0; + + if (!bfc || !entries) + return -EFAULT; + + if (start_index < 0 || bm_base_off <= 0) + return -ENODATA; + + result = incfs_kread(bfc->bc_file, entries, bytes_to_read, + bm_entry_off); + if (result < 0) + return result; + if (result < bytes_to_read) + return -EIO; + return 0; +} + + +int incfs_read_file_header(struct backing_file_context *bfc, + loff_t *first_md_off, incfs_uuid_t *uuid, + u64 *file_size) +{ + ssize_t bytes_read = 0; + struct incfs_file_header fh = {}; + + if (!bfc || !first_md_off) + return -EFAULT; + + LOCK_REQUIRED(bfc->bc_mutex); + bytes_read = incfs_kread(bfc->bc_file, &fh, sizeof(fh), 0); + if (bytes_read < 0) + return bytes_read; + + if (bytes_read < sizeof(fh)) + return -EBADMSG; + + if (le64_to_cpu(fh.fh_magic) != INCFS_MAGIC_NUMBER) + return -EILSEQ; + + if (le64_to_cpu(fh.fh_version) > INCFS_FORMAT_CURRENT_VER) + return -EILSEQ; + + if (le16_to_cpu(fh.fh_data_block_size) != INCFS_DATA_FILE_BLOCK_SIZE) + return -EILSEQ; + + if (le16_to_cpu(fh.fh_header_size) != sizeof(fh)) + return -EILSEQ; + + if (first_md_off) + *first_md_off = le64_to_cpu(fh.fh_first_md_offset); + if (uuid) + *uuid = fh.fh_uuid; + if (file_size) + *file_size = le64_to_cpu(fh.fh_file_size); + return 0; +} + +/* + * Read through metadata records from the backing file one by one + * and call provided metadata handlers. + */ +int incfs_read_next_metadata_record(struct backing_file_context *bfc, + struct metadata_handler *handler) +{ + const ssize_t max_md_size = INCFS_MAX_METADATA_RECORD_SIZE; + ssize_t bytes_read = 0; + size_t md_record_size = 0; + loff_t next_record = 0; + loff_t prev_record = 0; + int res = 0; + struct incfs_md_header *md_hdr = NULL; + + if (!bfc || !handler) + return -EFAULT; + + LOCK_REQUIRED(bfc->bc_mutex); + + if (handler->md_record_offset == 0) + return -EPERM; + + memset(&handler->md_buffer, 0, max_md_size); + bytes_read = incfs_kread(bfc->bc_file, &handler->md_buffer, + max_md_size, handler->md_record_offset); + if (bytes_read < 0) + return bytes_read; + if (bytes_read < sizeof(*md_hdr)) + return -EBADMSG; + + md_hdr = &handler->md_buffer.md_header; + next_record = le64_to_cpu(md_hdr->h_next_md_offset); + prev_record = le64_to_cpu(md_hdr->h_prev_md_offset); + md_record_size = le16_to_cpu(md_hdr->h_record_size); + + if (md_record_size > max_md_size) { + pr_warn("incfs: The record is too large. Size: %ld", + md_record_size); + return -EBADMSG; + } + + if (bytes_read < md_record_size) { + pr_warn("incfs: The record hasn't been fully read."); + return -EBADMSG; + } + + if (next_record <= handler->md_record_offset && next_record != 0) { + pr_warn("incfs: Next record (%lld) points back in file.", + next_record); + return -EBADMSG; + } + + if (prev_record != handler->md_prev_record_offset) { + pr_warn("incfs: Metadata chain has been corrupted."); + return -EBADMSG; + } + + if (le32_to_cpu(md_hdr->h_record_crc) != calc_md_crc(md_hdr)) { + pr_warn("incfs: Metadata CRC mismatch."); + return -EBADMSG; + } + + switch (md_hdr->h_md_entry_type) { + case INCFS_MD_NONE: + break; + case INCFS_MD_BLOCK_MAP: + if (handler->handle_blockmap) + res = handler->handle_blockmap( + &handler->md_buffer.blockmap, handler); + break; + case INCFS_MD_FILE_ATTR: + if (handler->handle_file_attr) + res = handler->handle_file_attr( + &handler->md_buffer.file_attr, handler); + break; + case INCFS_MD_SIGNATURE: + if (handler->handle_signature) + res = handler->handle_signature( + &handler->md_buffer.signature, handler); + break; + default: + res = -ENOTSUPP; + break; + } + + if (!res) { + if (next_record == 0) { + /* + * Zero offset for the next record means that the last + * metadata record has just been processed. + */ + bfc->bc_last_md_record_offset = + handler->md_record_offset; + } + handler->md_prev_record_offset = handler->md_record_offset; + handler->md_record_offset = next_record; + } + return res; +} + +ssize_t incfs_kread(struct file *f, void *buf, size_t size, loff_t pos) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) + return kernel_read(f, pos, (char *)buf, size); +#else + return kernel_read(f, buf, size, &pos); +#endif +} + +ssize_t incfs_kwrite(struct file *f, const void *buf, size_t size, loff_t pos) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) + return kernel_write(f, buf, size, pos); +#else + return kernel_write(f, buf, size, &pos); +#endif +} diff --git a/fs/incfs/format.h b/fs/incfs/format.h new file mode 100644 index 000000000000..a86881482e19 --- /dev/null +++ b/fs/incfs/format.h @@ -0,0 +1,349 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2018 Google LLC + */ + +/* + * Overview + * -------- + * The backbone of the incremental-fs ondisk format is an append only linked + * list of metadata blocks. Each metadata block contains an offset of the next + * one. These blocks describe files and directories on the + * file system. They also represent actions of adding and removing file names + * (hard links). + * + * Every time incremental-fs instance is mounted, it reads through this list + * to recreate filesystem's state in memory. An offset of the first record in + * the metadata list is stored in the superblock at the beginning of the backing + * file. + * + * Most of the backing file is taken by data areas and blockmaps. + * Since data blocks can be compressed and have different sizes, + * single per-file data area can't be pre-allocated. That's why blockmaps are + * needed in order to find a location and size of each data block in + * the backing file. Each time a file is created, a corresponding block map is + * allocated to store future offsets of data blocks. + * + * Whenever a data block is given by data loader to incremental-fs: + * - A data area with the given block is appended to the end of + * the backing file. + * - A record in the blockmap for the given block index is updated to reflect + * its location, size, and compression algorithm. + + * Metadata records + * ---------------- + * incfs_blockmap - metadata record that specifies size and location + * of a blockmap area for a given file. This area + * contains an array of incfs_blockmap_entry-s. + * incfs_file_signature - metadata record that specifies where file signature + * and its hash tree can be found in the backing file. + * + * incfs_file_attr - metadata record that specifies where additional file + * attributes blob can be found. + * + * Metadata header + * --------------- + * incfs_md_header - header of a metadata record. It's always a part + * of other structures and served purpose of metadata + * bookkeeping. + * + * +-----------------------------------------------+ ^ + * | incfs_md_header | | + * | 1. type of body(BLOCKMAP, FILE_ATTR..) | | + * | 2. size of the whole record header + body | | + * | 3. CRC the whole record header + body | | + * | 4. offset of the previous md record |]------+ + * | 5. offset of the next md record (md link) |]---+ + * +-----------------------------------------------+ | + * | Metadata record body with useful data | | + * +-----------------------------------------------+ | + * +---> + * + * Other ondisk structures + * ----------------------- + * incfs_super_block - backing file header + * incfs_blockmap_entry - a record in a blockmap area that describes size + * and location of a data block. + * Data blocks dont have any particular structure, they are written to the + * backing file in a raw form as they come from a data loader. + * + * Backing file layout + * ------------------- + * + * + * +-------------------------------------------+ + * | incfs_super_block |]---+ + * +-------------------------------------------+ | + * | metadata |<---+ + * | incfs_file_signature |]---+ + * +-------------------------------------------+ | + * ......................... | + * +-------------------------------------------+ | metadata + * +------->| blockmap area | | list links + * | | [incfs_blockmap_entry] | | + * | | [incfs_blockmap_entry] | | + * | | [incfs_blockmap_entry] | | + * | +--[| [incfs_blockmap_entry] | | + * | | | [incfs_blockmap_entry] | | + * | | | [incfs_blockmap_entry] | | + * | | +-------------------------------------------+ | + * | | ......................... | + * | | +-------------------------------------------+ | + * | | | metadata |<---+ + * +----|--[| incfs_blockmap |]---+ + * | +-------------------------------------------+ | + * | ......................... | + * | +-------------------------------------------+ | + * +-->| data block | | + * +-------------------------------------------+ | + * ......................... | + * +-------------------------------------------+ | + * | metadata |<---+ + * | incfs_file_attr | + * +-------------------------------------------+ + */ +#ifndef _INCFS_FORMAT_H +#define _INCFS_FORMAT_H +#include +#include +#include + +#include "internal.h" + +#define INCFS_MAX_NAME_LEN 255 +#define INCFS_FORMAT_V1 1 +#define INCFS_FORMAT_CURRENT_VER INCFS_FORMAT_V1 + +enum incfs_metadata_type { + INCFS_MD_NONE = 0, + INCFS_MD_BLOCK_MAP = 1, + INCFS_MD_FILE_ATTR = 2, + INCFS_MD_SIGNATURE = 3 +}; + +/* Header included at the beginning of all metadata records on the disk. */ +struct incfs_md_header { + __u8 h_md_entry_type; + + /* + * Size of the metadata record. + * (e.g. inode, dir entry etc) not just this struct. + */ + __le16 h_record_size; + + /* + * CRC32 of the metadata record. + * (e.g. inode, dir entry etc) not just this struct. + */ + __le32 h_record_crc; + + /* Offset of the next metadata entry if any */ + __le64 h_next_md_offset; + + /* Offset of the previous metadata entry if any */ + __le64 h_prev_md_offset; + +} __packed; + +/* Backing file header */ +struct incfs_file_header { + /* Magic number: INCFS_MAGIC_NUMBER */ + __le64 fh_magic; + + /* Format version: INCFS_FORMAT_CURRENT_VER */ + __le64 fh_version; + + /* sizeof(incfs_file_header) */ + __le16 fh_header_size; + + /* INCFS_DATA_FILE_BLOCK_SIZE */ + __le16 fh_data_block_size; + + /* Padding, also reserved for future use. */ + __le32 fh_dummy; + + /* Offset of the first metadata record */ + __le64 fh_first_md_offset; + + /* + * Put file specific information after this point + */ + + /* Full size of the file's content */ + __le64 fh_file_size; + + /* File uuid */ + incfs_uuid_t fh_uuid; +} __packed; + +enum incfs_block_map_entry_flags { + INCFS_BLOCK_COMPRESSED_LZ4 = (1 << 0), +}; + +/* Block map entry pointing to an actual location of the data block. */ +struct incfs_blockmap_entry { + /* Offset of the actual data block. Lower 32 bits */ + __le32 me_data_offset_lo; + + /* Offset of the actual data block. Higher 16 bits */ + __le16 me_data_offset_hi; + + /* How many bytes the data actually occupies in the backing file */ + __le16 me_data_size; + + /* Block flags from incfs_block_map_entry_flags */ + __le16 me_flags; +} __packed; + +/* Metadata record for locations of file blocks. Type = INCFS_MD_BLOCK_MAP */ +struct incfs_blockmap { + struct incfs_md_header m_header; + + /* Base offset of the array of incfs_blockmap_entry */ + __le64 m_base_offset; + + /* Size of the map entry array in blocks */ + __le32 m_block_count; +} __packed; + +/* Metadata record for file attribute. Type = INCFS_MD_FILE_ATTR */ +struct incfs_file_attr { + struct incfs_md_header fa_header; + + __le64 fa_offset; + + __le16 fa_size; + + __le32 fa_crc; +} __packed; + +/* Metadata record for file attribute. Type = INCFS_MD_SIGNATURE */ +struct incfs_file_signature { + struct incfs_md_header sg_header; + + __u8 sg_hash_alg; /* Value from incfs_hash_tree_algorithm */ + + __le32 sg_hash_tree_size; /* The size of the hash tree. */ + + __le64 sg_hash_tree_offset; /* Hash tree offset in the backing file */ + + __u8 sg_root_hash[INCFS_MAX_HASH_SIZE]; + + __le32 sg_sig_size; /* The size of the pkcs7 signature. */ + + __le64 sg_sig_offset; /* pkcs7 signature's offset in the backing file */ + + __le32 sg_add_data_size; /* The size of the additional data. */ + + __le64 sg_add_data_offset; /* Additional data's offset */ +} __packed; + +/* State of the backing file. */ +struct backing_file_context { + /* Protects writes to bc_file */ + struct mutex bc_mutex; + + /* File object to read data from */ + struct file *bc_file; + + /* + * Offset of the last known metadata record in the backing file. + * 0 means there are no metadata records. + */ + loff_t bc_last_md_record_offset; +}; + + +/* Backing file locations of things required for signature validation. */ +struct ondisk_signature { + + loff_t add_data_offset; /* Additional data's offset */ + + loff_t sig_offset; /* pkcs7 signature's offset in the backing file */ + + loff_t mtree_offset; /* Backing file offset of the hash tree. */ + + u32 add_data_size; /* The size of the additional data. */ + + u32 sig_size; /* The size of the pkcs7 signature. */ + + u32 mtree_size; /* The size of the hash tree. */ +}; + +struct metadata_handler { + loff_t md_record_offset; + loff_t md_prev_record_offset; + void *context; + + union { + struct incfs_md_header md_header; + struct incfs_blockmap blockmap; + struct incfs_file_attr file_attr; + struct incfs_file_signature signature; + } md_buffer; + + int (*handle_blockmap)(struct incfs_blockmap *bm, + struct metadata_handler *handler); + int (*handle_file_attr)(struct incfs_file_attr *fa, + struct metadata_handler *handler); + int (*handle_signature)(struct incfs_file_signature *sig, + struct metadata_handler *handler); +}; +#define INCFS_MAX_METADATA_RECORD_SIZE \ + FIELD_SIZEOF(struct metadata_handler, md_buffer) + +loff_t incfs_get_end_offset(struct file *f); + +/* Backing file context management */ +struct backing_file_context *incfs_alloc_bfc(struct file *backing_file); + +void incfs_free_bfc(struct backing_file_context *bfc); + +/* Writing stuff */ +int incfs_write_blockmap_to_backing_file(struct backing_file_context *bfc, + u32 block_count, loff_t *map_base_off); + +int incfs_write_fh_to_backing_file(struct backing_file_context *bfc, + incfs_uuid_t *uuid, u64 file_size); + +int incfs_write_data_block_to_backing_file(struct backing_file_context *bfc, + struct mem_range block, + int block_index, loff_t bm_base_off, + u16 flags); + +int incfs_write_hash_block_to_backing_file(struct backing_file_context *bfc, + struct mem_range block, + int block_index, loff_t hash_area_off); + +int incfs_write_file_attr_to_backing_file(struct backing_file_context *bfc, + struct mem_range value, struct incfs_file_attr *attr); + +int incfs_write_signature_to_backing_file(struct backing_file_context *bfc, + u8 hash_alg, u32 tree_size, + struct mem_range root_hash, struct mem_range add_data, + struct mem_range sig); + +int incfs_make_empty_backing_file(struct backing_file_context *bfc, + incfs_uuid_t *uuid, u64 file_size); + +/* Reading stuff */ +int incfs_read_file_header(struct backing_file_context *bfc, + loff_t *first_md_off, incfs_uuid_t *uuid, + u64 *file_size); + +int incfs_read_blockmap_entry(struct backing_file_context *bfc, int block_index, + loff_t bm_base_off, + struct incfs_blockmap_entry *bm_entry); + +int incfs_read_blockmap_entries(struct backing_file_context *bfc, + struct incfs_blockmap_entry *entries, + int start_index, int blocks_number, + loff_t bm_base_off); + +int incfs_read_next_metadata_record(struct backing_file_context *bfc, + struct metadata_handler *handler); + +ssize_t incfs_kread(struct file *f, void *buf, size_t size, loff_t pos); +ssize_t incfs_kwrite(struct file *f, const void *buf, size_t size, loff_t pos); + +#endif /* _INCFS_FORMAT_H */ diff --git a/fs/incfs/integrity.c b/fs/incfs/integrity.c new file mode 100644 index 000000000000..c6444e73e4d8 --- /dev/null +++ b/fs/incfs/integrity.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ +#include +#include +#include +#include +#include + +#include "integrity.h" + +int incfs_validate_pkcs7_signature(struct mem_range pkcs7_blob, + struct mem_range root_hash, struct mem_range add_data) +{ + struct pkcs7_message *pkcs7 = NULL; + const void *data = NULL; + size_t data_len = 0; + const char *p; + int err; + + pkcs7 = pkcs7_parse_message(pkcs7_blob.data, pkcs7_blob.len); + if (IS_ERR(pkcs7)) { + pr_debug("PKCS#7 parsing error. ptr=%p size=%ld err=%ld\n", + pkcs7_blob.data, pkcs7_blob.len, -PTR_ERR(pkcs7)); + return PTR_ERR(pkcs7); + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) + err = pkcs7_get_content_data(pkcs7, &data, &data_len, false); +#else + err = pkcs7_get_content_data(pkcs7, &data, &data_len, NULL); +#endif + if (err || data_len == 0 || data == NULL) { + pr_debug("PKCS#7 message does not contain data\n"); + err = -EBADMSG; + goto out; + } + + if (root_hash.len == 0) { + pr_debug("Root hash is empty.\n"); + err = -EBADMSG; + goto out; + } + + if (data_len != root_hash.len + add_data.len) { + pr_debug("PKCS#7 data size doesn't match arguments.\n"); + err = -EKEYREJECTED; + goto out; + } + + p = data; + if (memcmp(p, root_hash.data, root_hash.len) != 0) { + pr_debug("Root hash mismatch.\n"); + err = -EKEYREJECTED; + goto out; + } + p += root_hash.len; + if (memcmp(p, add_data.data, add_data.len) != 0) { + pr_debug("Additional data mismatch.\n"); + err = -EKEYREJECTED; + goto out; + } + + err = pkcs7_verify(pkcs7, VERIFYING_UNSPECIFIED_SIGNATURE); + if (err) + pr_debug("PKCS#7 signature verification error: %d\n", -err); + + /* + * RSA signature verification sometimes returns unexpected error codes + * when signature doesn't match. + */ + if (err == -ERANGE || err == -EINVAL) + err = -EBADMSG; + +out: + pkcs7_free_message(pkcs7); + return err; +} + +struct incfs_hash_alg *incfs_get_hash_alg(enum incfs_hash_tree_algorithm id) +{ + static struct incfs_hash_alg sha256 = { + .name = "sha256", + .digest_size = SHA256_DIGEST_SIZE, + .id = INCFS_HASH_TREE_SHA256 + }; + struct incfs_hash_alg *result = NULL; + struct crypto_shash *shash; + + if (id == INCFS_HASH_TREE_SHA256) { + BUILD_BUG_ON(INCFS_MAX_HASH_SIZE < SHA256_DIGEST_SIZE); + result = &sha256; + } + + if (result == NULL) + return ERR_PTR(-ENOENT); + + /* pairs with cmpxchg_release() below */ + shash = smp_load_acquire(&result->shash); + if (shash) + return result; + + shash = crypto_alloc_shash(result->name, 0, 0); + if (IS_ERR(shash)) { + int err = PTR_ERR(shash); + + pr_err("Can't allocate hash alg %s, error code:%d", + result->name, err); + return ERR_PTR(err); + } + + /* pairs with smp_load_acquire() above */ + if (cmpxchg_release(&result->shash, NULL, shash) != NULL) + crypto_free_shash(shash); + + return result; +} + + +struct mtree *incfs_alloc_mtree(enum incfs_hash_tree_algorithm id, + int data_block_count, + struct mem_range root_hash) +{ + struct mtree *result = NULL; + struct incfs_hash_alg *hash_alg = NULL; + int hash_per_block; + int lvl; + int total_blocks = 0; + int blocks_in_level[INCFS_MAX_MTREE_LEVELS]; + int blocks = data_block_count; + + if (data_block_count <= 0) + return ERR_PTR(-EINVAL); + + hash_alg = incfs_get_hash_alg(id); + if (IS_ERR(hash_alg)) + return ERR_PTR(PTR_ERR(hash_alg)); + + if (root_hash.len < hash_alg->digest_size) + return ERR_PTR(-EINVAL); + + result = kzalloc(sizeof(*result), GFP_NOFS); + if (!result) + return ERR_PTR(-ENOMEM); + + result->alg = hash_alg; + hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / result->alg->digest_size; + + /* Calculating tree geometry. */ + /* First pass: calculate how many blocks in each tree level. */ + for (lvl = 0; blocks > 1; lvl++) { + if (lvl >= INCFS_MAX_MTREE_LEVELS) { + pr_err("incfs: too much data in mtree"); + goto err; + } + + blocks = (blocks + hash_per_block - 1) / hash_per_block; + blocks_in_level[lvl] = blocks; + total_blocks += blocks; + } + result->depth = lvl; + result->hash_tree_area_size = total_blocks * INCFS_DATA_FILE_BLOCK_SIZE; + if (result->hash_tree_area_size > INCFS_MAX_HASH_AREA_SIZE) + goto err; + + blocks = 0; + /* Second pass: calculate offset of each level. 0th level goes last. */ + for (lvl = 0; lvl < result->depth; lvl++) { + u32 suboffset; + + blocks += blocks_in_level[lvl]; + suboffset = (total_blocks - blocks) + * INCFS_DATA_FILE_BLOCK_SIZE; + + result->hash_level_suboffset[lvl] = suboffset; + } + + /* Root hash is stored separately from the rest of the tree. */ + memcpy(result->root_hash, root_hash.data, hash_alg->digest_size); + return result; + +err: + kfree(result); + return ERR_PTR(-E2BIG); +} + +void incfs_free_mtree(struct mtree *tree) +{ + kfree(tree); +} + +int incfs_calc_digest(struct incfs_hash_alg *alg, struct mem_range data, + struct mem_range digest) +{ + SHASH_DESC_ON_STACK(desc, alg->shash); + + if (!alg || !alg->shash || !data.data || !digest.data) + return -EFAULT; + + if (alg->digest_size > digest.len) + return -EINVAL; + + desc->tfm = alg->shash; + return crypto_shash_digest(desc, data.data, data.len, digest.data); +} + +void incfs_free_signature_info(struct signature_info *si) +{ + if (!si) + return; + kfree(si->root_hash.data); + kfree(si->additional_data.data); + kfree(si->signature.data); + kfree(si); +} + diff --git a/fs/incfs/integrity.h b/fs/incfs/integrity.h new file mode 100644 index 000000000000..da1c38486b2f --- /dev/null +++ b/fs/incfs/integrity.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ +#ifndef _INCFS_INTEGRITY_H +#define _INCFS_INTEGRITY_H +#include +#include +#include + +#include + +#include "internal.h" + +#define INCFS_MAX_MTREE_LEVELS 8 +#define INCFS_MAX_HASH_AREA_SIZE (1280 * 1024 * 1024) + +struct incfs_hash_alg { + const char *name; + int digest_size; + enum incfs_hash_tree_algorithm id; + + struct crypto_shash *shash; +}; + +/* Merkle tree structure. */ +struct mtree { + struct incfs_hash_alg *alg; + + u8 root_hash[INCFS_MAX_HASH_SIZE]; + + /* Offset of each hash level in the hash area. */ + u32 hash_level_suboffset[INCFS_MAX_MTREE_LEVELS]; + + u32 hash_tree_area_size; + + /* Number of levels in hash_level_suboffset */ + int depth; +}; + +struct signature_info { + struct mem_range root_hash; + + struct mem_range additional_data; + + struct mem_range signature; + + enum incfs_hash_tree_algorithm hash_alg; +}; + +struct incfs_hash_alg *incfs_get_hash_alg(enum incfs_hash_tree_algorithm id); + +struct mtree *incfs_alloc_mtree(enum incfs_hash_tree_algorithm id, + int data_block_count, + struct mem_range root_hash); + +void incfs_free_mtree(struct mtree *tree); + +size_t incfs_get_mtree_depth(enum incfs_hash_tree_algorithm alg, loff_t size); + +size_t incfs_get_mtree_hash_count(enum incfs_hash_tree_algorithm alg, + loff_t size); + +int incfs_calc_digest(struct incfs_hash_alg *alg, struct mem_range data, + struct mem_range digest); + +int incfs_validate_pkcs7_signature(struct mem_range pkcs7_blob, + struct mem_range root_hash, struct mem_range add_data); + +void incfs_free_signature_info(struct signature_info *si); + +#endif /* _INCFS_INTEGRITY_H */ diff --git a/fs/incfs/internal.h b/fs/incfs/internal.h new file mode 100644 index 000000000000..0a85eaed41d3 --- /dev/null +++ b/fs/incfs/internal.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2018 Google LLC + */ +#ifndef _INCFS_INTERNAL_H +#define _INCFS_INTERNAL_H +#include + +struct mem_range { + u8 *data; + size_t len; +}; + +static inline struct mem_range range(u8 *data, size_t len) +{ + return (struct mem_range){ .data = data, .len = len }; +} + +#define LOCK_REQUIRED(lock) WARN_ON_ONCE(!mutex_is_locked(&lock)) + +#endif /* _INCFS_INTERNAL_H */ diff --git a/fs/incfs/main.c b/fs/incfs/main.c new file mode 100644 index 000000000000..d9eec7496846 --- /dev/null +++ b/fs/incfs/main.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 Google LLC + */ +#include +#include +#include + +#include + +#include "vfs.h" + +#define INCFS_NODE_FEATURES "features" + +struct file_system_type incfs_fs_type = { + .owner = THIS_MODULE, + .name = INCFS_NAME, + .mount = incfs_mount_fs, + .kill_sb = incfs_kill_sb, + .fs_flags = 0 +}; + +static struct kobject *sysfs_root, *featurefs_root; + +static ssize_t corefs_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buff) +{ + return snprintf(buff, PAGE_SIZE, "supported\n"); +} + +static struct kobj_attribute corefs_attr = __ATTR_RO(corefs); + +static struct attribute *attributes[] = { + &corefs_attr.attr, + NULL, +}; + +static const struct attribute_group attr_group = { + .attrs = attributes, +}; + +static int __init init_sysfs(void) +{ + int res = 0; + + sysfs_root = kobject_create_and_add(INCFS_NAME, fs_kobj); + if (!sysfs_root) + return -ENOMEM; + + featurefs_root = kobject_create_and_add(INCFS_NODE_FEATURES, + sysfs_root); + if (!featurefs_root) + return -ENOMEM; + + res = sysfs_create_group(featurefs_root, &attr_group); + if (res) { + kobject_put(sysfs_root); + sysfs_root = NULL; + } + return res; +} + +static void cleanup_sysfs(void) +{ + if (featurefs_root) { + sysfs_remove_group(featurefs_root, &attr_group); + kobject_put(featurefs_root); + featurefs_root = NULL; + } + + if (sysfs_root) { + kobject_put(sysfs_root); + sysfs_root = NULL; + } +} + +static int __init init_incfs_module(void) +{ + int err = 0; + + err = init_sysfs(); + if (err) + return err; + + err = register_filesystem(&incfs_fs_type); + if (err) + cleanup_sysfs(); + + return err; +} + +static void __exit cleanup_incfs_module(void) +{ + cleanup_sysfs(); + unregister_filesystem(&incfs_fs_type); +} + +module_init(init_incfs_module); +module_exit(cleanup_incfs_module); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Eugene Zemtsov "); +MODULE_DESCRIPTION("Incremental File System"); diff --git a/fs/incfs/vfs.c b/fs/incfs/vfs.c new file mode 100644 index 000000000000..41efd70af8e1 --- /dev/null +++ b/fs/incfs/vfs.c @@ -0,0 +1,2203 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "compat.h" +#include "data_mgmt.h" +#include "format.h" +#include "integrity.h" +#include "internal.h" + +#define INCFS_PENDING_READS_INODE 2 +#define INCFS_LOG_INODE 3 +#define INCFS_START_INO_RANGE 10 +#define READ_FILE_MODE 0444 +#define READ_EXEC_FILE_MODE 0555 +#define READ_WRITE_FILE_MODE 0666 + +static int incfs_remount_fs(struct super_block *sb, int *flags, char *data); + +static int dentry_revalidate(struct dentry *dentry, unsigned int flags); +static void dentry_release(struct dentry *d); + +static int iterate_incfs_dir(struct file *file, struct dir_context *ctx); +static struct dentry *dir_lookup(struct inode *dir_inode, + struct dentry *dentry, unsigned int flags); +static int dir_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); +static int dir_unlink(struct inode *dir, struct dentry *dentry); +static int dir_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *new_dentry); +static int dir_rmdir(struct inode *dir, struct dentry *dentry); +static int dir_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry); + +static int file_open(struct inode *inode, struct file *file); +static int file_release(struct inode *inode, struct file *file); +static ssize_t file_write(struct file *f, const char __user *buf, + size_t size, loff_t *offset); +static int read_single_page(struct file *f, struct page *page); +static long dispatch_ioctl(struct file *f, unsigned int req, unsigned long arg); + +static ssize_t pending_reads_read(struct file *f, char __user *buf, size_t len, + loff_t *ppos); +static __poll_t pending_reads_poll(struct file *file, poll_table *wait); +static int pending_reads_open(struct inode *inode, struct file *file); +static int pending_reads_release(struct inode *, struct file *); + +static ssize_t log_read(struct file *f, char __user *buf, size_t len, + loff_t *ppos); +static __poll_t log_poll(struct file *file, poll_table *wait); +static int log_open(struct inode *inode, struct file *file); +static int log_release(struct inode *, struct file *); + +static struct inode *alloc_inode(struct super_block *sb); +static void free_inode(struct inode *inode); +static void evict_inode(struct inode *inode); + +static ssize_t incfs_getxattr(struct dentry *d, const char *name, + void *value, size_t size); +static ssize_t incfs_listxattr(struct dentry *d, char *list, size_t size); + +static int show_options(struct seq_file *, struct dentry *); + +static const struct super_operations incfs_super_ops = { + .statfs = simple_statfs, + .remount_fs = incfs_remount_fs, + .alloc_inode = alloc_inode, + .destroy_inode = free_inode, + .evict_inode = evict_inode, + .show_options = show_options +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) +#define dir_rename_wrap dir_rename +#else +static int dir_rename_wrap(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) +{ + return dir_rename(old_dir, old_dentry, new_dir, new_dentry); +} +#endif + +static const struct inode_operations incfs_dir_inode_ops = { + .lookup = dir_lookup, + .mkdir = dir_mkdir, + .rename = dir_rename_wrap, + .unlink = dir_unlink, + .link = dir_link, + .rmdir = dir_rmdir +}; + +static const struct file_operations incfs_dir_fops = { + .llseek = generic_file_llseek, + .read = generic_read_dir, + .iterate = iterate_incfs_dir, + .open = file_open, + .release = file_release, + .unlocked_ioctl = dispatch_ioctl, + .compat_ioctl = dispatch_ioctl +}; + +static const struct dentry_operations incfs_dentry_ops = { + .d_revalidate = dentry_revalidate, + .d_release = dentry_release +}; + +static const struct address_space_operations incfs_address_space_ops = { + .readpage = read_single_page, + /* .readpages = readpages */ +}; + +static const struct file_operations incfs_file_ops = { + .open = file_open, + .release = file_release, + .write = file_write, + .read_iter = generic_file_read_iter, + .mmap = generic_file_mmap, + .splice_read = generic_file_splice_read, + .llseek = generic_file_llseek, + .unlocked_ioctl = dispatch_ioctl, + .compat_ioctl = dispatch_ioctl +}; + +static const struct file_operations incfs_pending_read_file_ops = { + .read = pending_reads_read, + .poll = pending_reads_poll, + .open = pending_reads_open, + .release = pending_reads_release, + .llseek = noop_llseek, + .unlocked_ioctl = dispatch_ioctl, + .compat_ioctl = dispatch_ioctl +}; + +static const struct file_operations incfs_log_file_ops = { + .read = log_read, + .poll = log_poll, + .open = log_open, + .release = log_release, + .llseek = noop_llseek, + .unlocked_ioctl = dispatch_ioctl, + .compat_ioctl = dispatch_ioctl +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0) + +static const struct inode_operations incfs_file_inode_ops = { + .setattr = simple_setattr, + .getattr = simple_getattr, + .getxattr = incfs_getxattr, + .listxattr = incfs_listxattr +}; + +#else + +static const struct inode_operations incfs_file_inode_ops = { + .setattr = simple_setattr, + .getattr = simple_getattr, + .listxattr = incfs_listxattr +}; + +static int incfs_handler_getxattr(const struct xattr_handler *xh, + struct dentry *d, struct inode *inode, + const char *name, void *buffer, size_t size) +{ + return incfs_getxattr(d, name, buffer, size); +} + +static const struct xattr_handler incfs_xattr_handler = { + .prefix = "", /* AKA all attributes */ + .get = incfs_handler_getxattr, +}; + +const struct xattr_handler *incfs_xattr_ops[] = { + &incfs_xattr_handler, + NULL, +}; + + +#endif + +/* State of an open .pending_reads file, unique for each file descriptor. */ +struct pending_reads_state { + /* A serial number of the last pending read obtained from this file. */ + int last_pending_read_sn; +}; + +/* State of an open .log file, unique for each file descriptor. */ +struct log_file_state { + struct read_log_state state; +}; + +struct inode_search { + unsigned long ino; + + struct dentry *backing_dentry; +}; + +enum parse_parameter { + Opt_read_timeout, + Opt_readahead_pages, + Opt_no_backing_file_cache, + Opt_no_backing_file_readahead, + Opt_rlog_pages, + Opt_rlog_wakeup_cnt, + Opt_err +}; + +static const char pending_reads_file_name[] = INCFS_PENDING_READS_FILENAME; +static struct mem_range pending_reads_file_name_range = { + .data = (u8 *)pending_reads_file_name, + .len = ARRAY_SIZE(pending_reads_file_name) - 1 +}; + +static const char log_file_name[] = INCFS_LOG_FILENAME; +static struct mem_range log_file_name_range = { + .data = (u8 *)log_file_name, + .len = ARRAY_SIZE(log_file_name) - 1 +}; + +static const match_table_t option_tokens = { + { Opt_read_timeout, "read_timeout_ms=%u" }, + { Opt_readahead_pages, "readahead=%u" }, + { Opt_no_backing_file_cache, "no_bf_cache=%u" }, + { Opt_no_backing_file_readahead, "no_bf_readahead=%u" }, + { Opt_rlog_pages, "rlog_pages=%u" }, + { Opt_rlog_wakeup_cnt, "rlog_wakeup_cnt=%u" }, + { Opt_err, NULL } +}; + +static int parse_options(struct mount_options *opts, char *str) +{ + substring_t args[MAX_OPT_ARGS]; + int value; + char *position; + + if (opts == NULL) + return -EFAULT; + + opts->read_timeout_ms = 1000; /* Default: 1s */ + opts->readahead_pages = 10; + opts->read_log_pages = 2; + opts->read_log_wakeup_count = 10; + opts->no_backing_file_cache = false; + opts->no_backing_file_readahead = false; + if (str == NULL || *str == 0) + return 0; + + while ((position = strsep(&str, ",")) != NULL) { + int token; + + if (!*position) + continue; + + token = match_token(position, option_tokens, args); + + switch (token) { + case Opt_read_timeout: + if (match_int(&args[0], &value)) + return -EINVAL; + opts->read_timeout_ms = value; + break; + case Opt_readahead_pages: + if (match_int(&args[0], &value)) + return -EINVAL; + opts->readahead_pages = value; + break; + case Opt_no_backing_file_cache: + if (match_int(&args[0], &value)) + return -EINVAL; + opts->no_backing_file_cache = (value != 0); + break; + case Opt_no_backing_file_readahead: + if (match_int(&args[0], &value)) + return -EINVAL; + opts->no_backing_file_readahead = (value != 0); + break; + case Opt_rlog_pages: + if (match_int(&args[0], &value)) + return -EINVAL; + opts->read_log_pages = value; + break; + case Opt_rlog_wakeup_cnt: + if (match_int(&args[0], &value)) + return -EINVAL; + opts->read_log_wakeup_count = value; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static struct super_block *file_superblock(struct file *f) +{ + struct inode *inode = file_inode(f); + + return inode->i_sb; +} + +static struct mount_info *get_mount_info(struct super_block *sb) +{ + struct mount_info *result = sb->s_fs_info; + + WARN_ON(!result); + return result; +} + +/* Read file size from the attribute. Quicker than reading the header */ +static u64 read_size_attr(struct dentry *backing_dentry) +{ + __le64 attr_value; + ssize_t bytes_read; + + bytes_read = vfs_getxattr(backing_dentry, INCFS_XATTR_SIZE_NAME, + (char *)&attr_value, sizeof(attr_value)); + + if (bytes_read != sizeof(attr_value)) + return 0; + + return le64_to_cpu(attr_value); +} + +static int inode_test(struct inode *inode, void *opaque) +{ + struct inode_search *search = opaque; + struct inode_info *node = get_incfs_node(inode); + + if (!node) + return 0; + + if (search->backing_dentry) { + struct inode *backing_inode = d_inode(search->backing_dentry); + + return (node->n_backing_inode == backing_inode) && + inode->i_ino == search->ino; + } + return 1; +} + +static int inode_set(struct inode *inode, void *opaque) +{ + struct inode_search *search = opaque; + struct inode_info *node = get_incfs_node(inode); + + if (search->backing_dentry) { + /* It's a regular inode that has corresponding backing inode */ + struct dentry *backing_dentry = search->backing_dentry; + struct inode *backing_inode = d_inode(backing_dentry); + + inode_init_owner(inode, NULL, backing_inode->i_mode); + fsstack_copy_attr_all(inode, backing_inode); + if (S_ISREG(inode->i_mode)) { + u64 size = read_size_attr(backing_dentry); + + inode->i_size = size; + inode->i_blocks = get_blocks_count_for_size(size); + inode->i_mapping->a_ops = &incfs_address_space_ops; + inode->i_op = &incfs_file_inode_ops; + inode->i_fop = &incfs_file_ops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_size = 0; + inode->i_blocks = 1; + inode->i_mapping->a_ops = &incfs_address_space_ops; + inode->i_op = &incfs_dir_inode_ops; + inode->i_fop = &incfs_dir_fops; + } else { + pr_warn_once("incfs: Unexpected inode type\n"); + return -EBADF; + } + + ihold(backing_inode); + node->n_backing_inode = backing_inode; + node->n_mount_info = get_mount_info(inode->i_sb); + inode->i_ctime = backing_inode->i_ctime; + inode->i_mtime = backing_inode->i_mtime; + inode->i_atime = backing_inode->i_atime; + inode->i_ino = backing_inode->i_ino; + if (backing_inode->i_ino < INCFS_START_INO_RANGE) { + pr_warn("incfs: ino conflict with backing FS %ld\n", + backing_inode->i_ino); + } + return 0; + } else if (search->ino == INCFS_PENDING_READS_INODE) { + /* It's an inode for .pending_reads pseudo file. */ + + inode->i_ctime = (struct timespec){}; + inode->i_mtime = inode->i_ctime; + inode->i_atime = inode->i_ctime; + inode->i_size = 0; + inode->i_ino = INCFS_PENDING_READS_INODE; + inode->i_private = NULL; + + inode_init_owner(inode, NULL, S_IFREG | READ_WRITE_FILE_MODE); + + inode->i_op = &incfs_file_inode_ops; + inode->i_fop = &incfs_pending_read_file_ops; + + } else if (search->ino == INCFS_LOG_INODE) { + /* It's an inode for .log pseudo file. */ + + inode->i_ctime = (struct timespec){}; + inode->i_mtime = inode->i_ctime; + inode->i_atime = inode->i_ctime; + inode->i_size = 0; + inode->i_ino = INCFS_LOG_INODE; + inode->i_private = NULL; + + inode_init_owner(inode, NULL, S_IFREG | READ_WRITE_FILE_MODE); + + inode->i_op = &incfs_file_inode_ops; + inode->i_fop = &incfs_log_file_ops; + + } else { + /* Unknown inode requested. */ + return -EINVAL; + } + + return 0; +} + +static struct inode *fetch_regular_inode(struct super_block *sb, + struct dentry *backing_dentry) +{ + struct inode *backing_inode = d_inode(backing_dentry); + struct inode_search search = { + .ino = backing_inode->i_ino, + .backing_dentry = backing_dentry + }; + struct inode *inode = iget5_locked(sb, search.ino, inode_test, + inode_set, &search); + + if (!inode) + return ERR_PTR(-ENOMEM); + + if (inode->i_state & I_NEW) + unlock_new_inode(inode); + + return inode; +} + +static ssize_t pending_reads_read(struct file *f, char __user *buf, size_t len, + loff_t *ppos) +{ + struct pending_reads_state *pr_state = f->private_data; + struct mount_info *mi = get_mount_info(file_superblock(f)); + struct incfs_pending_read_info *reads_buf = NULL; + size_t reads_to_collect = len / sizeof(*reads_buf); + int last_known_read_sn = READ_ONCE(pr_state->last_pending_read_sn); + int new_max_sn = last_known_read_sn; + int reads_collected = 0; + ssize_t result = 0; + int i = 0; + + if (!access_ok(VERIFY_WRITE, buf, len)) + return -EFAULT; + + if (!incfs_fresh_pending_reads_exist(mi, last_known_read_sn)) + return 0; + + reads_buf = (struct incfs_pending_read_info *)get_zeroed_page(GFP_NOFS); + if (!reads_buf) + return -ENOMEM; + + reads_to_collect = + min_t(size_t, PAGE_SIZE / sizeof(*reads_buf), reads_to_collect); + + reads_collected = incfs_collect_pending_reads( + mi, last_known_read_sn, reads_buf, reads_to_collect); + if (reads_collected < 0) { + result = reads_collected; + goto out; + } + + for (i = 0; i < reads_collected; i++) + if (reads_buf[i].serial_number > new_max_sn) + new_max_sn = reads_buf[i].serial_number; + + /* + * Just to make sure that we don't accidentally copy more data + * to reads buffer than userspace can handle. + */ + reads_collected = min_t(size_t, reads_collected, reads_to_collect); + result = reads_collected * sizeof(*reads_buf); + + /* Copy reads info to the userspace buffer */ + if (copy_to_user(buf, reads_buf, result)) { + result = -EFAULT; + goto out; + } + + WRITE_ONCE(pr_state->last_pending_read_sn, new_max_sn); + *ppos = 0; +out: + if (reads_buf) + free_page((unsigned long)reads_buf); + return result; +} + + +static __poll_t pending_reads_poll(struct file *file, poll_table *wait) +{ + struct pending_reads_state *state = file->private_data; + struct mount_info *mi = get_mount_info(file_superblock(file)); + __poll_t ret = 0; + + poll_wait(file, &mi->mi_pending_reads_notif_wq, wait); + if (incfs_fresh_pending_reads_exist(mi, + state->last_pending_read_sn)) + ret = EPOLLIN | EPOLLRDNORM; + + return ret; +} + +static int pending_reads_open(struct inode *inode, struct file *file) +{ + struct pending_reads_state *state = NULL; + + state = kzalloc(sizeof(*state), GFP_NOFS); + if (!state) + return -ENOMEM; + + file->private_data = state; + return 0; +} + +static int pending_reads_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +static struct inode *fetch_pending_reads_inode(struct super_block *sb) +{ + struct inode_search search = { + .ino = INCFS_PENDING_READS_INODE + }; + struct inode *inode = iget5_locked(sb, search.ino, inode_test, + inode_set, &search); + + if (!inode) + return ERR_PTR(-ENOMEM); + + if (inode->i_state & I_NEW) + unlock_new_inode(inode); + + return inode; +} + +static int log_open(struct inode *inode, struct file *file) +{ + struct log_file_state *log_state = NULL; + struct mount_info *mi = get_mount_info(file_superblock(file)); + + log_state = kzalloc(sizeof(*log_state), GFP_NOFS); + if (!log_state) + return -ENOMEM; + + log_state->state = incfs_get_log_state(mi); + file->private_data = log_state; + return 0; +} + +static int log_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +static ssize_t log_read(struct file *f, char __user *buf, size_t len, + loff_t *ppos) +{ + struct log_file_state *log_state = f->private_data; + struct mount_info *mi = get_mount_info(file_superblock(f)); + struct incfs_pending_read_info *reads_buf = + (struct incfs_pending_read_info *)__get_free_page(GFP_NOFS); + size_t reads_to_collect = len / sizeof(*reads_buf); + size_t reads_per_page = PAGE_SIZE / sizeof(*reads_buf); + int total_reads_collected = 0; + ssize_t result = 0; + + if (!reads_buf) + return -ENOMEM; + + reads_to_collect = min_t(size_t, mi->mi_log.rl_size, reads_to_collect); + while (reads_to_collect > 0) { + struct read_log_state next_state = READ_ONCE(log_state->state); + int reads_collected = incfs_collect_logged_reads( + mi, &next_state, reads_buf, + min_t(size_t, reads_to_collect, reads_per_page)); + if (reads_collected <= 0) { + result = total_reads_collected ? + total_reads_collected * + sizeof(*reads_buf) : + reads_collected; + goto out; + } + if (copy_to_user(buf, reads_buf, + reads_collected * sizeof(*reads_buf))) { + result = total_reads_collected ? + total_reads_collected * + sizeof(*reads_buf) : + -EFAULT; + goto out; + } + + WRITE_ONCE(log_state->state, next_state); + total_reads_collected += reads_collected; + buf += reads_collected * sizeof(*reads_buf); + reads_to_collect -= reads_collected; + } + + result = total_reads_collected * sizeof(*reads_buf); + *ppos = 0; +out: + if (reads_buf) + free_page((unsigned long)reads_buf); + return result; +} + +static __poll_t log_poll(struct file *file, poll_table *wait) +{ + struct log_file_state *log_state = file->private_data; + struct mount_info *mi = get_mount_info(file_superblock(file)); + int count; + __poll_t ret = 0; + + poll_wait(file, &mi->mi_log.ml_notif_wq, wait); + count = incfs_get_uncollected_logs_count(mi, log_state->state); + if (count >= mi->mi_options.read_log_wakeup_count) + ret = EPOLLIN | EPOLLRDNORM; + + return ret; +} + +static struct inode *fetch_log_inode(struct super_block *sb) +{ + struct inode_search search = { + .ino = INCFS_LOG_INODE + }; + struct inode *inode = iget5_locked(sb, search.ino, inode_test, + inode_set, &search); + + if (!inode) + return ERR_PTR(-ENOMEM); + + if (inode->i_state & I_NEW) + unlock_new_inode(inode); + + return inode; +} + +static int iterate_incfs_dir(struct file *file, struct dir_context *ctx) +{ + struct dir_file *dir = get_incfs_dir_file(file); + int error = 0; + struct mount_info *mi = get_mount_info(file_superblock(file)); + bool root; + + if (!dir) { + error = -EBADF; + goto out; + } + + root = dir->backing_dir->f_inode + == d_inode(mi->mi_backing_dir_path.dentry); + + if (root && ctx->pos == 0) { + if (!dir_emit(ctx, pending_reads_file_name, + ARRAY_SIZE(pending_reads_file_name) - 1, + INCFS_PENDING_READS_INODE, DT_REG)) { + error = -EINVAL; + goto out; + } + ctx->pos++; + } + + if (root && ctx->pos == 1) { + if (!dir_emit(ctx, log_file_name, + ARRAY_SIZE(log_file_name) - 1, + INCFS_LOG_INODE, DT_REG)) { + error = -EINVAL; + goto out; + } + ctx->pos++; + } + + ctx->pos -= 2; + error = iterate_dir(dir->backing_dir, ctx); + ctx->pos += 2; + file->f_pos = dir->backing_dir->f_pos; +out: + if (error) + pr_warn("incfs: %s %s %d\n", __func__, + file->f_path.dentry->d_name.name, error); + return error; +} + +static int incfs_init_dentry(struct dentry *dentry, struct path *path) +{ + struct dentry_info *d_info = NULL; + + if (!dentry || !path) + return -EFAULT; + + d_info = kzalloc(sizeof(*d_info), GFP_NOFS); + if (!d_info) + return -ENOMEM; + + d_info->backing_path = *path; + path_get(path); + + dentry->d_fsdata = d_info; + return 0; +} + +static struct dentry *incfs_lookup_dentry(struct dentry *parent, + const char *name) +{ + struct inode *inode; + struct dentry *result = NULL; + + if (!parent) + return ERR_PTR(-EFAULT); + + inode = d_inode(parent); + inode_lock_nested(inode, I_MUTEX_PARENT); + result = lookup_one_len(name, parent, strlen(name)); + inode_unlock(inode); + + if (IS_ERR(result)) + pr_warn("%s err:%ld\n", __func__, PTR_ERR(result)); + + return result; +} + +static struct dentry *open_or_create_index_dir(struct dentry *backing_dir) +{ + static const char name[] = ".index"; + struct dentry *index_dentry; + struct inode *backing_inode = d_inode(backing_dir); + int err = 0; + + index_dentry = incfs_lookup_dentry(backing_dir, name); + if (!index_dentry) { + return ERR_PTR(-EINVAL); + } else if (IS_ERR(index_dentry)) { + return index_dentry; + } else if (d_really_is_positive(index_dentry)) { + /* Index already exists. */ + return index_dentry; + } + + /* Index needs to be created. */ + inode_lock_nested(backing_inode, I_MUTEX_PARENT); + err = vfs_mkdir(backing_inode, index_dentry, 0777); + inode_unlock(backing_inode); + + if (err) + return ERR_PTR(err); + + if (!d_really_is_positive(index_dentry)) { + dput(index_dentry); + return ERR_PTR(-EINVAL); + } + + return index_dentry; +} + +static int read_single_page(struct file *f, struct page *page) +{ + loff_t offset = 0; + loff_t size = 0; + ssize_t bytes_to_read = 0; + ssize_t read_result = 0; + struct data_file *df = get_incfs_data_file(f); + int result = 0; + void *page_start = kmap(page); + int block_index; + int timeout_ms; + + if (!df) + return -EBADF; + + offset = page_offset(page); + block_index = offset / INCFS_DATA_FILE_BLOCK_SIZE; + size = df->df_size; + timeout_ms = df->df_mount_info->mi_options.read_timeout_ms; + + pr_debug("incfs: %s %s %lld\n", __func__, + f->f_path.dentry->d_name.name, offset); + + if (offset < size) { + struct mem_range tmp = { + .len = 2 * INCFS_DATA_FILE_BLOCK_SIZE + }; + + tmp.data = (u8 *)__get_free_pages(GFP_NOFS, get_order(tmp.len)); + bytes_to_read = min_t(loff_t, size - offset, PAGE_SIZE); + read_result = incfs_read_data_file_block( + range(page_start, bytes_to_read), df, block_index, + timeout_ms, tmp); + + free_pages((unsigned long)tmp.data, get_order(tmp.len)); + } else { + bytes_to_read = 0; + read_result = 0; + } + + if (read_result < 0) + result = read_result; + else if (read_result < PAGE_SIZE) + zero_user(page, read_result, PAGE_SIZE - read_result); + + if (result == 0) + SetPageUptodate(page); + else + SetPageError(page); + + flush_dcache_page(page); + kunmap(page); + unlock_page(page); + return result; +} + +static char *file_id_to_str(incfs_uuid_t id) +{ + char *result = kmalloc(1 + sizeof(id.bytes) * 2, GFP_NOFS); + char *end; + + if (!result) + return NULL; + + end = bin2hex(result, id.bytes, sizeof(id.bytes)); + *end = 0; + return result; +} + +static struct signature_info *incfs_copy_signature_info_from_user( + struct incfs_file_signature_info __user *original) +{ + struct incfs_file_signature_info usr_si; + struct signature_info *result; + int error; + + if (!original) + return NULL; + + if (!access_ok(VERIFY_READ, original, sizeof(usr_si))) + return ERR_PTR(-EFAULT); + + if (copy_from_user(&usr_si, original, sizeof(usr_si)) > 0) + return ERR_PTR(-EFAULT); + + result = kzalloc(sizeof(*result), GFP_NOFS); + if (!result) + return ERR_PTR(-ENOMEM); + + result->hash_alg = usr_si.hash_tree_alg; + + if (result->hash_alg) { + void *p = kzalloc(INCFS_MAX_HASH_SIZE, GFP_NOFS); + + if (!p) { + error = -ENOMEM; + goto err; + } + + // TODO this sets the root_hash length to MAX_HASH_SIZE not + // the actual size. Fix, then set INCFS_MAX_HASH_SIZE back + // to 64 + result->root_hash = range(p, INCFS_MAX_HASH_SIZE); + if (copy_from_user(p, u64_to_user_ptr(usr_si.root_hash), + result->root_hash.len) > 0) { + error = -EFAULT; + goto err; + } + } + + if (usr_si.additional_data_size > INCFS_MAX_FILE_ATTR_SIZE) { + error = -E2BIG; + goto err; + } + + if (usr_si.additional_data && usr_si.additional_data_size) { + void *p = kzalloc(usr_si.additional_data_size, GFP_NOFS); + + if (!p) { + error = -ENOMEM; + goto err; + } + result->additional_data = range(p, + usr_si.additional_data_size); + if (copy_from_user(p, u64_to_user_ptr(usr_si.additional_data), + result->additional_data.len) > 0) { + error = -EFAULT; + goto err; + } + } + + if (usr_si.signature_size > INCFS_MAX_SIGNATURE_SIZE) { + error = -E2BIG; + goto err; + } + + if (usr_si.signature && usr_si.signature_size) { + void *p = kzalloc(usr_si.signature_size, GFP_NOFS); + + if (!p) { + error = -ENOMEM; + goto err; + } + result->signature = range(p, usr_si.signature_size); + if (copy_from_user(p, u64_to_user_ptr(usr_si.signature), + result->signature.len) > 0) { + error = -EFAULT; + goto err; + } + } + + return result; + +err: + incfs_free_signature_info(result); + return ERR_PTR(-error); +} + +static int init_new_file(struct mount_info *mi, struct dentry *dentry, + incfs_uuid_t *uuid, u64 size, struct mem_range attr, + struct incfs_file_signature_info __user *fsi) +{ + struct path path = {}; + struct file *new_file; + int error = 0; + struct backing_file_context *bfc = 0; + u32 block_count; + struct mem_range mem_range = {0}; + struct signature_info *si = 0; + struct mtree *hash_tree = 0; + + if (!mi || !dentry || !uuid) + return -EFAULT; + + /* Resize newly created file to its true size. */ + path = (struct path) { + .mnt = mi->mi_backing_dir_path.mnt, + .dentry = dentry + }; + new_file = dentry_open(&path, O_RDWR | O_NOATIME, mi->mi_owner); + + if (IS_ERR(new_file)) { + error = PTR_ERR(new_file); + goto out; + } + + bfc = incfs_alloc_bfc(new_file); + if (IS_ERR(bfc)) { + error = PTR_ERR(bfc); + bfc = NULL; + goto out; + } + + mutex_lock(&bfc->bc_mutex); + error = incfs_write_fh_to_backing_file(bfc, uuid, size); + if (error) + goto out; + + block_count = (u32)get_blocks_count_for_size(size); + error = incfs_write_blockmap_to_backing_file(bfc, block_count, NULL); + if (error) + goto out; + + /* This fill has data, reserve space for the block map. */ + if (block_count > 0) { + error = incfs_write_blockmap_to_backing_file( + bfc, block_count, NULL); + if (error) + goto out; + } + + if (attr.data && attr.len) { + error = incfs_write_file_attr_to_backing_file(bfc, + attr, NULL); + if (error) + goto out; + } + + if (fsi) { + si = incfs_copy_signature_info_from_user(fsi); + + if (IS_ERR(si)) { + error = PTR_ERR(si); + si = NULL; + goto out; + } + + if (si->hash_alg) { + hash_tree = incfs_alloc_mtree(si->hash_alg, block_count, + si->root_hash); + if (IS_ERR(hash_tree)) { + error = PTR_ERR(hash_tree); + hash_tree = NULL; + goto out; + } + + // TODO This code seems wrong when len is zero - we + // should error out?? + if (si->signature.len > 0) + error = incfs_validate_pkcs7_signature( + si->signature, + si->root_hash, + si->additional_data); + if (error) + goto out; + + error = incfs_write_signature_to_backing_file(bfc, + si->hash_alg, + hash_tree->hash_tree_area_size, + si->root_hash, si->additional_data, + si->signature); + + if (error) + goto out; + } + } + +out: + if (bfc) { + mutex_unlock(&bfc->bc_mutex); + incfs_free_bfc(bfc); + } + incfs_free_mtree(hash_tree); + incfs_free_signature_info(si); + kfree(mem_range.data); + + if (error) + pr_debug("incfs: %s error: %d\n", __func__, error); + return error; +} + +static int incfs_link(struct dentry *what, struct dentry *where) +{ + struct dentry *parent_dentry = dget_parent(where); + struct inode *pinode = d_inode(parent_dentry); + int error = 0; + + inode_lock_nested(pinode, I_MUTEX_PARENT); + error = vfs_link(what, pinode, where, NULL); + inode_unlock(pinode); + + dput(parent_dentry); + return error; +} + +static int incfs_unlink(struct dentry *dentry) +{ + struct dentry *parent_dentry = dget_parent(dentry); + struct inode *pinode = d_inode(parent_dentry); + int error = 0; + + inode_lock_nested(pinode, I_MUTEX_PARENT); + error = vfs_unlink(pinode, dentry, NULL); + inode_unlock(pinode); + + dput(parent_dentry); + return error; +} + +static int incfs_rmdir(struct dentry *dentry) +{ + struct dentry *parent_dentry = dget_parent(dentry); + struct inode *pinode = d_inode(parent_dentry); + int error = 0; + + inode_lock_nested(pinode, I_MUTEX_PARENT); + error = vfs_rmdir(pinode, dentry); + inode_unlock(pinode); + + dput(parent_dentry); + return error; +} + +static int dir_relative_path_resolve( + struct mount_info *mi, + const char __user *relative_path, + struct path *result_path) +{ + struct path *base_path = &mi->mi_backing_dir_path; + int dir_fd = get_unused_fd_flags(0); + struct file *dir_f = NULL; + int error = 0; + + if (dir_fd < 0) + return dir_fd; + + dir_f = dentry_open(base_path, O_RDONLY | O_NOATIME, mi->mi_owner); + + if (IS_ERR(dir_f)) { + error = PTR_ERR(dir_f); + goto out; + } + fd_install(dir_fd, dir_f); + + if (!relative_path) { + /* No relative path given, just return the base dir. */ + *result_path = *base_path; + path_get(result_path); + goto out; + } + + error = user_path_at_empty(dir_fd, relative_path, + LOOKUP_FOLLOW | LOOKUP_DIRECTORY, result_path, NULL); + +out: + // TODO sys_close should be replaced with ksys_close on later kernel + // Add to compat or some such? + sys_close(dir_fd); + if (error) + pr_debug("incfs: %s %d\n", __func__, error); + return error; +} + +static int validate_name(char *file_name) +{ + struct mem_range name = range(file_name, strlen(file_name)); + int i = 0; + + if (name.len > INCFS_MAX_NAME_LEN) + return -ENAMETOOLONG; + + if (incfs_equal_ranges(pending_reads_file_name_range, name)) + return -EINVAL; + + for (i = 0; i < name.len; i++) + if (name.data[i] == '/') + return -EINVAL; + + return 0; +} + +static long ioctl_create_file(struct mount_info *mi, + struct incfs_new_file_args __user *usr_args) +{ + struct incfs_new_file_args args; + char *file_id_str = NULL; + struct dentry *index_file_dentry = NULL; + struct dentry *named_file_dentry = NULL; + struct path parent_dir_path = {}; + struct inode *index_dir_inode = NULL; + __le64 size_attr_value = 0; + char *file_name = NULL; + char *attr_value = NULL; + int error = 0; + bool locked = false; + + if (!mi || !mi->mi_index_dir) { + error = -EFAULT; + goto out; + } + if (!access_ok(VERIFY_READ, usr_args, sizeof(args))) { + error = -EFAULT; + goto out; + } + if (copy_from_user(&args, usr_args, sizeof(args)) > 0) { + error = -EFAULT; + goto out; + } + + file_name = strndup_user(u64_to_user_ptr(args.file_name), PATH_MAX); + if (IS_ERR(file_name)) { + error = PTR_ERR(file_name); + file_name = NULL; + goto out; + } + + error = validate_name(file_name); + if (error) + goto out; + + file_id_str = file_id_to_str(args.file_id); + if (!file_id_str) { + error = -ENOMEM; + goto out; + } + + error = mutex_lock_interruptible(&mi->mi_dir_struct_mutex); + if (error) + goto out; + locked = true; + + /* Find a directory to put the file into. */ + error = dir_relative_path_resolve(mi, + u64_to_user_ptr(args.directory_path), + &parent_dir_path); + if (error) + goto out; + + if (parent_dir_path.dentry == mi->mi_index_dir) { + /* Can't create a file directly inside .index */ + error = -EBUSY; + goto out; + } + + /* Look up a dentry in the parent dir. It should be negative. */ + named_file_dentry = incfs_lookup_dentry(parent_dir_path.dentry, + file_name); + if (!named_file_dentry) { + error = -EFAULT; + goto out; + } + if (IS_ERR(named_file_dentry)) { + error = PTR_ERR(named_file_dentry); + named_file_dentry = NULL; + goto out; + } + if (d_really_is_positive(named_file_dentry)) { + /* File with this path already exists. */ + error = -EEXIST; + goto out; + } + /* Look up a dentry in the .index dir. It should be negative. */ + index_file_dentry = incfs_lookup_dentry(mi->mi_index_dir, file_id_str); + if (!index_file_dentry) { + error = -EFAULT; + goto out; + } + if (IS_ERR(index_file_dentry)) { + error = PTR_ERR(index_file_dentry); + index_file_dentry = NULL; + goto out; + } + if (d_really_is_positive(index_file_dentry)) { + /* File with this ID already exists in index. */ + error = -EEXIST; + goto out; + } + + /* Creating a file in the .index dir. */ + index_dir_inode = d_inode(mi->mi_index_dir); + inode_lock_nested(index_dir_inode, I_MUTEX_PARENT); + error = vfs_create(index_dir_inode, index_file_dentry, + args.mode, true); + inode_unlock(index_dir_inode); + + if (error) + goto out; + if (!d_really_is_positive(index_file_dentry)) { + error = -EINVAL; + goto out; + } + + /* Save the file's ID as an xattr for easy fetching in future. */ + error = vfs_setxattr(index_file_dentry, INCFS_XATTR_ID_NAME, + file_id_str, strlen(file_id_str), XATTR_CREATE); + if (error) { + pr_debug("incfs: vfs_setxattr err:%d\n", error); + goto delete_index_file; + } + + /* Save the file's size as an xattr for easy fetching in future. */ + size_attr_value = cpu_to_le64(args.size); + error = vfs_setxattr(index_file_dentry, INCFS_XATTR_SIZE_NAME, + (char *)&size_attr_value, sizeof(size_attr_value), + XATTR_CREATE); + if (error) { + pr_debug("incfs: vfs_setxattr err:%d\n", error); + goto delete_index_file; + } + + /* Save the file's attrubute as an xattr */ + if (args.file_attr_len && args.file_attr) { + if (args.file_attr_len > INCFS_MAX_FILE_ATTR_SIZE) { + error = -E2BIG; + goto delete_index_file; + } + + attr_value = kmalloc(args.file_attr_len, GFP_NOFS); + if (!attr_value) { + error = -ENOMEM; + goto delete_index_file; + } + + if (!access_ok(VERIFY_READ, u64_to_user_ptr(args.file_attr), + args.file_attr_len)) { + error = -EFAULT; + goto delete_index_file; + } + + if (copy_from_user(attr_value, + u64_to_user_ptr(args.file_attr), + args.file_attr_len) > 0) { + error = -EFAULT; + goto delete_index_file; + } + + error = vfs_setxattr(index_file_dentry, + INCFS_XATTR_METADATA_NAME, + attr_value, args.file_attr_len, + XATTR_CREATE); + + if (error) + goto delete_index_file; + } + + /* Initializing a newly created file. */ + error = init_new_file(mi, index_file_dentry, &args.file_id, args.size, + range(attr_value, args.file_attr_len), + (struct incfs_file_signature_info __user *) + args.signature_info); + if (error) + goto delete_index_file; + + /* Linking a file with it's real name from the requested dir. */ + error = incfs_link(index_file_dentry, named_file_dentry); + + if (!error) + goto out; + +delete_index_file: + incfs_unlink(index_file_dentry); + +out: + if (error) + pr_debug("incfs: %s err:%d\n", __func__, error); + + kfree(file_id_str); + kfree(file_name); + kfree(attr_value); + dput(named_file_dentry); + dput(index_file_dentry); + path_put(&parent_dir_path); + if (locked) + mutex_unlock(&mi->mi_dir_struct_mutex); + return error; +} + +static long ioctl_read_file_signature(struct file *f, void __user *arg) +{ + struct incfs_get_file_sig_args __user *args_usr_ptr = arg; + struct incfs_get_file_sig_args args = {}; + u8 *sig_buffer = NULL; + size_t sig_buf_size = 0; + int error = 0; + int read_result = 0; + struct data_file *df = get_incfs_data_file(f); + + if (!df) + return -EINVAL; + + if (!access_ok(VERIFY_READ, args_usr_ptr, sizeof(args))) + return -EFAULT; + if (copy_from_user(&args, args_usr_ptr, sizeof(args)) > 0) + return -EINVAL; + + if (!access_ok(VERIFY_WRITE, u64_to_user_ptr(args.file_signature), + args.file_signature_buf_size)) + return -EFAULT; + + sig_buf_size = args.file_signature_buf_size; + if (sig_buf_size > INCFS_MAX_SIGNATURE_SIZE) + return -E2BIG; + + sig_buffer = kzalloc(sig_buf_size, GFP_NOFS); + if (!sig_buffer) + return -ENOMEM; + + read_result = incfs_read_file_signature(df, + range(sig_buffer, sig_buf_size)); + + if (read_result < 0) { + error = read_result; + goto out; + } + + if (copy_to_user(u64_to_user_ptr(args.file_signature), sig_buffer, + read_result)) { + error = -EFAULT; + goto out; + } + + args.file_signature_len_out = read_result; + if (copy_to_user(args_usr_ptr, &args, sizeof(args))) + error = -EFAULT; + +out: + kfree(sig_buffer); + + return error; +} + +static long dispatch_ioctl(struct file *f, unsigned int req, unsigned long arg) +{ + struct mount_info *mi = get_mount_info(file_superblock(f)); + + switch (req) { + case INCFS_IOC_CREATE_FILE: + return ioctl_create_file(mi, (void __user *)arg); + case INCFS_IOC_READ_FILE_SIGNATURE: + return ioctl_read_file_signature(f, (void __user *)arg); + default: + return -EINVAL; + } +} + +static struct dentry *dir_lookup(struct inode *dir_inode, struct dentry *dentry, + unsigned int flags) +{ + struct mount_info *mi = get_mount_info(dir_inode->i_sb); + struct dentry *dir_dentry = NULL; + struct dentry *backing_dentry = NULL; + struct path dir_backing_path = {}; + struct inode_info *dir_info = get_incfs_node(dir_inode); + struct mem_range name_range = + range((u8 *)dentry->d_name.name, dentry->d_name.len); + int err = 0; + + if (d_inode(mi->mi_backing_dir_path.dentry) == + dir_info->n_backing_inode) { + /* We do lookup in the FS root. Show pseudo files. */ + + if (incfs_equal_ranges(pending_reads_file_name_range, + name_range)) { + struct inode *inode = fetch_pending_reads_inode( + dir_inode->i_sb); + + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + + d_add(dentry, inode); + goto out; + } + + if (incfs_equal_ranges(log_file_name_range, name_range)) { + struct inode *inode = fetch_log_inode( + dir_inode->i_sb); + + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + + d_add(dentry, inode); + goto out; + } + } + + dir_dentry = dget_parent(dentry); + get_incfs_backing_path(dir_dentry, &dir_backing_path); + backing_dentry = incfs_lookup_dentry(dir_backing_path.dentry, + dentry->d_name.name); + + if (!backing_dentry || IS_ERR(backing_dentry)) { + err = IS_ERR(backing_dentry) + ? PTR_ERR(backing_dentry) + : -EFAULT; + goto out; + } else { + struct inode *inode = NULL; + struct path backing_path = { + .mnt = dir_backing_path.mnt, + .dentry = backing_dentry + }; + + err = incfs_init_dentry(dentry, &backing_path); + if (err) + goto out; + + if (!d_really_is_positive(backing_dentry)) { + /* + * No such entry found in the backing dir. + * Create a negative entry. + */ + d_add(dentry, NULL); + err = 0; + goto out; + } + + if (d_inode(backing_dentry)->i_sb != + dir_info->n_backing_inode->i_sb) { + /* + * Somehow after the path lookup we ended up in a + * different fs mount. If we keep going it's going + * to end badly. + */ + err = -EXDEV; + goto out; + } + + inode = fetch_regular_inode(dir_inode->i_sb, backing_dentry); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + + d_add(dentry, inode); + } + +out: + dput(dir_dentry); + dput(backing_dentry); + path_put(&dir_backing_path); + if (err) + pr_debug("incfs: %s %s %d\n", __func__, + dentry->d_name.name, err); + return ERR_PTR(err); +} + +static int dir_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + struct mount_info *mi = get_mount_info(dir->i_sb); + struct inode_info *dir_node = get_incfs_node(dir); + struct dentry *backing_dentry = NULL; + struct path backing_path = {}; + int err = 0; + + + if (!mi || !dir_node || !dir_node->n_backing_inode) + return -EBADF; + + err = mutex_lock_interruptible(&mi->mi_dir_struct_mutex); + if (err) + return err; + + get_incfs_backing_path(dentry, &backing_path); + backing_dentry = backing_path.dentry; + + if (!backing_dentry) { + err = -EBADF; + goto out; + } + + if (backing_dentry->d_parent == mi->mi_index_dir) { + /* Can't create a subdir inside .index */ + err = -EBUSY; + goto out; + } + + inode_lock_nested(dir_node->n_backing_inode, I_MUTEX_PARENT); + err = vfs_mkdir(dir_node->n_backing_inode, backing_dentry, mode); + inode_unlock(dir_node->n_backing_inode); + if (!err) { + struct inode *inode = NULL; + + if (d_really_is_negative(backing_dentry)) { + err = -EINVAL; + goto out; + } + + inode = fetch_regular_inode(dir->i_sb, backing_dentry); + if (IS_ERR(inode)) { + err = PTR_ERR(inode); + goto out; + } + d_instantiate(dentry, inode); + } + +out: + if (d_really_is_negative(dentry)) + d_drop(dentry); + path_put(&backing_path); + mutex_unlock(&mi->mi_dir_struct_mutex); + if (err) + pr_debug("incfs: %s err:%d\n", __func__, err); + return err; +} + +/* Delete file referenced by backing_dentry and also its hardlink from .index */ +static int final_file_delete(struct mount_info *mi, + struct dentry *backing_dentry) +{ + struct dentry *index_file_dentry = NULL; + /* 2 chars per byte of file ID + 1 char for \0 */ + char file_id_str[2 * sizeof(incfs_uuid_t) + 1] = {0}; + ssize_t uuid_size = 0; + int error = 0; + + WARN_ON(!mutex_is_locked(&mi->mi_dir_struct_mutex)); + uuid_size = vfs_getxattr(backing_dentry, INCFS_XATTR_ID_NAME, + file_id_str, 2 * sizeof(incfs_uuid_t)); + if (uuid_size < 0) { + error = uuid_size; + goto out; + } + + if (uuid_size != 2 * sizeof(incfs_uuid_t)) { + error = -EBADMSG; + goto out; + } + + index_file_dentry = incfs_lookup_dentry(mi->mi_index_dir, file_id_str); + if (IS_ERR(index_file_dentry)) { + error = PTR_ERR(index_file_dentry); + goto out; + } + + error = incfs_unlink(backing_dentry); + if (error) + goto out; + + if (d_really_is_positive(index_file_dentry)) + error = incfs_unlink(index_file_dentry); +out: + if (error) + pr_debug("incfs: delete_file_from_index err:%d\n", error); + return error; +} + +static int dir_unlink(struct inode *dir, struct dentry *dentry) +{ + struct mount_info *mi = get_mount_info(dir->i_sb); + struct path backing_path = {}; + struct kstat stat; + int err = 0; + + err = mutex_lock_interruptible(&mi->mi_dir_struct_mutex); + if (err) + return err; + + get_incfs_backing_path(dentry, &backing_path); + if (!backing_path.dentry) { + err = -EBADF; + goto out; + } + + if (backing_path.dentry->d_parent == mi->mi_index_dir) { + /* Direct unlink from .index are not allowed. */ + err = -EBUSY; + goto out; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) + err = vfs_getattr(&backing_path, &stat); +#else + err = vfs_getattr(&backing_path, &stat, STATX_NLINK, + AT_STATX_SYNC_AS_STAT); +#endif + if (err) + goto out; + + if (stat.nlink == 2) { + /* + * This is the last named link to this file. The only one left + * is in .index. Remove them both now. + */ + err = final_file_delete(mi, backing_path.dentry); + } else { + /* There are other links to this file. Remove just this one. */ + err = incfs_unlink(backing_path.dentry); + } + + d_drop(dentry); +out: + path_put(&backing_path); + if (err) + pr_debug("incfs: %s err:%d\n", __func__, err); + mutex_unlock(&mi->mi_dir_struct_mutex); + return err; +} + +static int dir_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *new_dentry) +{ + struct mount_info *mi = get_mount_info(dir->i_sb); + struct path backing_old_path = {}; + struct path backing_new_path = {}; + int error = 0; + + error = mutex_lock_interruptible(&mi->mi_dir_struct_mutex); + if (error) + return error; + + get_incfs_backing_path(old_dentry, &backing_old_path); + get_incfs_backing_path(new_dentry, &backing_new_path); + + if (backing_new_path.dentry->d_parent == mi->mi_index_dir) { + /* Can't link to .index */ + error = -EBUSY; + goto out; + } + + error = incfs_link(backing_old_path.dentry, backing_new_path.dentry); + if (!error) { + struct inode *inode = NULL; + struct dentry *bdentry = backing_new_path.dentry; + + if (d_really_is_negative(bdentry)) { + error = -EINVAL; + goto out; + } + + inode = fetch_regular_inode(dir->i_sb, bdentry); + if (IS_ERR(inode)) { + error = PTR_ERR(inode); + goto out; + } + d_instantiate(new_dentry, inode); + } + +out: + path_put(&backing_old_path); + path_put(&backing_new_path); + if (error) + pr_debug("incfs: %s err:%d\n", __func__, error); + mutex_unlock(&mi->mi_dir_struct_mutex); + return error; +} + +static int dir_rmdir(struct inode *dir, struct dentry *dentry) +{ + struct mount_info *mi = get_mount_info(dir->i_sb); + struct path backing_path = {}; + int err = 0; + + err = mutex_lock_interruptible(&mi->mi_dir_struct_mutex); + if (err) + return err; + + get_incfs_backing_path(dentry, &backing_path); + if (!backing_path.dentry) { + err = -EBADF; + goto out; + } + + if (backing_path.dentry == mi->mi_index_dir) { + /* Can't delete .index */ + err = -EBUSY; + goto out; + } + + err = incfs_rmdir(backing_path.dentry); + if (!err) + d_drop(dentry); +out: + path_put(&backing_path); + if (err) + pr_debug("incfs: %s err:%d\n", __func__, err); + mutex_unlock(&mi->mi_dir_struct_mutex); + return err; +} + +static int dir_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + struct mount_info *mi = get_mount_info(old_dir->i_sb); + struct dentry *backing_old_dentry; + struct dentry *backing_new_dentry; + struct dentry *backing_old_dir_dentry; + struct dentry *backing_new_dir_dentry; + struct inode *target_inode; + struct dentry *trap; + int error = 0; + + error = mutex_lock_interruptible(&mi->mi_dir_struct_mutex); + if (error) + return error; + + backing_old_dentry = get_incfs_dentry(old_dentry)->backing_path.dentry; + backing_new_dentry = get_incfs_dentry(new_dentry)->backing_path.dentry; + dget(backing_old_dentry); + dget(backing_new_dentry); + + backing_old_dir_dentry = dget_parent(backing_old_dentry); + backing_new_dir_dentry = dget_parent(backing_new_dentry); + target_inode = d_inode(new_dentry); + + if (backing_old_dir_dentry == mi->mi_index_dir) { + /* Direct moves from .index are not allowed. */ + error = -EBUSY; + goto out; + } + + trap = lock_rename(backing_old_dir_dentry, backing_new_dir_dentry); + + if (trap == backing_old_dentry) { + error = -EINVAL; + goto unlock_out; + } + if (trap == backing_new_dentry) { + error = -ENOTEMPTY; + goto unlock_out; + } + + error = vfs_rename(d_inode(backing_old_dir_dentry), backing_old_dentry, + d_inode(backing_new_dir_dentry), backing_new_dentry, + NULL, 0); + if (error) + goto unlock_out; + if (target_inode) + fsstack_copy_attr_all(target_inode, + get_incfs_node(target_inode)->n_backing_inode); + fsstack_copy_attr_all(new_dir, d_inode(backing_new_dir_dentry)); + if (new_dir != old_dir) + fsstack_copy_attr_all(old_dir, d_inode(backing_old_dir_dentry)); + +unlock_out: + unlock_rename(backing_old_dir_dentry, backing_new_dir_dentry); + +out: + dput(backing_new_dir_dentry); + dput(backing_old_dir_dentry); + dput(backing_new_dentry); + dput(backing_old_dentry); + + mutex_unlock(&mi->mi_dir_struct_mutex); + if (error) + pr_debug("incfs: %s err:%d\n", __func__, error); + return error; +} + + +static int file_open(struct inode *inode, struct file *file) +{ + struct mount_info *mi = get_mount_info(inode->i_sb); + struct file *backing_file = NULL; + struct path backing_path = {}; + int err = 0; + + get_incfs_backing_path(file->f_path.dentry, &backing_path); + backing_file = dentry_open(&backing_path, O_RDWR | O_NOATIME, + mi->mi_owner); + path_put(&backing_path); + + if (IS_ERR(backing_file)) { + err = PTR_ERR(backing_file); + backing_file = NULL; + goto out; + } + + if (S_ISREG(inode->i_mode)) + err = make_inode_ready_for_data_ops(mi, inode, backing_file); + else if (S_ISDIR(inode->i_mode)) { + struct dir_file *dir = NULL; + + dir = incfs_open_dir_file(mi, backing_file); + if (IS_ERR(dir)) + err = PTR_ERR(dir); + else + file->private_data = dir; + } else + err = -EBADF; + +out: + if (err) + pr_debug("incfs: %s name:%s err: %d\n", __func__, + file->f_path.dentry->d_name.name, err); + if (backing_file) + fput(backing_file); + return err; +} + +static int file_release(struct inode *inode, struct file *file) +{ + if (S_ISREG(inode->i_mode)) { + /* Do nothing. + * data_file is released only by inode eviction. + */ + } else if (S_ISDIR(inode->i_mode)) { + struct dir_file *dir = get_incfs_dir_file(file); + + incfs_free_dir_file(dir); + } + + return 0; +} + +static ssize_t file_write(struct file *f, const char __user *buf, + size_t size, loff_t *offset) +{ + struct data_file *df = get_incfs_data_file(f); + const ssize_t data_buf_size = 2 * INCFS_DATA_FILE_BLOCK_SIZE; + size_t block_count = size / sizeof(struct incfs_new_data_block); + struct incfs_new_data_block __user *usr_blocks = + (struct incfs_new_data_block __user *)buf; + u8 *data_buf = NULL; + ssize_t error = 0; + int i = 0; + + if (!df) + return -EBADF; + + if (!access_ok(VERIFY_READ, usr_blocks, size)) + return -EFAULT; + + data_buf = (u8 *)__get_free_pages(GFP_NOFS, get_order(data_buf_size)); + if (!data_buf) + return -ENOMEM; + + for (i = 0; i < block_count; i++) { + struct incfs_new_data_block block = {}; + + if (copy_from_user(&block, &usr_blocks[i], sizeof(block)) > 0) { + error = -EFAULT; + break; + } + + if (block.data_len > data_buf_size) { + error = -E2BIG; + break; + } + if (!access_ok(VERIFY_READ, u64_to_user_ptr(block.data), + block.data_len)) { + error = -EFAULT; + break; + } + if (copy_from_user(data_buf, u64_to_user_ptr(block.data), + block.data_len) > 0) { + error = -EFAULT; + break; + } + block.data = 0; /* To make sure nobody uses it. */ + if (block.flags & INCFS_BLOCK_FLAGS_HASH) { + error = incfs_process_new_hash_block(df, &block, + data_buf); + } else { + error = incfs_process_new_data_block(df, &block, + data_buf); + } + if (error) + break; + } + + if (data_buf) + free_pages((unsigned long)data_buf, get_order(data_buf_size)); + *offset = 0; + + /* + * Only report the error if no records were processed, otherwise + * just return how many were processed successfully. + */ + if (i == 0) + return error; + + return i * sizeof(struct incfs_new_data_block); +} + + +static int dentry_revalidate(struct dentry *d, unsigned int flags) +{ + struct path backing_path = {}; + struct inode_info *info = get_incfs_node(d_inode(d)); + struct inode *binode = (info == NULL) ? NULL : info->n_backing_inode; + struct dentry *backing_dentry = NULL; + int result = 0; + + if (flags & LOOKUP_RCU) + return -ECHILD; + + get_incfs_backing_path(d, &backing_path); + backing_dentry = backing_path.dentry; + if (!backing_dentry) + goto out; + + if (d_inode(backing_dentry) != binode) { + /* + * Backing inodes obtained via dentry and inode don't match. + * It indicates that most likely backing dir has changed + * directly bypassing Incremental FS interface. + */ + goto out; + } + + if (backing_dentry->d_flags & DCACHE_OP_REVALIDATE) { + result = backing_dentry->d_op->d_revalidate(backing_dentry, + flags); + } else + result = 1; + +out: + path_put(&backing_path); + return result; +} + +static void dentry_release(struct dentry *d) +{ + struct dentry_info *di = get_incfs_dentry(d); + + if (di) + path_put(&di->backing_path); + d->d_fsdata = NULL; +} + +static struct inode *alloc_inode(struct super_block *sb) +{ + struct inode_info *node = kzalloc(sizeof(*node), GFP_NOFS); + + /* TODO: add a slab-based cache here. */ + if (!node) + return NULL; + inode_init_once(&node->n_vfs_inode); + return &node->n_vfs_inode; +} + +static void free_inode(struct inode *inode) +{ + struct inode_info *node = get_incfs_node(inode); + + kfree(node); +} + +static void evict_inode(struct inode *inode) +{ + struct inode_info *node = get_incfs_node(inode); + + if (node) { + if (node->n_backing_inode) { + iput(node->n_backing_inode); + node->n_backing_inode = NULL; + } + if (node->n_file) { + incfs_free_data_file(node->n_file); + node->n_file = NULL; + } + } + + truncate_inode_pages(&inode->i_data, 0); + clear_inode(inode); +} + +static ssize_t incfs_getxattr(struct dentry *d, const char *name, + void *value, size_t size) +{ + struct dentry_info *di = get_incfs_dentry(d); + + if (!di || !di->backing_path.dentry) + return -ENODATA; + + return vfs_getxattr(di->backing_path.dentry, name, value, size); +} + +static ssize_t incfs_listxattr(struct dentry *d, char *list, size_t size) +{ + struct dentry_info *di = get_incfs_dentry(d); + + if (!di || !di->backing_path.dentry) + return -ENODATA; + + return vfs_listxattr(di->backing_path.dentry, list, size); +} + +struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, + const char *dev_name, void *data) +{ + struct mount_options options = {}; + struct mount_info *mi = NULL; + struct path backing_dir_path = {}; + struct dentry *index_dir; + struct super_block *src_fs_sb = NULL; + struct inode *root_inode = NULL; + struct super_block *sb = sget(type, NULL, set_anon_super, flags, NULL); + int error = 0; + + if (IS_ERR(sb)) + return ERR_CAST(sb); + + sb->s_op = &incfs_super_ops; + sb->s_d_op = &incfs_dentry_ops; + sb->s_flags |= S_NOATIME; + sb->s_magic = INCFS_MAGIC_NUMBER; + sb->s_time_gran = 1; + sb->s_blocksize = INCFS_DATA_FILE_BLOCK_SIZE; + sb->s_blocksize_bits = blksize_bits(sb->s_blocksize); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) + sb->s_xattr = incfs_xattr_ops; +#endif + + BUILD_BUG_ON(PAGE_SIZE != INCFS_DATA_FILE_BLOCK_SIZE); + + error = parse_options(&options, (char *)data); + if (error != 0) { + pr_err("incfs: Options parsing error. %d\n", error); + goto err; + } + + sb->s_bdi->ra_pages = options.readahead_pages; + if (!dev_name) { + pr_err("incfs: Backing dir is not set, filesystem can't be mounted.\n"); + error = -ENOENT; + goto err; + } + + error = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, + &backing_dir_path); + if (error || backing_dir_path.dentry == NULL || + !d_really_is_positive(backing_dir_path.dentry)) { + pr_err("incfs: Error accessing: %s.\n", + dev_name); + goto err; + } + src_fs_sb = backing_dir_path.dentry->d_sb; + sb->s_maxbytes = src_fs_sb->s_maxbytes; + + mi = incfs_alloc_mount_info(sb, &options, &backing_dir_path); + + if (IS_ERR_OR_NULL(mi)) { + error = PTR_ERR(mi); + pr_err("incfs: Error allocating mount info. %d\n", error); + mi = NULL; + goto err; + } + + index_dir = open_or_create_index_dir(backing_dir_path.dentry); + if (IS_ERR_OR_NULL(index_dir)) { + error = PTR_ERR(index_dir); + pr_err("incfs: Can't find or create .index dir in %s\n", + dev_name); + goto err; + } + mi->mi_index_dir = index_dir; + + sb->s_fs_info = mi; + root_inode = fetch_regular_inode(sb, backing_dir_path.dentry); + if (IS_ERR(root_inode)) { + error = PTR_ERR(root_inode); + goto err; + } + + sb->s_root = d_make_root(root_inode); + if (!sb->s_root) { + error = -ENOMEM; + goto err; + } + error = incfs_init_dentry(sb->s_root, &backing_dir_path); + if (error) + goto err; + + path_put(&backing_dir_path); + sb->s_flags |= SB_ACTIVE; + + pr_debug("infs: mount\n"); + return dget(sb->s_root); +err: + sb->s_fs_info = NULL; + path_put(&backing_dir_path); + incfs_free_mount_info(mi); + deactivate_locked_super(sb); + return ERR_PTR(error); +} + +static int incfs_remount_fs(struct super_block *sb, int *flags, char *data) +{ + struct mount_options options; + struct mount_info *mi = get_mount_info(sb); + int err = 0; + + sync_filesystem(sb); + err = parse_options(&options, (char *)data); + if (err) + return err; + + if (mi->mi_options.read_timeout_ms != options.read_timeout_ms) { + mi->mi_options.read_timeout_ms = options.read_timeout_ms; + pr_debug("incfs: new timeout_ms=%d", options.read_timeout_ms); + } + + pr_debug("infs: remount\n"); + return 0; +} + +void incfs_kill_sb(struct super_block *sb) +{ + struct mount_info *mi = sb->s_fs_info; + + pr_debug("infs: unmount\n"); + incfs_free_mount_info(mi); + generic_shutdown_super(sb); +} + +static int show_options(struct seq_file *m, struct dentry *root) +{ + struct mount_info *mi = get_mount_info(root->d_sb); + + seq_printf(m, ",read_timeout_ms=%u", mi->mi_options.read_timeout_ms); + seq_printf(m, ",readahead=%u", mi->mi_options.readahead_pages); + if (mi->mi_options.read_log_pages != 0) { + seq_printf(m, ",rlog_pages=%u", mi->mi_options.read_log_pages); + seq_printf(m, ",rlog_wakeup_cnt=%u", + mi->mi_options.read_log_wakeup_count); + } + if (mi->mi_options.no_backing_file_cache) + seq_puts(m, ",no_bf_cache"); + if (mi->mi_options.no_backing_file_readahead) + seq_puts(m, ",no_bf_readahead"); + return 0; +} diff --git a/fs/incfs/vfs.h b/fs/incfs/vfs.h new file mode 100644 index 000000000000..eaa490e19072 --- /dev/null +++ b/fs/incfs/vfs.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2018 Google LLC + */ + +#ifndef _INCFS_VFS_H +#define _INCFS_VFS_H + +void incfs_kill_sb(struct super_block *sb); +struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, + const char *dev_name, void *data); + +#endif diff --git a/include/uapi/linux/incrementalfs.h b/include/uapi/linux/incrementalfs.h new file mode 100644 index 000000000000..8a06e2e48fc4 --- /dev/null +++ b/include/uapi/linux/incrementalfs.h @@ -0,0 +1,244 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Userspace interface for Incremental FS. + * + * Incremental FS is special-purpose Linux virtual file system that allows + * execution of a program while its binary and resource files are still being + * lazily downloaded over the network, USB etc. + * + * Copyright 2019 Google LLC + */ +#ifndef _UAPI_LINUX_INCREMENTALFS_H +#define _UAPI_LINUX_INCREMENTALFS_H + +#include +#include +#include +#include + +/* ===== constants ===== */ +#define INCFS_NAME "incremental-fs" +#define INCFS_MAGIC_NUMBER (0x5346434e49ul) +#define INCFS_DATA_FILE_BLOCK_SIZE 4096 +#define INCFS_HEADER_VER 1 + +// TODO: This value is assumed in incfs_copy_signature_info_from_user to be the +// actual signature length. Set back to 64 when fixed. +#define INCFS_MAX_HASH_SIZE 32 +#define INCFS_MAX_FILE_ATTR_SIZE 512 + +#define INCFS_PENDING_READS_FILENAME ".pending_reads" +#define INCFS_LOG_FILENAME ".log" +#define INCFS_XATTR_ID_NAME (XATTR_USER_PREFIX "incfs.id") +#define INCFS_XATTR_SIZE_NAME (XATTR_USER_PREFIX "incfs.size") +#define INCFS_XATTR_METADATA_NAME (XATTR_USER_PREFIX "incfs.metadata") + +#define INCFS_MAX_SIGNATURE_SIZE 8096 + +#define INCFS_IOCTL_BASE_CODE 'g' + +/* ===== ioctl requests on the command dir ===== */ + +/* Create a new file */ +#define INCFS_IOC_CREATE_FILE \ + _IOWR(INCFS_IOCTL_BASE_CODE, 30, struct incfs_new_file_args) + +/* Read file signature */ +#define INCFS_IOC_READ_FILE_SIGNATURE \ + _IOWR(INCFS_IOCTL_BASE_CODE, 31, struct incfs_get_file_sig_args) + +enum incfs_compression_alg { + COMPRESSION_NONE = 0, + COMPRESSION_LZ4 = 1 +}; + +enum incfs_block_flags { + INCFS_BLOCK_FLAGS_NONE = 0, + INCFS_BLOCK_FLAGS_HASH = 1, +}; + +typedef struct { + __u8 bytes[16]; +} incfs_uuid_t __attribute__((aligned (8))); + +/* + * Description of a pending read. A pending read - a read call by + * a userspace program for which the filesystem currently doesn't have data. + */ +struct incfs_pending_read_info { + /* Id of a file that is being read from. */ + incfs_uuid_t file_id; + + /* A number of microseconds since system boot to the read. */ + __aligned_u64 timestamp_us; + + /* Index of a file block that is being read. */ + __u32 block_index; + + /* A serial number of this pending read. */ + __u32 serial_number; +}; + +/* + * A struct to be written into a control file to load a data or hash + * block to a data file. + */ +struct incfs_new_data_block { + /* Index of a data block. */ + __u32 block_index; + + /* Length of data */ + __u32 data_len; + + /* + * A pointer to an actual data for the block. + * + * Equivalent to: __u8 *data; + */ + __aligned_u64 data; + + /* + * Compression algorithm used to compress the data block. + * Values from enum incfs_compression_alg. + */ + __u8 compression; + + /* Values from enum incfs_block_flags */ + __u8 flags; + + __u16 reserved1; + + __u32 reserved2; + + __aligned_u64 reserved3; +}; + +enum incfs_hash_tree_algorithm { + INCFS_HASH_TREE_NONE = 0, + INCFS_HASH_TREE_SHA256 = 1 +}; + +struct incfs_file_signature_info { + /* + * A pointer to file's root hash (if determined != 0) + * Actual hash size determined by hash_tree_alg. + * Size of the buffer should be at least INCFS_MAX_HASH_SIZE + * + * Equivalent to: u8 *root_hash; + */ + __aligned_u64 root_hash; + + /* + * A pointer to additional data that was attached to the root hash + * before signing. + * + * Equivalent to: u8 *additional_data; + */ + __aligned_u64 additional_data; + + /* Size of additional data. */ + __u32 additional_data_size; + + __u32 reserved1; + + /* + * A pointer to pkcs7 signature DER blob. + * + * Equivalent to: u8 *signature; + */ + __aligned_u64 signature; + + + /* Size of pkcs7 signature DER blob */ + __u32 signature_size; + + __u32 reserved2; + + /* Value from incfs_hash_tree_algorithm */ + __u8 hash_tree_alg; +}; + +/* + * Create a new file or directory. + */ +struct incfs_new_file_args { + /* Id of a file to create. */ + incfs_uuid_t file_id; + + /* + * Total size of the new file. Ignored if S_ISDIR(mode). + */ + __aligned_u64 size; + + /* + * File mode. Permissions and dir flag. + */ + __u16 mode; + + __u16 reserved1; + + __u32 reserved2; + + /* + * A pointer to a null-terminated relative path to the file's parent + * dir. + * Max length: PATH_MAX + * + * Equivalent to: char *directory_path; + */ + __aligned_u64 directory_path; + + /* + * A pointer to a null-terminated file's name. + * Max length: PATH_MAX + * + * Equivalent to: char *file_name; + */ + __aligned_u64 file_name; + + /* + * A pointer to a file attribute to be set on creation. + * + * Equivalent to: u8 *file_attr; + */ + __aligned_u64 file_attr; + + /* + * Length of the data buffer specfied by file_attr. + * Max value: INCFS_MAX_FILE_ATTR_SIZE + */ + __u32 file_attr_len; + + __u32 reserved4; + + /* struct incfs_file_signature_info *signature_info; */ + __aligned_u64 signature_info; + + __aligned_u64 reserved5; + + __aligned_u64 reserved6; +}; + +/* + * Request a digital signature blob for a given file. + * Argument for INCFS_IOC_READ_FILE_SIGNATURE ioctl + */ +struct incfs_get_file_sig_args { + /* + * A pointer to the data buffer to save an signature blob to. + * + * Equivalent to: u8 *file_signature; + */ + __aligned_u64 file_signature; + + /* Size of the buffer at file_signature. */ + __u32 file_signature_buf_size; + + /* + * Number of bytes save file_signature buffer. + * It is set after ioctl done. + */ + __u32 file_signature_len_out; +}; + +#endif /* _UAPI_LINUX_INCREMENTALFS_H */ diff --git a/tools/testing/selftests/filesystems/incfs/Makefile b/tools/testing/selftests/filesystems/incfs/Makefile new file mode 100644 index 000000000000..7cff78cf5131 --- /dev/null +++ b/tools/testing/selftests/filesystems/incfs/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0 +CFLAGS += -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -lssl -lcrypto -llz4 +CFLAGS += -I../../../../../usr/include/ +CFLAGS += -I../../../../include/uapi/ +CFLAGS += -I../../../../lib + +EXTRA_SOURCES := utils.c +TEST_GEN_PROGS := incfs_test + +include ../../lib.mk + +$(OUTPUT)incfs_test: incfs_test.c $(EXTRA_SOURCES) +all: $(OUTPUT)incfs_test + +clean: + rm -rf $(OUTPUT)incfs_test *.o diff --git a/tools/testing/selftests/filesystems/incfs/config b/tools/testing/selftests/filesystems/incfs/config new file mode 100644 index 000000000000..b6749837a318 --- /dev/null +++ b/tools/testing/selftests/filesystems/incfs/config @@ -0,0 +1 @@ +CONFIG_INCREMENTAL_FS=y \ No newline at end of file diff --git a/tools/testing/selftests/filesystems/incfs/incfs_test.c b/tools/testing/selftests/filesystems/incfs/incfs_test.c new file mode 100644 index 000000000000..f1e9f86605e7 --- /dev/null +++ b/tools/testing/selftests/filesystems/incfs/incfs_test.c @@ -0,0 +1,2420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 Google LLC + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../kselftest.h" + +#include "lz4.h" +#include "utils.h" + +#define __packed __attribute__((__packed__)) + +#define TEST_FAILURE 1 +#define TEST_SUCCESS 0 +#define INCFS_MAX_MTREE_LEVELS 8 + +#define INCFS_ROOT_INODE 0 + +struct hash_block { + char data[INCFS_DATA_FILE_BLOCK_SIZE]; +}; + +struct test_signature { + void *data; + size_t size; + + char add_data[100]; + size_t add_data_size; +}; + +struct test_file { + int index; + incfs_uuid_t id; + char *name; + off_t size; + char root_hash[INCFS_MAX_HASH_SIZE]; + struct hash_block *mtree; + int mtree_block_count; + struct test_signature sig; +}; + +struct test_files_set { + struct test_file *files; + int files_count; +}; + +struct linux_dirent64 { + uint64_t d_ino; + int64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[0]; +} __packed; + +/* + * The certificate below and the private key were created by calling: + * openssl req -x509 -newkey rsa:4096 -keyout private.key -out cert.crt + * -days 1000 -sha256 -nodes -outform PEM -subj + * "/C=US/ST=WA/L=Kirkland/O=Example/OU=Org/CN=www.example.com" + */ +char x509_cert[] = +"-----BEGIN CERTIFICATE-----\n" +"MIIFvzCCA6egAwIBAgIUXpwqelEljm6BBllRQGHLrls2MYgwDQYJKoZIhvcNAQEL\n" +"BQAwbzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xETAPBgNVBAcM\n" +"CEtpcmtsYW5kMRAwDgYDVQQKDAdFeGFtcGxlMQwwCgYDVQQLDANPcmcxGDAWBgNV\n" +"BAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xOTA4MDgyMzA3MDZaFw0yMjA1MDQyMzA3\n" +"MDZaMG8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMREwDwYDVQQH\n" +"DAhLaXJrbGFuZDEQMA4GA1UECgwHRXhhbXBsZTEMMAoGA1UECwwDT3JnMRgwFgYD\n" +"VQQDDA93d3cuZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n" +"AoICAQC1LuFW/lDV/GflqFMz7RDvFFgWld982ZuDJRaK55JNj+MI4RZNL61PDw43\n" +"NeeJtqUoVxSLS9wHURjSjD/CV5GudUOnzGfbwFlLko+jhYRT4HNFS+5ys1FEJLtA\n" +"uYcY4P9GHQEXYUX+ue82A2kJ91oY6G3vCQYJFiGteb6TRDICmug31x4pBfB8rOdt\n" +"4/NXS/Dn+S0/mJlxw34IKfqrlFjzUziRZtAWWqDcfxFDUizSggkdXIUq4GY38RAD\n" +"qGewNNCab3ClJDP7/M32BhSNgsIKhgtSTM2+ocfvBhwup+BjV6UbL21DPAshlolV\n" +"gSL1HM2jin5bi4bpFMreY0LXwFih87/6AVSfQHY9TZrombVZnMxvB7NG1NCSwDBT\n" +"qjjFb3oiSMugJzY+MhISM754m46fwUyHZ1ylWCLJEU8kQ5A1q9vvqMcaDa4uTGP3\n" +"UgC6SyVmZxG2o+AO6m8TRTCtqHN41mPTM9HK4T1UyuzVpykSc2LlYkKE517SyEiV\n" +"XDmotNb2myXNYHHTjRYNxkq75Lbii2I4Q4z8XtDngaIrhZqACKSqIt2CocGjx61S\n" +"oxKWi+LGa7B4NaCMjz1LnaOIsXn1rJDRnUWL49T42g4kOi/5QaC2JDygfefw1hAb\n" +"uxkq9EYUDg+w9broltiBf4rKAnw8JMySARnyPZbj0lhZK3va5wIDAQABo1MwUTAd\n" +"BgNVHQ4EFgQUo6JN3gY2yGbzOTNj8Al7hNB3rw0wHwYDVR0jBBgwFoAUo6JN3gY2\n" +"yGbzOTNj8Al7hNB3rw0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n" +"AgEAQb3pJqOzM4whfNVdpEOswd1EApcWNM1ps9iTlEEjDoRv9F7F1PW0uXCIpk3B\n" +"j5JgCmIxAcPnzj42rduRSx421hHMZhbAIWI/JL4ZSF64qlG0YrmJDXlJgSMoyst5\n" +"biUqeWgO7Js5udPt3zhkeA62z3hGM6dE5B3k7gHTaKKtK17+UeR9imZKsOK8GBnM\n" +"rxMPI6XghxxAK2OQ/r09DHDiyf/GxgOE46oknfXfMPx3HaSvDKrZUTZ+UvVbM5c2\n" +"5eXOgH5UO/e4llLknJK7CoP/R6G7pV44iT4t4t9FMnvCYvavAHwfR+6z5vTF3o8a\n" +"wd80fC8z1vfLsIPLROdzBl9rGCvv536fPiEA677CM1AZkjfT0a9DVzrE1NDvuCUF\n" +"0KgEdiNwux+hO6dbTyiS38yPT6TbpoWJptJmFhFkC4hGvUgoX/TI0covSyf74VRH\n" +"k3BHojOBMYiX1K66xoN7fhlGK8cith3L0XXPB8CgSEUPWURvm8RCaGuX2T3FZomF\n" +"BCnNpN+WNnN3Yf4OkjtuvtxxktUU7pfVLsUxrdpo/ph4rWm6U83VT/Zlq92aF4vW\n" +"QJ+7uraQFip7e+Gy9g3UJINm3B7b1C4ch/Z/upCZESOI/23sVGzkfTgOrS+23i6/\n" +"Vi9YW75zySC2FCa1AWMS1NmS5qfDSycJUgD6YvOUg0C54ZI=\n" +"-----END CERTIFICATE-----"; + +char private_key[] = +"-----BEGIN PRIVATE KEY-----\n" +"MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC1LuFW/lDV/Gfl\n" +"qFMz7RDvFFgWld982ZuDJRaK55JNj+MI4RZNL61PDw43NeeJtqUoVxSLS9wHURjS\n" +"jD/CV5GudUOnzGfbwFlLko+jhYRT4HNFS+5ys1FEJLtAuYcY4P9GHQEXYUX+ue82\n" +"A2kJ91oY6G3vCQYJFiGteb6TRDICmug31x4pBfB8rOdt4/NXS/Dn+S0/mJlxw34I\n" +"KfqrlFjzUziRZtAWWqDcfxFDUizSggkdXIUq4GY38RADqGewNNCab3ClJDP7/M32\n" +"BhSNgsIKhgtSTM2+ocfvBhwup+BjV6UbL21DPAshlolVgSL1HM2jin5bi4bpFMre\n" +"Y0LXwFih87/6AVSfQHY9TZrombVZnMxvB7NG1NCSwDBTqjjFb3oiSMugJzY+MhIS\n" +"M754m46fwUyHZ1ylWCLJEU8kQ5A1q9vvqMcaDa4uTGP3UgC6SyVmZxG2o+AO6m8T\n" +"RTCtqHN41mPTM9HK4T1UyuzVpykSc2LlYkKE517SyEiVXDmotNb2myXNYHHTjRYN\n" +"xkq75Lbii2I4Q4z8XtDngaIrhZqACKSqIt2CocGjx61SoxKWi+LGa7B4NaCMjz1L\n" +"naOIsXn1rJDRnUWL49T42g4kOi/5QaC2JDygfefw1hAbuxkq9EYUDg+w9broltiB\n" +"f4rKAnw8JMySARnyPZbj0lhZK3va5wIDAQABAoICAQCMKul/0J2e/ncub6t2t4dr\n" +"PnTrfCT6xKqPqciny4Ee6hr9So1jR2gvink380bd/mQFMmEdZqGhM3cdpAzLf82f\n" +"hu7BSNxsYIF0er0PB4MZFMJ4sMaXC+zp5/TJnP5MG/zBND0c5k8tQpEyWy8O28Jj\n" +"FKW/0F5P90Q0ncP20EJUS50tXgniOMsU2Prtw/UE6yZDgD0mPxsurMu66ycXSFwM\n" +"WqyfqEeBk7lw/AjR6Sft71W31lTbl+DclG0MN2OIKUPcxiwCRmDFKI36MDgERk1x\n" +"sMPfdrWRLj2ryDFTUuLAWBTOVEGWS0RdRsWWVaJCuHbKd6FLl0TW2xQbOfWDTjYC\n" +"Ps31ejh163qdbk7OGOZIbd83fP3jsyL+4eNzhUpeXMKhfG58mFIv4yhdZIUOpuL6\n" +"aqnoU9z9wEsJKj/SrKr3nw6tuTnmbXgNjun9LfTFmqqDRBYd0Okiprw6jHNM1jgA\n" +"GG0kC/K7r89jKymVDABwGMFCS33ynR1Tb6zG+cqgNMPw19Fy3uQuW21CjqSzCOyP\n" +"aEVCEUZeP+ofql5+7ZKi6Dj+EdTfeKt2ihgheHZZoaYSINb8tsnKbdJhwBfW9PFT\n" +"aT/hu3bnO2FPC8H2NGOqxOEeel9ALU4SFu1pOknEhiL3/mNfOQ+KgrSRDtNRlcL0\n" +"cto05J90u0cmqwWKlshfaQKCAQEA5dcklxs4ezyzt28NcsiyS02oZ+9TkQp6pCXV\n" +"kx7AwhivAmVTlJ+c6BegA5EPd7A1gknM3+EKzGpoBOqmlF45G57phVIAphAp4oCH\n" +"UOVtIQgM8p4EU2gtX+uNOopdYlpBQnWimXaHA2sOD9/yTbZ03j/McRH6D15+iCld\n" +"3880GHdZaYYbQmHoSDg39LRRO1bdS3WC0oKBD2gPi3K0b9RaZSwKzuVrmlvrLURj\n" +"WMZfmkGl4BsITfuoTxbWFVncG3Kb9eYkYUFZy4M2G/s849PS/HjrN7BvgpanjtVp\n" +"1/39APQfAYfUuBPbKYnb6F8dE0pb5cVd4uMZklAeTb3bXjOO9QKCAQEAyc4CxWXr\n" +"bG6Do5dGpWudQ7ucq00MR0T3MHQIu5XTn6BsPHAJ9ZgrQw9C24PXm2VEjjsrMs5T\n" +"rHNF9oeO39s25Za1iyJ+893icqA3h3ivCUOOoVE54BkuJK6REhkXPD5G1ubmxeBz\n" +"MKNehlpd/eSbJJArkzKFZ8sBtLt8i9VFhRnXSpDAbiMpCbjW+bem9MWdLmkenSnu\n" +"OUbnqYcJhFBCvOT7ZCHFCDNUNPfHcaReSY2EYjw0ZqtqAZD0Q+DL+RkLz7l1+/bF\n" +"eEwNjmjFTcwRyawqf38D4miU0H6ca16FkeSlbmM5p3HdwZK2HVYYz3FSwhox6Ebd\n" +"n6in42qfL4Ug6wKCAQAh9IDRWhIkErmyNdPUy1WbzmM8x5ye5t9rdLNywq5TfnYM\n" +"co/AezwhBax8GmgglIWzM9fykzqXLHklkMz/SlRBgl6ZdZ3m6qhlb/uNtfdDU/8l\n" +"sLaO4+sgKpp4tYxKRW8ytFJLPbmAhcZUDg+r73KgiuhXJAK/VoR29TWLJP9bRfaN\n" +"omRQkEpSsQuDOUhu7cxPo5KqKuGKNyNkxJNnmgWowLLwEfCtozrBO0M6EER7c4tf\n" +"6l51tuIMnSEPknD0FSB5WYCyZYcwi7fotlsuhVK8PdjyJzyyHDOw5FJ4uGsyQt55\n" +"yWlhsH1GS7mTQMn42Zlt/pR6OnbCqNdxQMUxy4gpAoIBAFvMbs5E0pb8nr0n72cI\n" +"UP2itl3mKpOw95D+94n9WcrfOt0zShSCKAvVQWCB1O5HXqwklj4CRWXI+iZu+7sx\n" +"CQPfTq3//ygH4x6paxkg+N6J8LPJMz6Rtb/R+QP2je9FlQvk9U1GEKArcLBFI0R/\n" +"XWOAgZHwBWd1nU0NjFY/qeQmIR02Q5LWQ7C8eG4X8MafriSShO6RSGCdtHwVhWq+\n" +"59ztfL3L7skQMFn37K3xS0LCMVpOcLfTeeFEgxjthVvG3OydPOJlGubiEbiaSEZf\n" +"cif/PUXKDYZMdIVzUsw0ryXykJ5qXKuizHFlv5oQtDCJKFBLgjBbLC2YluaIdekz\n" +"8gkCggEBAJWxS7EuB/qL7fOz0o3HRy0plR3qbwZ0pLoCz0Ii7WxraBS1yQwmxif1\n" +"Rgv89GyFqg1yQl3CSrMiw7oC9WxxxuiEZDO18c4KO3NTv9K4itN9OPQVBTHmEhod\n" +"KWcyP4/W/Sfuae77PyclSqUsAARRrKYn2fpLTS5ibaU0QZgHmdPgYDUrPr+6PHKK\n" +"ZfQKU2uBfuo6zoMbMmFi3UYG49j9rv4d6v+44vS1MPHV9JK/LD8YfBhgx8Pg/u6D\n" +"nUgipS48pkGjJr2u2Vu7Mx70vqz0Yf2neyyDbdLtkYauC4w7YKPTD0yzDJyGuAeB\n" +"GyPbW1yZa5vE302a1Cr0Cd7RC4AFAAw=\n" +"-----END PRIVATE KEY-----"; + +struct test_files_set get_test_files_set(void) +{ + static struct test_file files[] = { + { .index = 0, .name = "file_one_byte", .size = 1 }, + { .index = 1, + .name = "file_one_block", + .size = INCFS_DATA_FILE_BLOCK_SIZE }, + { .index = 2, + .name = "file_one_and_a_half_blocks", + .size = INCFS_DATA_FILE_BLOCK_SIZE + + INCFS_DATA_FILE_BLOCK_SIZE / 2 }, + { .index = 3, + .name = "file_three", + .size = 300 * INCFS_DATA_FILE_BLOCK_SIZE + 3 }, + { .index = 4, + .name = "file_four", + .size = 400 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }, + { .index = 5, + .name = "file_five", + .size = 500 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }, + { .index = 6, + .name = "file_six", + .size = 600 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }, + { .index = 7, + .name = "file_seven", + .size = 700 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }, + { .index = 8, + .name = "file_eight", + .size = 800 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }, + { .index = 9, + .name = "file_nine", + .size = 900 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }, + { .index = 10, .name = "file_big", .size = 500 * 1024 * 1024 } + }; + return (struct test_files_set){ .files = files, + .files_count = ARRAY_SIZE(files) }; +} + +struct test_files_set get_small_test_files_set(void) +{ + static struct test_file files[] = { + { .index = 0, .name = "file_one_byte", .size = 1 }, + { .index = 1, + .name = "file_one_block", + .size = INCFS_DATA_FILE_BLOCK_SIZE }, + { .index = 2, + .name = "file_one_and_a_half_blocks", + .size = INCFS_DATA_FILE_BLOCK_SIZE + + INCFS_DATA_FILE_BLOCK_SIZE / 2 }, + { .index = 3, + .name = "file_three", + .size = 300 * INCFS_DATA_FILE_BLOCK_SIZE + 3 }, + { .index = 4, + .name = "file_four", + .size = 400 * INCFS_DATA_FILE_BLOCK_SIZE + 7 } + }; + return (struct test_files_set){ .files = files, + .files_count = ARRAY_SIZE(files) }; +} + +static int get_file_block_seed(int file, int block) +{ + return 7919 * file + block; +} + +static loff_t min(loff_t a, loff_t b) +{ + return a < b ? a : b; +} + +static pid_t flush_and_fork(void) +{ + fflush(stdout); + return fork(); +} + +static void print_error(char *msg) +{ + ksft_print_msg("%s: %s\n", msg, strerror(errno)); +} + +static int wait_for_process(pid_t pid) +{ + int status; + int wait_res; + + wait_res = waitpid(pid, &status, 0); + if (wait_res <= 0) { + print_error("Can't wait for the child"); + return -EINVAL; + } + if (!WIFEXITED(status)) { + ksft_print_msg("Unexpected child status pid=%d\n", pid); + return -EINVAL; + } + status = WEXITSTATUS(status); + if (status != 0) + return status; + return 0; +} + +static void rnd_buf(uint8_t *data, size_t len, unsigned int seed) +{ + int i; + + for (i = 0; i < len; i++) { + seed = 1103515245 * seed + 12345; + data[i] = (uint8_t)(seed >> (i % 13)); + } +} + +char *bin2hex(char *dst, const void *src, size_t count) +{ + const unsigned char *_src = src; + static const char hex_asc[] = "0123456789abcdef"; + + while (count--) { + unsigned char x = *_src++; + + *dst++ = hex_asc[(x & 0xf0) >> 4]; + *dst++ = hex_asc[(x & 0x0f)]; + } + *dst = 0; + return dst; +} + +static char *get_index_filename(char *mnt_dir, incfs_uuid_t id) +{ + char path[FILENAME_MAX]; + char str_id[1 + 2 * sizeof(id)]; + + bin2hex(str_id, id.bytes, sizeof(id.bytes)); + snprintf(path, ARRAY_SIZE(path), "%s/.index/%s", mnt_dir, str_id); + + return strdup(path); +} + +int open_file_by_id(char *mnt_dir, incfs_uuid_t id) +{ + char *path = get_index_filename(mnt_dir, id); + int fd = open(path, O_RDWR); + + free(path); + if (fd < 0) { + print_error("Can't open file by id."); + return -errno; + } + + return fd; +} + +int get_file_attr(char *mnt_dir, incfs_uuid_t id, char *value, int size) +{ + char *path = get_index_filename(mnt_dir, id); + int res; + + res = getxattr(path, INCFS_XATTR_METADATA_NAME, value, size); + if (res < 0) + res = -errno; + + free(path); + return res; +} + +static bool same_id(incfs_uuid_t *id1, incfs_uuid_t *id2) +{ + return !memcmp(id1->bytes, id2->bytes, sizeof(id1->bytes)); +} + +static int emit_test_blocks(char *mnt_dir, struct test_file *file, + int blocks[], int count) +{ + uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE]; + uint8_t comp_data[2 * INCFS_DATA_FILE_BLOCK_SIZE]; + int block_count = (count > 32) ? 32 : count; + int data_buf_size = 2 * INCFS_DATA_FILE_BLOCK_SIZE * block_count; + uint8_t *data_buf = malloc(data_buf_size); + uint8_t *current_data = data_buf; + uint8_t *data_end = data_buf + data_buf_size; + struct incfs_new_data_block *block_buf = + calloc(block_count, sizeof(*block_buf)); + ssize_t write_res = 0; + int fd; + int error = 0; + int i = 0; + int blocks_written = 0; + + fd = open_file_by_id(mnt_dir, file->id); + if (fd <= 0) { + error = -errno; + goto out; + } + + for (i = 0; i < block_count; i++) { + int block_index = blocks[i]; + bool compress = (file->index + block_index) % 2 == 0; + int seed = get_file_block_seed(file->index, block_index); + off_t block_offset = + ((off_t)block_index) * INCFS_DATA_FILE_BLOCK_SIZE; + size_t block_size = 0; + + if (block_offset > file->size) { + error = -EINVAL; + break; + } + if (file->size - block_offset > + INCFS_DATA_FILE_BLOCK_SIZE) + block_size = INCFS_DATA_FILE_BLOCK_SIZE; + else + block_size = file->size - block_offset; + + rnd_buf(data, block_size, seed); + if (compress) { + size_t comp_size = LZ4_compress_default( + (char *)data, (char *)comp_data, block_size, + ARRAY_SIZE(comp_data)); + + if (comp_size <= 0) { + error = -EBADMSG; + break; + } + if (current_data + comp_size > data_end) { + error = -ENOMEM; + break; + } + memcpy(current_data, comp_data, comp_size); + block_size = comp_size; + block_buf[i].compression = COMPRESSION_LZ4; + } else { + if (current_data + block_size > data_end) { + error = -ENOMEM; + break; + } + memcpy(current_data, data, block_size); + block_buf[i].compression = COMPRESSION_NONE; + } + + block_buf[i].block_index = block_index; + block_buf[i].data_len = block_size; + block_buf[i].data = ptr_to_u64(current_data); + block_buf[i].compression = + compress ? COMPRESSION_LZ4 : COMPRESSION_NONE; + current_data += block_size; + } + + if (!error) { + write_res = write(fd, block_buf, sizeof(*block_buf) * i); + if (write_res < 0) + error = -errno; + else + blocks_written = write_res / sizeof(*block_buf); + } + if (error) { + ksft_print_msg( + "Writing data block error. Write returned: %d. Error:%s\n", + write_res, strerror(-error)); + } + +out: + free(block_buf); + free(data_buf); + close(fd); + return (error < 0) ? error : blocks_written; +} + +static int emit_test_block(char *mnt_dir, struct test_file *file, + int block_index) +{ + int res = emit_test_blocks(mnt_dir, file, &block_index, 1); + + if (res == 0) + return -EINVAL; + if (res == 1) + return 0; + return res; +} + +static void shuffle(int array[], int count, unsigned int seed) +{ + int i; + + for (i = 0; i < count - 1; i++) { + int items_left = count - i; + int shuffle_index; + int v; + + seed = 1103515245 * seed + 12345; + shuffle_index = i + seed % items_left; + + v = array[shuffle_index]; + array[shuffle_index] = array[i]; + array[i] = v; + } +} + +static int emit_test_file_data(char *mount_dir, struct test_file *file) +{ + int i; + int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; + int *block_indexes = NULL; + int result = 0; + int blocks_written = 0; + + if (file->size == 0) + return 0; + + block_indexes = calloc(block_cnt, sizeof(*block_indexes)); + for (i = 0; i < block_cnt; i++) + block_indexes[i] = i; + shuffle(block_indexes, block_cnt, file->index); + + for (i = 0; i < block_cnt; i += blocks_written) { + blocks_written = emit_test_blocks(mount_dir, file, + block_indexes + i, block_cnt - i); + if (blocks_written < 0) { + result = blocks_written; + goto out; + } + if (blocks_written == 0) { + result = -EIO; + goto out; + } + } +out: + free(block_indexes); + return result; +} + +static loff_t read_whole_file(char *filename) +{ + int fd = -1; + loff_t result; + loff_t bytes_read = 0; + uint8_t buff[16 * 1024]; + + fd = open(filename, O_RDONLY); + if (fd <= 0) + return fd; + + while (1) { + int read_result = read(fd, buff, ARRAY_SIZE(buff)); + + if (read_result < 0) { + print_error("Error during reading from a file."); + result = -errno; + goto cleanup; + } else if (read_result == 0) + break; + + bytes_read += read_result; + } + result = bytes_read; + +cleanup: + close(fd); + return result; +} + +static int read_test_file(uint8_t *buf, size_t len, char *filename, + int block_idx) +{ + int fd = -1; + int result; + int bytes_read = 0; + size_t bytes_to_read = len; + off_t offset = ((off_t)block_idx) * INCFS_DATA_FILE_BLOCK_SIZE; + + fd = open(filename, O_RDONLY); + if (fd <= 0) + return fd; + + if (lseek(fd, offset, SEEK_SET) != offset) { + print_error("Seek error"); + return -errno; + } + + while (bytes_read < bytes_to_read) { + int read_result = + read(fd, buf + bytes_read, bytes_to_read - bytes_read); + if (read_result < 0) { + result = -errno; + goto cleanup; + } else if (read_result == 0) + break; + + bytes_read += read_result; + } + result = bytes_read; + +cleanup: + close(fd); + return result; +} + +static char *create_backing_dir(char *mount_dir) +{ + struct stat st; + char backing_dir_name[255]; + + snprintf(backing_dir_name, ARRAY_SIZE(backing_dir_name), "%s-src", + mount_dir); + + if (stat(backing_dir_name, &st) == 0) { + if (S_ISDIR(st.st_mode)) { + int error = delete_dir_tree(backing_dir_name); + + if (error) { + ksft_print_msg( + "Can't delete existing backing dir. %d\n", + error); + return NULL; + } + } else { + if (unlink(backing_dir_name)) { + print_error("Can't clear backing dir"); + return NULL; + } + } + } + + if (mkdir(backing_dir_name, 0777)) { + if (errno != EEXIST) { + print_error("Can't open/create backing dir"); + return NULL; + } + } + + return strdup(backing_dir_name); +} + +static int validate_test_file_content_with_seed(char *mount_dir, + struct test_file *file, + unsigned int shuffle_seed) +{ + int error = -1; + char *filename = concat_file_name(mount_dir, file->name); + off_t size = file->size; + loff_t actual_size = get_file_size(filename); + int block_cnt = 1 + (size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; + int *block_indexes = NULL; + int i; + + block_indexes = alloca(sizeof(int) * block_cnt); + for (i = 0; i < block_cnt; i++) + block_indexes[i] = i; + + if (shuffle_seed != 0) + shuffle(block_indexes, block_cnt, shuffle_seed); + + if (actual_size != size) { + ksft_print_msg( + "File size doesn't match. name: %s expected size:%ld actual size:%ld\n", + filename, size, actual_size); + error = -1; + goto failure; + } + + for (i = 0; i < block_cnt; i++) { + int block_idx = block_indexes[i]; + uint8_t expected_block[INCFS_DATA_FILE_BLOCK_SIZE]; + uint8_t actual_block[INCFS_DATA_FILE_BLOCK_SIZE]; + int seed = get_file_block_seed(file->index, block_idx); + size_t bytes_to_compare = min( + (off_t)INCFS_DATA_FILE_BLOCK_SIZE, + size - ((off_t)block_idx) * INCFS_DATA_FILE_BLOCK_SIZE); + int read_result = + read_test_file(actual_block, INCFS_DATA_FILE_BLOCK_SIZE, + filename, block_idx); + if (read_result < 0) { + ksft_print_msg( + "Error reading block %d from file %s. Error: %s\n", + block_idx, filename, strerror(-read_result)); + error = read_result; + goto failure; + } + rnd_buf(expected_block, INCFS_DATA_FILE_BLOCK_SIZE, seed); + if (memcmp(expected_block, actual_block, bytes_to_compare)) { + ksft_print_msg( + "File contents don't match. name: %s block:%d\n", + file->name, block_idx); + error = -2; + goto failure; + } + } + free(filename); + return 0; + +failure: + free(filename); + return error; +} + +static int validate_test_file_content(char *mount_dir, struct test_file *file) +{ + return validate_test_file_content_with_seed(mount_dir, file, 0); +} + +static int data_producer(char *mount_dir, struct test_files_set *test_set) +{ + int ret = 0; + int timeout_ms = 1000; + struct incfs_pending_read_info prs[100] = {}; + int prs_size = ARRAY_SIZE(prs); + int fd = open_commands_file(mount_dir); + + if (fd < 0) + return -errno; + + while ((ret = wait_for_pending_reads(fd, timeout_ms, prs, prs_size)) > + 0) { + int read_count = ret; + int i; + + for (i = 0; i < read_count; i++) { + int j = 0; + struct test_file *file = NULL; + + for (j = 0; j < test_set->files_count; j++) { + bool same = same_id(&(test_set->files[j].id), + &(prs[i].file_id)); + + if (same) { + file = &test_set->files[j]; + break; + } + } + if (!file) { + ksft_print_msg( + "Unknown file in pending reads.\n"); + break; + } + + ret = emit_test_block(mount_dir, file, + prs[i].block_index); + if (ret < 0) { + ksft_print_msg("Emitting test data error: %s\n", + strerror(-ret)); + break; + } + } + } + close(fd); + return ret; +} + +static int build_mtree(struct test_file *file) +{ + char data[INCFS_DATA_FILE_BLOCK_SIZE] = {}; + const int digest_size = SHA256_DIGEST_SIZE; + const int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size; + int block_count = 0; + int hash_block_count = 0; + int total_tree_block_count = 0; + int tree_lvl_index[INCFS_MAX_MTREE_LEVELS] = {}; + int tree_lvl_count[INCFS_MAX_MTREE_LEVELS] = {}; + int levels_count = 0; + char data_to_sign[256] = {}; + int sig_data_size; + int i, level; + + if (file->size == 0) + return 0; + + block_count = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; + hash_block_count = block_count; + for (i = 0; hash_block_count > 1; i++) { + hash_block_count = (hash_block_count + hash_per_block - 1) + / hash_per_block; + tree_lvl_count[i] = hash_block_count; + total_tree_block_count += hash_block_count; + } + levels_count = i; + + for (i = 0; i < levels_count; i++) { + int prev_lvl_base = (i == 0) ? total_tree_block_count : + tree_lvl_index[i - 1]; + + tree_lvl_index[i] = prev_lvl_base - tree_lvl_count[i]; + } + + file->mtree_block_count = total_tree_block_count; + if (block_count == 1) { + int seed = get_file_block_seed(file->index, 0); + + rnd_buf((uint8_t *)data, file->size, seed); + sha256(data, file->size, file->root_hash); + return 0; + } + + file->mtree = calloc(total_tree_block_count, sizeof(*file->mtree)); + /* Build level 0 hashes. */ + for (i = 0; i < block_count; i++) { + off_t offset = i * INCFS_DATA_FILE_BLOCK_SIZE; + size_t block_size = INCFS_DATA_FILE_BLOCK_SIZE; + int block_index = tree_lvl_index[0] + + i / hash_per_block; + int block_off = (i % hash_per_block) * digest_size; + int seed = get_file_block_seed(file->index, i); + char *hash_ptr = file->mtree[block_index].data + block_off; + + if (file->size - offset < block_size) + block_size = file->size - offset; + + rnd_buf((uint8_t *)data, block_size, seed); + sha256(data, block_size, hash_ptr); + } + + /* Build higher levels of hash tree. */ + for (level = 1; level < levels_count; level++) { + int prev_lvl_base = tree_lvl_index[level - 1]; + int prev_lvl_count = tree_lvl_count[level - 1]; + + for (i = 0; i < prev_lvl_count; i++) { + int block_index = + i / hash_per_block + tree_lvl_index[level]; + int block_off = (i % hash_per_block) * digest_size; + char *hash_ptr = + file->mtree[block_index].data + block_off; + + sha256(file->mtree[i + prev_lvl_base].data, + INCFS_DATA_FILE_BLOCK_SIZE, hash_ptr); + } + } + + /* Calculate root hash from the top block */ + sha256(file->mtree[0].data, + INCFS_DATA_FILE_BLOCK_SIZE, file->root_hash); + + /* Calculating digital signature */ + snprintf(file->sig.add_data, sizeof(file->sig.add_data), "%ld", + file->size); + memcpy(data_to_sign, file->root_hash, SHA256_DIGEST_SIZE); + memcpy(data_to_sign + SHA256_DIGEST_SIZE, file->sig.add_data, + strlen(file->sig.add_data)); + sig_data_size = SHA256_DIGEST_SIZE + strlen(file->sig.add_data); + if (!sign_pkcs7(data_to_sign, sig_data_size, private_key, x509_cert, + &file->sig.data, &file->sig.size)) { + ksft_print_msg("Signing failed.\n"); + return -EINVAL; + } + + return 0; +} + +static int load_hash_tree(const char *mount_dir, struct test_file *file) +{ + int err; + int i; + int fd; + + size_t blocks_size = + file->mtree_block_count * sizeof(struct incfs_new_data_block); + struct incfs_new_data_block *blocks = NULL; + char *file_path; + + if (blocks_size == 0) + return 0; + + blocks = malloc(blocks_size); + if (!blocks) + return -ENOMEM; + + for (i = 0; i < file->mtree_block_count; i++) { + blocks[i] = (struct incfs_new_data_block){ + .block_index = i, + .data_len = INCFS_DATA_FILE_BLOCK_SIZE, + .data = ptr_to_u64(file->mtree[i].data), + .flags = INCFS_BLOCK_FLAGS_HASH + }; + } + + file_path = concat_file_name(mount_dir, file->name); + fd = open(file_path, O_RDWR); + free(file_path); + if (fd < 0) { + err = errno; + goto failure; + } + + err = write(fd, blocks, blocks_size); + close(fd); + + if (err < blocks_size) + err = errno; + else { + err = 0; + free(file->mtree); + } + +failure: + free(blocks); + return err; +} + +static int cant_touch_index_test(char *mount_dir) +{ + char *file_name = "test_file"; + int file_size = 123; + incfs_uuid_t file_id; + char *index_path = concat_file_name(mount_dir, ".index"); + char *subdir = concat_file_name(index_path, "subdir"); + char *dst_name = concat_file_name(mount_dir, "something"); + char *filename_in_index = NULL; + char *file_path = concat_file_name(mount_dir, file_name); + char *backing_dir; + int cmd_fd = -1; + int err; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + free(backing_dir); + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + + err = mkdir(subdir, 0777); + if (err == 0 || errno != EBUSY) { + print_error("Shouldn't be able to crate subdir in index\n"); + goto failure; + } + + err = emit_file(cmd_fd, ".index", file_name, &file_id, + file_size, NULL); + if (err != -EBUSY) { + print_error("Shouldn't be able to crate a file in index\n"); + goto failure; + } + + err = emit_file(cmd_fd, NULL, file_name, &file_id, + file_size, NULL); + if (err < 0) + goto failure; + filename_in_index = get_index_filename(mount_dir, file_id); + + err = unlink(filename_in_index); + if (err == 0 || errno != EBUSY) { + print_error("Shouldn't be delete from index\n"); + goto failure; + } + + + err = rename(filename_in_index, dst_name); + if (err == 0 || errno != EBUSY) { + print_error("Shouldn't be able to move from index\n"); + goto failure; + } + + free(filename_in_index); + filename_in_index = concat_file_name(index_path, "abc"); + err = link(file_path, filename_in_index); + if (err == 0 || errno != EBUSY) { + print_error("Shouldn't be able to link inside index\n"); + goto failure; + } + + close(cmd_fd); + free(subdir); + free(index_path); + free(dst_name); + free(filename_in_index); + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + free(subdir); + free(dst_name); + free(index_path); + free(filename_in_index); + close(cmd_fd); + umount(mount_dir); + return TEST_FAILURE; +} + +static bool iterate_directory(char *dir_to_iterate, bool root, int file_count) +{ + struct expected_name { + const char *name; + bool root_only; + bool found; + } names[] = { + {INCFS_LOG_FILENAME, true, false}, + {INCFS_PENDING_READS_FILENAME, true, false}, + {".index", true, false}, + {"..", false, false}, + {".", false, false}, + }; + + bool pass = true, found; + int i; + + /* Test directory iteration */ + int fd = open(dir_to_iterate, O_RDONLY | O_DIRECTORY); + + if (fd < 0) { + print_error("Can't open directory\n"); + return false; + } + + for (;;) { + /* Enough space for one dirent - no name over 30 */ + char buf[sizeof(struct linux_dirent64) + NAME_MAX]; + struct linux_dirent64 *dirent = (struct linux_dirent64 *) buf; + int nread; + int i; + + for (i = 0; i < NAME_MAX; ++i) { + nread = syscall(__NR_getdents64, fd, buf, + sizeof(struct linux_dirent64) + i); + + if (nread >= 0) + break; + if (errno != EINVAL) + break; + } + + if (nread == 0) + break; + if (nread < 0) { + print_error("Error iterating directory\n"); + pass = false; + goto failure; + } + + /* Expected size is rounded up to 8 byte boundary. Not sure if + * this is universal truth or just happenstance, but useful test + * for the moment + */ + if (nread != (((sizeof(struct linux_dirent64) + + strlen(dirent->d_name) + 1) + 7) & ~7)) { + print_error("Wrong dirent size"); + pass = false; + goto failure; + } + + found = false; + for (i = 0; i < sizeof(names) / sizeof(*names); ++i) + if (!strcmp(dirent->d_name, names[i].name)) { + if (names[i].root_only && !root) { + print_error("Root file error"); + pass = false; + goto failure; + } + + if (names[i].found) { + print_error("File appears twice"); + pass = false; + goto failure; + } + + names[i].found = true; + found = true; + break; + } + + if (!found) + --file_count; + } + + for (i = 0; i < sizeof(names) / sizeof(*names); ++i) { + if (!names[i].found) + if (root || !names[i].root_only) { + print_error("Expected file not present"); + pass = false; + goto failure; + } + } + + if (file_count) { + print_error("Wrong number of files\n"); + pass = false; + goto failure; + } + +failure: + close(fd); + return pass; +} + +static int basic_file_ops_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + char *subdir1 = concat_file_name(mount_dir, "subdir1"); + char *subdir2 = concat_file_name(mount_dir, "subdir2"); + char *backing_dir; + int cmd_fd = -1; + int i, err; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + free(backing_dir); + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + err = mkdir(subdir1, 0777); + if (err < 0 && errno != EEXIST) { + print_error("Can't create subdir1\n"); + goto failure; + } + + err = mkdir(subdir2, 0777); + if (err < 0 && errno != EEXIST) { + print_error("Can't create subdir2\n"); + goto failure; + } + + /* Create all test files in subdir1 directory */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + loff_t size; + char *file_path = concat_file_name(subdir1, file->name); + + err = emit_file(cmd_fd, "subdir1", file->name, &file->id, + file->size, NULL); + if (err < 0) + goto failure; + + size = get_file_size(file_path); + free(file_path); + if (size != file->size) { + ksft_print_msg("Wrong size %lld of %s.\n", + size, file->name); + goto failure; + } + } + + if (!iterate_directory(subdir1, false, file_num)) + goto failure; + + /* Link the files to subdir2 */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *src_name = concat_file_name(subdir1, file->name); + char *dst_name = concat_file_name(subdir2, file->name); + loff_t size; + + err = link(src_name, dst_name); + if (err < 0) { + print_error("Can't move file\n"); + goto failure; + } + + size = get_file_size(dst_name); + if (size != file->size) { + ksft_print_msg("Wrong size %lld of %s.\n", + size, file->name); + goto failure; + } + free(src_name); + free(dst_name); + } + + /* Move the files from subdir2 to the mount dir */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *src_name = concat_file_name(subdir2, file->name); + char *dst_name = concat_file_name(mount_dir, file->name); + loff_t size; + + err = rename(src_name, dst_name); + if (err < 0) { + print_error("Can't move file\n"); + goto failure; + } + + size = get_file_size(dst_name); + if (size != file->size) { + ksft_print_msg("Wrong size %lld of %s.\n", + size, file->name); + goto failure; + } + free(src_name); + free(dst_name); + } + + /* +2 because there are 2 subdirs */ + if (!iterate_directory(mount_dir, true, file_num + 2)) + goto failure; + + /* Open and close all files from the mount dir */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *path = concat_file_name(mount_dir, file->name); + int fd; + + fd = open(path, O_RDWR); + free(path); + if (fd <= 0) { + print_error("Can't open file"); + goto failure; + } + if (close(fd)) { + print_error("Can't close file"); + goto failure; + } + } + + /* Delete all files from the mount dir */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *path = concat_file_name(mount_dir, file->name); + + err = unlink(path); + free(path); + if (err < 0) { + print_error("Can't unlink file"); + goto failure; + } + } + + err = delete_dir_tree(subdir1); + if (err) { + ksft_print_msg("Error deleting subdir1 %d", err); + goto failure; + } + + err = rmdir(subdir2); + if (err) { + print_error("Error deleting subdir2"); + goto failure; + } + + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + umount(mount_dir); + return TEST_FAILURE; +} + +static int dynamic_files_and_data_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + const int missing_file_idx = 5; + int cmd_fd = -1; + char *backing_dir; + int i; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + free(backing_dir); + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Check that test files don't exist in the filesystem. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *filename = concat_file_name(mount_dir, file->name); + + if (access(filename, F_OK) != -1) { + ksft_print_msg( + "File %s somehow already exists in a clean FS.\n", + filename); + goto failure; + } + free(filename); + } + + /* Write test data into the command file. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int res; + + build_mtree(file); + res = emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL); + if (res < 0) { + ksft_print_msg("Error %s emiting file %s.\n", + strerror(-res), file->name); + goto failure; + } + + /* Skip writing data to one file so we can check */ + /* that it's missing later. */ + if (i == missing_file_idx) + continue; + + res = load_hash_tree(mount_dir, file); + if (res) { + ksft_print_msg("Can't load hashes for %s. error: %s\n", + file->name, strerror(-res)); + goto failure; + } + + res = emit_test_file_data(mount_dir, file); + if (res) { + ksft_print_msg("Error %s emiting data for %s.\n", + strerror(-res), file->name); + goto failure; + } + } + + /* Validate contents of the FS */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (i == missing_file_idx) { + /* No data has been written to this file. */ + /* Check for read error; */ + uint8_t buf; + char *filename = + concat_file_name(mount_dir, file->name); + int res = read_test_file(&buf, 1, filename, 0); + + free(filename); + if (res > 0) { + ksft_print_msg( + "Data present, even though never writtern.\n"); + goto failure; + } + if (res != -ETIME) { + ksft_print_msg("Wrong error code: %d.\n", res); + goto failure; + } + } else { + if (validate_test_file_content(mount_dir, file) < 0) + goto failure; + } + } + + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + umount(mount_dir); + return TEST_FAILURE; +} + +static int concurrent_reads_and_writes_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + /* Validate each file from that many child processes. */ + const int child_multiplier = 3; + int cmd_fd = -1; + char *backing_dir; + int status; + int i; + pid_t producer_pid; + pid_t *child_pids = alloca(child_multiplier * file_num * sizeof(pid_t)); + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + free(backing_dir); + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Tell FS about the files, without actually providing the data. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int res; + + res = emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL); + if (res) + goto failure; + } + + /* Start child processes acessing data in the files */ + for (i = 0; i < file_num * child_multiplier; i++) { + struct test_file *file = &test.files[i / child_multiplier]; + pid_t child_pid = flush_and_fork(); + + if (child_pid == 0) { + /* This is a child process, do the data validation. */ + int ret = validate_test_file_content_with_seed( + mount_dir, file, i); + if (ret >= 0) { + /* Zero exit status if data is valid. */ + exit(0); + } + + /* Positive status if validation error found. */ + exit(-ret); + } else if (child_pid > 0) { + child_pids[i] = child_pid; + } else { + print_error("Fork error"); + goto failure; + } + } + + producer_pid = flush_and_fork(); + if (producer_pid == 0) { + int ret; + /* + * This is a child that should provide data to + * pending reads. + */ + + ret = data_producer(mount_dir, &test); + exit(-ret); + } else { + status = wait_for_process(producer_pid); + if (status != 0) { + ksft_print_msg("Data produces failed. %d(%s) ", status, + strerror(status)); + goto failure; + } + } + + /* Check that all children has finished with 0 exit status */ + for (i = 0; i < file_num * child_multiplier; i++) { + struct test_file *file = &test.files[i / child_multiplier]; + + status = wait_for_process(child_pids[i]); + if (status != 0) { + ksft_print_msg( + "Validation for the file %s failed with code %d (%s)\n", + file->name, status, strerror(status)); + goto failure; + } + } + + /* Check that there are no pending reads left */ + { + struct incfs_pending_read_info prs[1] = {}; + int timeout = 0; + int read_count = wait_for_pending_reads(cmd_fd, timeout, prs, + ARRAY_SIZE(prs)); + + if (read_count) { + ksft_print_msg( + "Pending reads pending when all data written\n"); + goto failure; + } + } + + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + umount(mount_dir); + return TEST_FAILURE; +} + +static int work_after_remount_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + const int file_num_stage1 = file_num / 2; + const int file_num_stage2 = file_num; + char *backing_dir = NULL; + int i = 0; + int cmd_fd = -1; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Write first half of the data into the command file. (stage 1) */ + for (i = 0; i < file_num_stage1; i++) { + struct test_file *file = &test.files[i]; + int res; + + build_mtree(file); + if (emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL)) + goto failure; + + if (emit_test_file_data(mount_dir, file)) + goto failure; + + res = load_hash_tree(mount_dir, file); + if (res) { + ksft_print_msg("Can't load hashes for %s. error: %s\n", + file->name, strerror(-res)); + goto failure; + } +} + + /* Unmount and mount again, to see that data is persistent. */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Write the second half of the data into the command file. (stage 2) */ + for (; i < file_num_stage2; i++) { + struct test_file *file = &test.files[i]; + int res = emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL); + + if (res) + goto failure; + + if (emit_test_file_data(mount_dir, file)) + goto failure; + } + + /* Validate contents of the FS */ + for (i = 0; i < file_num_stage2; i++) { + struct test_file *file = &test.files[i]; + + if (validate_test_file_content(mount_dir, file) < 0) + goto failure; + } + + /* Delete all files */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *filename = concat_file_name(mount_dir, file->name); + char *filename_in_index = get_index_filename(mount_dir, + file->id); + + if (access(filename, F_OK) != 0) { + ksft_print_msg("File %s is not visible.\n", filename); + goto failure; + } + + if (access(filename_in_index, F_OK) != 0) { + ksft_print_msg("File %s is not visible.\n", + filename_in_index); + goto failure; + } + + unlink(filename); + + if (access(filename, F_OK) != -1) { + ksft_print_msg("File %s is still present.\n", filename); + goto failure; + } + + if (access(filename_in_index, F_OK) != 0) { + ksft_print_msg("File %s is still present.\n", + filename_in_index); + goto failure; + } + free(filename); + free(filename_in_index); + } + + /* Unmount and mount again, to see that deleted files stay deleted. */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Validate all deleted files are still deleted. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *filename = concat_file_name(mount_dir, file->name); + + if (access(filename, F_OK) != -1) { + ksft_print_msg("File %s is still visible.\n", filename); + goto failure; + } + free(filename); + } + + /* Final unmount */ + close(cmd_fd); + free(backing_dir); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static int attribute_test(char *mount_dir) +{ + char file_attr[] = "metadata123123"; + char attr_buf[INCFS_MAX_FILE_ATTR_SIZE] = {}; + int cmd_fd = -1; + incfs_uuid_t file_id; + int attr_res = 0; + char *backing_dir; + + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + if (emit_file(cmd_fd, NULL, "file", &file_id, 12, file_attr)) + goto failure; + + /* Test attribute values */ + attr_res = get_file_attr(mount_dir, file_id, attr_buf, + ARRAY_SIZE(attr_buf)); + if (attr_res != strlen(file_attr)) { + ksft_print_msg("Get file attr error: %d\n", attr_res); + goto failure; + } + if (strcmp(attr_buf, file_attr) != 0) { + ksft_print_msg("Incorrect file attr value: '%s'", attr_buf); + goto failure; + } + + /* Unmount and mount again, to see that attributes are persistent. */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Test attribute values again after remount*/ + attr_res = get_file_attr(mount_dir, file_id, attr_buf, + ARRAY_SIZE(attr_buf)); + if (attr_res != strlen(file_attr)) { + ksft_print_msg("Get dir attr error: %d\n", attr_res); + goto failure; + } + if (strcmp(attr_buf, file_attr) != 0) { + ksft_print_msg("Incorrect file attr value: '%s'", attr_buf); + goto failure; + } + + /* Final unmount */ + close(cmd_fd); + free(backing_dir); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static int child_procs_waiting_for_data_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + int cmd_fd = -1; + int i; + pid_t *child_pids = alloca(file_num * sizeof(pid_t)); + char *backing_dir; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. (10s wait time) */ + if (mount_fs(mount_dir, backing_dir, 10000) != 0) + goto failure; + + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Tell FS about the files, without actually providing the data. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL); + } + + /* Start child processes acessing data in the files */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + pid_t child_pid = flush_and_fork(); + + if (child_pid == 0) { + /* This is a child process, do the data validation. */ + int ret = validate_test_file_content(mount_dir, file); + + if (ret >= 0) { + /* Zero exit status if data is valid. */ + exit(0); + } + + /* Positive status if validation error found. */ + exit(-ret); + } else if (child_pid > 0) { + child_pids[i] = child_pid; + } else { + print_error("Fork error"); + goto failure; + } + } + + /* Write test data into the command file. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (emit_test_file_data(mount_dir, file)) + goto failure; + } + + /* Check that all children has finished with 0 exit status */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int status = wait_for_process(child_pids[i]); + + if (status != 0) { + ksft_print_msg( + "Validation for the file %s failed with code %d (%s)\n", + file->name, status, strerror(status)); + goto failure; + } + } + + close(cmd_fd); + free(backing_dir); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static int multiple_providers_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + const int producer_count = 5; + int cmd_fd = -1; + int status; + int i; + pid_t *producer_pids = alloca(producer_count * sizeof(pid_t)); + char *backing_dir; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. (10s wait time) */ + if (mount_fs(mount_dir, backing_dir, 10000) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Tell FS about the files, without actually providing the data. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL) < 0) + goto failure; + } + + /* Start producer processes */ + for (i = 0; i < producer_count; i++) { + pid_t producer_pid = flush_and_fork(); + + if (producer_pid == 0) { + int ret; + /* + * This is a child that should provide data to + * pending reads. + */ + + ret = data_producer(mount_dir, &test); + exit(-ret); + } else if (producer_pid > 0) { + producer_pids[i] = producer_pid; + } else { + print_error("Fork error"); + goto failure; + } + } + + /* Validate FS content */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + char *filename = concat_file_name(mount_dir, file->name); + loff_t read_result = read_whole_file(filename); + + free(filename); + if (read_result != file->size) { + ksft_print_msg( + "Error validating file %s. Result: %ld\n", + file->name, read_result); + goto failure; + } + } + + /* Check that all producers has finished with 0 exit status */ + for (i = 0; i < producer_count; i++) { + status = wait_for_process(producer_pids[i]); + if (status != 0) { + ksft_print_msg("Producer %d failed with code (%s)\n", i, + strerror(status)); + goto failure; + } + } + + close(cmd_fd); + free(backing_dir); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static int signature_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + int i = 0; + unsigned char sig_buf[INCFS_MAX_SIGNATURE_SIZE]; + char *backing_dir; + int cmd_fd = -1; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. (10s wait time) */ + if (mount_fs(mount_dir, backing_dir, 10000) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Write hashes and data. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int res; + + build_mtree(file); + + res = crypto_emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, file->root_hash, + file->sig.data, file->sig.size, file->sig.add_data); + + if (res) { + ksft_print_msg("Emit failed for %s. error: %s\n", + file->name, strerror(-res)); + goto failure; + } + + if (emit_test_file_data(mount_dir, file)) + goto failure; + + res = load_hash_tree(mount_dir, file); + if (res) { + ksft_print_msg("Can't load hashes for %s. error: %s\n", + file->name, strerror(-res)); + goto failure; + } + } + + /* Validate data */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int sig_len; + char *path; + int fd; + + if (validate_test_file_content(mount_dir, file) < 0) + goto failure; + + path = concat_file_name(mount_dir, file->name); + fd = open(path, O_RDWR); + free(path); + if (fd < 0) { + print_error("Can't open file"); + goto failure; + } + + sig_len = get_file_signature(fd, sig_buf, ARRAY_SIZE(sig_buf)); + + if (close(fd)) { + print_error("Can't close file"); + goto failure; + } + + if (sig_len < 0) { + ksft_print_msg("Can't load signature %s. error: %s\n", + file->name, strerror(-sig_len)); + goto failure; + } + + if (sig_len != file->sig.size || + memcmp(sig_buf, file->sig.data, sig_len)) { + ksft_print_msg("Signature mismatch %s.\n", + file->name); + goto failure; + } + } + + /* Unmount and mount again, to make sure the signature is persistent. */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Validate data again */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int sig_len; + char *path; + int fd; + + if (validate_test_file_content(mount_dir, file) < 0) + goto failure; + + path = concat_file_name(mount_dir, file->name); + fd = open(path, O_RDWR); + free(path); + if (fd < 0) { + print_error("Can't open file"); + goto failure; + } + + sig_len = get_file_signature(fd, sig_buf, ARRAY_SIZE(sig_buf)); + + if (close(fd)) { + print_error("Can't close file"); + goto failure; + } + + if (sig_len < 0) { + ksft_print_msg("Can't load signature %s. error: %s\n", + file->name, strerror(-sig_len)); + goto failure; + } + if (sig_len != file->sig.size || + memcmp(sig_buf, file->sig.data, sig_len)) { + ksft_print_msg("Signature mismatch %s.\n", + file->name); + goto failure; + } + } + + /* Final unmount */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + return TEST_SUCCESS; + +failure: + close(cmd_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static int hash_tree_test(char *mount_dir) +{ + char *backing_dir; + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + const int corrupted_file_idx = 5; + int i = 0; + int cmd_fd = -1; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + /* Mount FS and release the backing file. */ + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Write hashes and data. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + int res; + + build_mtree(file); + res = crypto_emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, file->root_hash, + file->sig.data, file->sig.size, file->sig.add_data); + + if (i == corrupted_file_idx) { + /* Corrupt third blocks hash */ + file->mtree[0].data[2 * SHA256_DIGEST_SIZE] ^= 0xff; + } + if (emit_test_file_data(mount_dir, file)) + goto failure; + + res = load_hash_tree(mount_dir, file); + if (res) { + ksft_print_msg("Can't load hashes for %s. error: %s\n", + file->name, strerror(-res)); + goto failure; + } + } + + /* Validate data */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (i == corrupted_file_idx) { + uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE]; + char *filename = + concat_file_name(mount_dir, file->name); + int res; + + res = read_test_file(data, INCFS_DATA_FILE_BLOCK_SIZE, + filename, 2); + free(filename); + if (res != -EBADMSG) { + ksft_print_msg("Hash violation missed1. %d\n", + res); + goto failure; + } + } else if (validate_test_file_content(mount_dir, file) < 0) + goto failure; + } + + /* Unmount and mount again, to that hashes are persistent. */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + if (mount_fs(mount_dir, backing_dir, 50) != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + /* Validate data again */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (i == corrupted_file_idx) { + uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE]; + char *filename = + concat_file_name(mount_dir, file->name); + int res; + + res = read_test_file(data, INCFS_DATA_FILE_BLOCK_SIZE, + filename, 2); + free(filename); + if (res != -EBADMSG) { + ksft_print_msg("Hash violation missed2. %d\n", + res); + goto failure; + } + } else if (validate_test_file_content(mount_dir, file) < 0) + goto failure; + } + + /* Final unmount */ + close(cmd_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + return TEST_SUCCESS; + +failure: + close(cmd_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static int validate_logs(char *mount_dir, int log_fd, struct test_file *file) +{ + uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE]; + struct incfs_pending_read_info prs[100] = {}; + int prs_size = ARRAY_SIZE(prs); + int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE; + int res; + int read_count; + int i; + char *filename = concat_file_name(mount_dir, file->name); + int fd; + + fd = open(filename, O_RDONLY); + free(filename); + if (fd <= 0) + return TEST_FAILURE; + + if (block_cnt > prs_size) + block_cnt = prs_size; + + for (i = 0; i < block_cnt; i++) { + res = pread(fd, data, sizeof(data), + INCFS_DATA_FILE_BLOCK_SIZE * i); + if (res <= 0) + goto failure; + } + + read_count = wait_for_pending_reads(log_fd, 0, prs, prs_size); + if (read_count < 0) { + ksft_print_msg("Error reading logged reads %s.\n", + strerror(-read_count)); + goto failure; + } + + if (read_count != block_cnt) { + ksft_print_msg("Bad log read count %s %d %d.\n", file->name, + read_count, block_cnt); + goto failure; + } + + for (i = 0; i < read_count; i++) { + struct incfs_pending_read_info *read = &prs[i]; + + if (!same_id(&read->file_id, &file->id)) { + ksft_print_msg("Bad log read ino %s\n", file->name); + goto failure; + } + + if (read->block_index != i) { + ksft_print_msg("Bad log read ino %s %d %d.\n", + file->name, read->block_index, i); + goto failure; + } + + if (i != 0) { + unsigned long psn = prs[i - 1].serial_number; + + if (read->serial_number != psn + 1) { + ksft_print_msg("Bad log read sn %s %d %d.\n", + file->name, read->serial_number, + psn); + goto failure; + } + } + + if (read->timestamp_us == 0) { + ksft_print_msg("Bad log read timestamp %s.\n", + file->name); + goto failure; + } + } + close(fd); + return TEST_SUCCESS; + +failure: + close(fd); + return TEST_FAILURE; +} + +static int read_log_test(char *mount_dir) +{ + struct test_files_set test = get_test_files_set(); + const int file_num = test.files_count; + int i = 0; + int cmd_fd = -1, log_fd = -1; + char *backing_dir; + + backing_dir = create_backing_dir(mount_dir); + if (!backing_dir) + goto failure; + + if (mount_fs_opt(mount_dir, backing_dir, "readahead=0") != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + log_fd = open_log_file(mount_dir); + if (cmd_fd < 0) + ksft_print_msg("Can't open log file.\n"); + + /* Write data. */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (emit_file(cmd_fd, NULL, file->name, &file->id, + file->size, NULL)) + goto failure; + + if (emit_test_file_data(mount_dir, file)) + goto failure; + } + + /* Validate data */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (validate_logs(mount_dir, log_fd, file)) + goto failure; + } + + /* Unmount and mount again, to see that logs work after remount. */ + close(cmd_fd); + close(log_fd); + cmd_fd = -1; + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + if (mount_fs_opt(mount_dir, backing_dir, "readahead=0") != 0) + goto failure; + + cmd_fd = open_commands_file(mount_dir); + if (cmd_fd < 0) + goto failure; + + log_fd = open_log_file(mount_dir); + if (cmd_fd < 0) + ksft_print_msg("Can't open log file.\n"); + + /* Validate data again */ + for (i = 0; i < file_num; i++) { + struct test_file *file = &test.files[i]; + + if (validate_logs(mount_dir, log_fd, file)) + goto failure; + } + + /* Final unmount */ + close(cmd_fd); + close(log_fd); + free(backing_dir); + if (umount(mount_dir) != 0) { + print_error("Can't unmout FS"); + goto failure; + } + + return TEST_SUCCESS; + +failure: + close(cmd_fd); + close(log_fd); + free(backing_dir); + umount(mount_dir); + return TEST_FAILURE; +} + +static char *setup_mount_dir() +{ + struct stat st; + char *current_dir = getcwd(NULL, 0); + char *mount_dir = concat_file_name(current_dir, "incfs-mount-dir"); + + free(current_dir); + if (stat(mount_dir, &st) == 0) { + if (S_ISDIR(st.st_mode)) + return mount_dir; + + ksft_print_msg("%s is a file, not a dir.\n", mount_dir); + return NULL; + } + + if (mkdir(mount_dir, 0777)) { + print_error("Can't create mount dir."); + return NULL; + } + + return mount_dir; +} + +int main(int argc, char *argv[]) +{ + char *mount_dir = NULL; + int fails = 0; + int i; + int fd, count; + + // Seed randomness pool for testing on QEMU + // NOTE - this abuses the concept of randomness - do *not* ever do this + // on a machine for production use - the device will think it has good + // randomness when it does not. + fd = open("/dev/urandom", O_WRONLY); + count = 4096; + for (int i = 0; i < 128; ++i) + ioctl(fd, RNDADDTOENTCNT, &count); + close(fd); + + ksft_print_header(); + + if (geteuid() != 0) + ksft_print_msg("Not a root, might fail to mount.\n"); + + mount_dir = setup_mount_dir(); + if (mount_dir == NULL) + ksft_exit_fail_msg("Can't create a mount dir\n"); + +#define MAKE_TEST(test) \ + { \ + test, #test \ + } + struct { + int (*pfunc)(char *dir); + const char *name; + } cases[] = { + MAKE_TEST(basic_file_ops_test), + MAKE_TEST(cant_touch_index_test), + MAKE_TEST(dynamic_files_and_data_test), + MAKE_TEST(concurrent_reads_and_writes_test), + MAKE_TEST(attribute_test), + MAKE_TEST(work_after_remount_test), + MAKE_TEST(child_procs_waiting_for_data_test), + MAKE_TEST(multiple_providers_test), + MAKE_TEST(signature_test), + MAKE_TEST(hash_tree_test), + MAKE_TEST(read_log_test), + }; +#undef MAKE_TEST + + ksft_set_plan(ARRAY_SIZE(cases)); + for (i = 0; i < ARRAY_SIZE(cases); ++i) { + ksft_print_msg("Running %s\n", cases[i].name); + if (cases[i].pfunc(mount_dir) == TEST_SUCCESS) + ksft_test_result_pass("%s\n", cases[i].name); + else { + ksft_test_result_fail("%s\n", cases[i].name); + fails++; + } + } + + umount2(mount_dir, MNT_FORCE); + rmdir(mount_dir); + + if (fails > 0) + ksft_exit_pass(); + else + ksft_exit_pass(); + return 0; +} diff --git a/tools/testing/selftests/filesystems/incfs/utils.c b/tools/testing/selftests/filesystems/incfs/utils.c new file mode 100644 index 000000000000..08b8452ad0bc --- /dev/null +++ b/tools/testing/selftests/filesystems/incfs/utils.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 Google LLC + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +int mount_fs(char *mount_dir, char *backing_dir, int read_timeout_ms) +{ + static const char fs_name[] = INCFS_NAME; + char mount_options[512]; + int result; + + snprintf(mount_options, ARRAY_SIZE(mount_options), + "read_timeout_ms=%u", + read_timeout_ms); + + result = mount(backing_dir, mount_dir, fs_name, 0, mount_options); + if (result != 0) + perror("Error mounting fs."); + return result; +} + +int mount_fs_opt(char *mount_dir, char *backing_dir, char *opt) +{ + static const char fs_name[] = INCFS_NAME; + int result; + + result = mount(backing_dir, mount_dir, fs_name, 0, opt); + if (result != 0) + perror("Error mounting fs."); + return result; +} + +int unlink_node(int fd, int parent_ino, char *filename) +{ + return 0; +} + + +static EVP_PKEY *deserialize_private_key(const char *pem_key) +{ + BIO *bio = NULL; + EVP_PKEY *pkey = NULL; + int len = strlen(pem_key); + + bio = BIO_new_mem_buf(pem_key, len); + if (!bio) + return NULL; + + pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + BIO_free(bio); + return pkey; +} + +static X509 *deserialize_cert(const char *pem_cert) +{ + BIO *bio = NULL; + X509 *cert = NULL; + int len = strlen(pem_cert); + + bio = BIO_new_mem_buf(pem_cert, len); + if (!bio) + return NULL; + + cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free(bio); + return cert; +} + +bool sign_pkcs7(const void *data_to_sign, size_t data_size, + char *pkey_pem, char *cert_pem, + void **sig_ret, size_t *sig_size_ret) +{ + /* + * PKCS#7 signing flags: + * + * - PKCS7_BINARY signing binary data, so skip MIME translation + * + * - PKCS7_NOATTR omit extra authenticated attributes, such as + * SMIMECapabilities + * + * - PKCS7_PARTIAL PKCS7_sign() creates a handle only, then + * PKCS7_sign_add_signer() can add a signer later. + * This is necessary to change the message digest + * algorithm from the default of SHA-1. Requires + * OpenSSL 1.0.0 or later. + */ + int pkcs7_flags = PKCS7_BINARY | PKCS7_NOATTR | PKCS7_PARTIAL; + void *sig; + size_t sig_size; + BIO *bio = NULL; + PKCS7 *p7 = NULL; + EVP_PKEY *pkey = NULL; + X509 *cert = NULL; + bool ok = false; + + const EVP_MD *md = EVP_sha256(); + + pkey = deserialize_private_key(pkey_pem); + if (!pkey) { + printf("deserialize_private_key failed\n"); + goto out; + } + + cert = deserialize_cert(cert_pem); + if (!cert) { + printf("deserialize_cert failed\n"); + goto out; + } + + bio = BIO_new_mem_buf(data_to_sign, data_size); + if (!bio) + goto out; + + p7 = PKCS7_sign(NULL, NULL, NULL, bio, pkcs7_flags); + if (!p7) { + printf("failed to initialize PKCS#7 signature object\n"); + goto out; + } + + if (!PKCS7_sign_add_signer(p7, cert, pkey, md, pkcs7_flags)) { + printf("failed to add signer to PKCS#7 signature object\n"); + goto out; + } + + if (PKCS7_final(p7, bio, pkcs7_flags) != 1) { + printf("failed to finalize PKCS#7 signature\n"); + goto out; + } + + BIO_free(bio); + bio = BIO_new(BIO_s_mem()); + if (!bio) { + printf("out of memory\n"); + goto out; + } + + if (i2d_PKCS7_bio(bio, p7) != 1) { + printf("failed to DER-encode PKCS#7 signature object\n"); + goto out; + } + + sig_size = BIO_get_mem_data(bio, &sig); + *sig_ret = malloc(sig_size); + memcpy(*sig_ret, sig, sig_size); + *sig_size_ret = sig_size; + ok = true; +out: + PKCS7_free(p7); + BIO_free(bio); + return ok; +} + +int crypto_emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out, + size_t size, const char *root_hash, char *sig, size_t sig_size, + char *add_data) +{ + int mode = __S_IFREG | 0555; + struct incfs_file_signature_info sig_info = { + .hash_tree_alg = root_hash + ? INCFS_HASH_TREE_SHA256 + : 0, + .root_hash = ptr_to_u64(root_hash), + .additional_data = ptr_to_u64(add_data), + .additional_data_size = strlen(add_data), + .signature = ptr_to_u64(sig), + .signature_size = sig_size, + }; + + struct incfs_new_file_args args = { + .size = size, + .mode = mode, + .file_name = ptr_to_u64(filename), + .directory_path = ptr_to_u64(dir), + .signature_info = ptr_to_u64(&sig_info), + .file_attr = 0, + .file_attr_len = 0 + }; + + md5(filename, strlen(filename), (char *)args.file_id.bytes); + + if (ioctl(fd, INCFS_IOC_CREATE_FILE, &args) != 0) + return -errno; + + *id_out = args.file_id; + return 0; +} + + +int emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out, + size_t size, char *attr) +{ + int mode = __S_IFREG | 0555; + struct incfs_file_signature_info sig_info = { + .hash_tree_alg = 0, + .root_hash = ptr_to_u64(NULL) + }; + struct incfs_new_file_args args = { + .size = size, + .mode = mode, + .file_name = ptr_to_u64(filename), + .directory_path = ptr_to_u64(dir), + .signature_info = ptr_to_u64(&sig_info), + .file_attr = ptr_to_u64(attr), + .file_attr_len = attr ? strlen(attr) : 0 + }; + + md5(filename, strlen(filename), (char *)args.file_id.bytes); + + if (ioctl(fd, INCFS_IOC_CREATE_FILE, &args) != 0) + return -errno; + + *id_out = args.file_id; + return 0; +} + +int get_file_bmap(int cmd_fd, int ino, unsigned char *buf, int buf_size) +{ + return 0; +} + +int get_file_signature(int fd, unsigned char *buf, int buf_size) +{ + struct incfs_get_file_sig_args args = { + .file_signature = ptr_to_u64(buf), + .file_signature_buf_size = buf_size + }; + + if (ioctl(fd, INCFS_IOC_READ_FILE_SIGNATURE, &args) == 0) + return args.file_signature_len_out; + return -errno; +} + +loff_t get_file_size(char *name) +{ + struct stat st; + + if (stat(name, &st) == 0) + return st.st_size; + return -ENOENT; +} + +int open_commands_file(char *mount_dir) +{ + char cmd_file[255]; + int cmd_fd; + + snprintf(cmd_file, ARRAY_SIZE(cmd_file), + "%s/%s", mount_dir, INCFS_PENDING_READS_FILENAME); + cmd_fd = open(cmd_file, O_RDONLY); + + if (cmd_fd < 0) + perror("Can't open commands file"); + return cmd_fd; +} + +int open_log_file(char *mount_dir) +{ + char cmd_file[255]; + int cmd_fd; + + snprintf(cmd_file, ARRAY_SIZE(cmd_file), "%s/.log", mount_dir); + cmd_fd = open(cmd_file, O_RDWR); + if (cmd_fd < 0) + perror("Can't open log file"); + return cmd_fd; +} + +int wait_for_pending_reads(int fd, int timeout_ms, + struct incfs_pending_read_info *prs, int prs_count) +{ + ssize_t read_res = 0; + + if (timeout_ms > 0) { + int poll_res = 0; + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN + }; + + poll_res = poll(&pollfd, 1, timeout_ms); + if (poll_res < 0) + return -errno; + if (poll_res == 0) + return 0; + if (!(pollfd.revents | POLLIN)) + return 0; + } + + read_res = read(fd, prs, prs_count * sizeof(*prs)); + if (read_res < 0) + return -errno; + + return read_res / sizeof(*prs); +} + +char *concat_file_name(const char *dir, char *file) +{ + char full_name[FILENAME_MAX] = ""; + + if (snprintf(full_name, ARRAY_SIZE(full_name), "%s/%s", dir, file) < 0) + return NULL; + return strdup(full_name); +} + +int delete_dir_tree(const char *dir_path) +{ + DIR *dir = NULL; + struct dirent *dp; + int result = 0; + + dir = opendir(dir_path); + if (!dir) { + result = -errno; + goto out; + } + + while ((dp = readdir(dir))) { + char *full_path; + + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) + continue; + + full_path = concat_file_name(dir_path, dp->d_name); + if (dp->d_type == DT_DIR) + result = delete_dir_tree(full_path); + else + result = unlink(full_path); + free(full_path); + if (result) + goto out; + } + +out: + if (dir) + closedir(dir); + if (!result) + rmdir(dir_path); + return result; +} + +void sha256(char *data, size_t dsize, char *hash) +{ + SHA256_CTX ctx; + + SHA256_Init(&ctx); + SHA256_Update(&ctx, data, dsize); + SHA256_Final((unsigned char *)hash, &ctx); +} + +void md5(char *data, size_t dsize, char *hash) +{ + MD5_CTX ctx; + + MD5_Init(&ctx); + MD5_Update(&ctx, data, dsize); + MD5_Final((unsigned char *)hash, &ctx); +} diff --git a/tools/testing/selftests/filesystems/incfs/utils.h b/tools/testing/selftests/filesystems/incfs/utils.h new file mode 100644 index 000000000000..9c9ba3c5f70a --- /dev/null +++ b/tools/testing/selftests/filesystems/incfs/utils.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ +#include +#include + +#include "../../include/uapi/linux/incrementalfs.h" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) + +#ifdef __LP64__ +#define ptr_to_u64(p) ((__u64)p) +#else +#define ptr_to_u64(p) ((__u64)(__u32)p) +#endif + +#define SHA256_DIGEST_SIZE 32 + +int mount_fs(char *mount_dir, char *backing_dir, int read_timeout_ms); + +int mount_fs_opt(char *mount_dir, char *backing_dir, char *opt); + +int get_file_bmap(int cmd_fd, int ino, unsigned char *buf, int buf_size); + +int get_file_signature(int fd, unsigned char *buf, int buf_size); + +int emit_node(int fd, char *filename, int *ino_out, int parent_ino, + size_t size, mode_t mode, char *attr); + +int emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out, + size_t size, char *attr); + +int crypto_emit_file(int fd, char *dir, char *filename, incfs_uuid_t *id_out, + size_t size, const char *root_hash, char *sig, size_t sig_size, + char *add_data); + +int unlink_node(int fd, int parent_ino, char *filename); + +loff_t get_file_size(char *name); + +int open_commands_file(char *mount_dir); + +int open_log_file(char *mount_dir); + +int wait_for_pending_reads(int fd, int timeout_ms, + struct incfs_pending_read_info *prs, int prs_count); + +char *concat_file_name(const char *dir, char *file); + +void sha256(char *data, size_t dsize, char *hash); + +void md5(char *data, size_t dsize, char *hash); + +bool sign_pkcs7(const void *data_to_sign, size_t data_size, + char *pkey_pem, char *cert_pem, + void **sig_ret, size_t *sig_size_ret); + +int delete_dir_tree(const char *path); -- GitLab From aa40e0ce6db23acbc1bfcca0f09a64758b512a74 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Mon, 27 Jan 2020 14:48:38 -0800 Subject: [PATCH 0642/1055] ANDROID: Make incfs selftests pass Fixed incfs_test build errors Fixed Kconfig errors Readded .gitignore Test: With just enabling CONFIG_INCREMENTAL_FS, both defconfig and cuttlefish_defconfig build and incfs_test runs and passes Bug: 133435829 Change-Id: Id3247ffcc63a095f66dcedf554017a06c5a9ce4a Signed-off-by: Paul Lawrence --- fs/incfs/Kconfig | 1 + tools/testing/selftests/filesystems/incfs/.gitignore | 1 + tools/testing/selftests/filesystems/incfs/Makefile | 2 ++ tools/testing/selftests/filesystems/incfs/incfs_test.c | 4 +++- 4 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/filesystems/incfs/.gitignore diff --git a/fs/incfs/Kconfig b/fs/incfs/Kconfig index d860c07664c3..a655d599ea46 100644 --- a/fs/incfs/Kconfig +++ b/fs/incfs/Kconfig @@ -4,6 +4,7 @@ config INCREMENTAL_FS select DECOMPRESS_LZ4 select CRC32 select CRYPTO + select CRYPTO_RSA select CRYPTO_SHA256 select X509_CERTIFICATE_PARSER select ASYMMETRIC_KEY_TYPE diff --git a/tools/testing/selftests/filesystems/incfs/.gitignore b/tools/testing/selftests/filesystems/incfs/.gitignore new file mode 100644 index 000000000000..4cba9c219a92 --- /dev/null +++ b/tools/testing/selftests/filesystems/incfs/.gitignore @@ -0,0 +1 @@ +incfs_test \ No newline at end of file diff --git a/tools/testing/selftests/filesystems/incfs/Makefile b/tools/testing/selftests/filesystems/incfs/Makefile index 7cff78cf5131..1f13573d3617 100644 --- a/tools/testing/selftests/filesystems/incfs/Makefile +++ b/tools/testing/selftests/filesystems/incfs/Makefile @@ -5,6 +5,8 @@ CFLAGS += -I../../../../include/uapi/ CFLAGS += -I../../../../lib EXTRA_SOURCES := utils.c +CFLAGS += $(EXTRA_SOURCES) + TEST_GEN_PROGS := incfs_test include ../../lib.mk diff --git a/tools/testing/selftests/filesystems/incfs/incfs_test.c b/tools/testing/selftests/filesystems/incfs/incfs_test.c index f1e9f86605e7..dd70e019dc4c 100644 --- a/tools/testing/selftests/filesystems/incfs/incfs_test.c +++ b/tools/testing/selftests/filesystems/incfs/incfs_test.c @@ -2398,7 +2398,9 @@ int main(int argc, char *argv[]) }; #undef MAKE_TEST - ksft_set_plan(ARRAY_SIZE(cases)); + /* Bring back for kernel 5.x */ + /* ksft_set_plan(ARRAY_SIZE(cases)); */ + for (i = 0; i < ARRAY_SIZE(cases); ++i) { ksft_print_msg("Running %s\n", cases[i].name); if (cases[i].pfunc(mount_dir) == TEST_SUCCESS) -- GitLab From 4a1f984742c7b4ebfd2d77f48bf24b4ffcb069fd Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 28 Jan 2020 14:21:12 -0800 Subject: [PATCH 0643/1055] ANDROID: Fixing incremental fs style issues Removed WARN_ONs Removed compatibilty code Fixed tab issue Bug: 133435829 Signed-off-by: Paul Lawrence Change-Id: I8a9e9ead48a65fd09c2d01d22f65d9a352f118e2 --- fs/incfs/compat.h | 33 --------------------------------- fs/incfs/data_mgmt.c | 14 ++++---------- fs/incfs/format.c | 9 --------- fs/incfs/integrity.c | 4 ---- fs/incfs/vfs.c | 28 +++------------------------- 5 files changed, 7 insertions(+), 81 deletions(-) delete mode 100644 fs/incfs/compat.h diff --git a/fs/incfs/compat.h b/fs/incfs/compat.h deleted file mode 100644 index f6fd9b2b3cb2..000000000000 --- a/fs/incfs/compat.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright 2019 Google LLC - */ -#ifndef _INCFS_COMPAT_H -#define _INCFS_COMPAT_H - -#include -#include - -typedef unsigned int __poll_t; - -#ifndef u64_to_user_ptr -#define u64_to_user_ptr(x) ( \ -{ \ - typecheck(u64, x); \ - (void __user *)(uintptr_t)x; \ -} \ -) -#endif - -#ifndef lru_to_page -#define lru_to_page(head) (list_entry((head)->prev, struct page, lru)) -#endif - -#define readahead_gfp_mask(x) \ - (mapping_gfp_mask(x) | __GFP_NORETRY | __GFP_NOWARN) - -#ifndef SB_ACTIVE -#define SB_ACTIVE MS_ACTIVE -#endif - -#endif /* _INCFS_COMPAT_H */ diff --git a/fs/incfs/data_mgmt.c b/fs/incfs/data_mgmt.c index 25ea1099946d..109329e0a180 100644 --- a/fs/incfs/data_mgmt.c +++ b/fs/incfs/data_mgmt.c @@ -456,13 +456,9 @@ static struct pending_read *add_pending_read(struct data_file *df, struct data_file_segment *segment = NULL; struct mount_info *mi = NULL; - WARN_ON(!df); segment = get_file_segment(df, block_index); mi = df->df_mount_info; - WARN_ON(!segment); - WARN_ON(!mi); - result = kzalloc(sizeof(*result), GFP_NOFS); if (!result) return NULL; @@ -545,8 +541,6 @@ static int wait_for_data_block(struct data_file *df, int block_index, return -ENODATA; segment = get_file_segment(df, block_index); - WARN_ON(!segment); - error = mutex_lock_interruptible(&segment->blockmap_mutex); if (error) return error; @@ -596,10 +590,10 @@ static int wait_for_data_block(struct data_file *df, int block_index, return -ETIME; } if (wait_res < 0) { - /* - * Only ERESTARTSYS is really expected here when a signal - * comes while we wait. - */ + /* + * Only ERESTARTSYS is really expected here when a signal + * comes while we wait. + */ return wait_res; } diff --git a/fs/incfs/format.c b/fs/incfs/format.c index 27498b9c3d34..247e1b4ec563 100644 --- a/fs/incfs/format.c +++ b/fs/incfs/format.c @@ -12,7 +12,6 @@ #include #include -#include "compat.h" #include "format.h" struct backing_file_context *incfs_alloc_bfc(struct file *backing_file) @@ -679,18 +678,10 @@ int incfs_read_next_metadata_record(struct backing_file_context *bfc, ssize_t incfs_kread(struct file *f, void *buf, size_t size, loff_t pos) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) - return kernel_read(f, pos, (char *)buf, size); -#else return kernel_read(f, buf, size, &pos); -#endif } ssize_t incfs_kwrite(struct file *f, const void *buf, size_t size, loff_t pos) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) - return kernel_write(f, buf, size, pos); -#else return kernel_write(f, buf, size, &pos); -#endif } diff --git a/fs/incfs/integrity.c b/fs/incfs/integrity.c index c6444e73e4d8..feb212c38945 100644 --- a/fs/incfs/integrity.c +++ b/fs/incfs/integrity.c @@ -26,11 +26,7 @@ int incfs_validate_pkcs7_signature(struct mem_range pkcs7_blob, return PTR_ERR(pkcs7); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) - err = pkcs7_get_content_data(pkcs7, &data, &data_len, false); -#else err = pkcs7_get_content_data(pkcs7, &data, &data_len, NULL); -#endif if (err || data_len == 0 || data == NULL) { pr_debug("PKCS#7 message does not contain data\n"); err = -EBADMSG; diff --git a/fs/incfs/vfs.c b/fs/incfs/vfs.c index 41efd70af8e1..0c2f23e5ca55 100644 --- a/fs/incfs/vfs.c +++ b/fs/incfs/vfs.c @@ -18,7 +18,6 @@ #include -#include "compat.h" #include "data_mgmt.h" #include "format.h" #include "integrity.h" @@ -31,6 +30,9 @@ #define READ_EXEC_FILE_MODE 0555 #define READ_WRITE_FILE_MODE 0666 +/* Needed for kernel 4.14 - remove for later kernels */ +typedef unsigned int __poll_t; + static int incfs_remount_fs(struct super_block *sb, int *flags, char *data); static int dentry_revalidate(struct dentry *dentry, unsigned int flags); @@ -85,16 +87,12 @@ static const struct super_operations incfs_super_ops = { .show_options = show_options }; -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) -#define dir_rename_wrap dir_rename -#else static int dir_rename_wrap(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) { return dir_rename(old_dir, old_dentry, new_dir, new_dentry); } -#endif static const struct inode_operations incfs_dir_inode_ops = { .lookup = dir_lookup, @@ -157,17 +155,6 @@ static const struct file_operations incfs_log_file_ops = { .compat_ioctl = dispatch_ioctl }; -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0) - -static const struct inode_operations incfs_file_inode_ops = { - .setattr = simple_setattr, - .getattr = simple_getattr, - .getxattr = incfs_getxattr, - .listxattr = incfs_listxattr -}; - -#else - static const struct inode_operations incfs_file_inode_ops = { .setattr = simple_setattr, .getattr = simple_getattr, @@ -191,9 +178,6 @@ const struct xattr_handler *incfs_xattr_ops[] = { NULL, }; - -#endif - /* State of an open .pending_reads file, unique for each file descriptor. */ struct pending_reads_state { /* A serial number of the last pending read obtained from this file. */ @@ -1647,12 +1631,8 @@ static int dir_unlink(struct inode *dir, struct dentry *dentry) goto out; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) - err = vfs_getattr(&backing_path, &stat); -#else err = vfs_getattr(&backing_path, &stat, STATX_NLINK, AT_STATX_SYNC_AS_STAT); -#endif if (err) goto out; @@ -2078,9 +2058,7 @@ struct dentry *incfs_mount_fs(struct file_system_type *type, int flags, sb->s_time_gran = 1; sb->s_blocksize = INCFS_DATA_FILE_BLOCK_SIZE; sb->s_blocksize_bits = blksize_bits(sb->s_blocksize); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) sb->s_xattr = incfs_xattr_ops; -#endif BUILD_BUG_ON(PAGE_SIZE != INCFS_DATA_FILE_BLOCK_SIZE); -- GitLab From 641dfeb61d45e3c3a841bcaaa5389adc037d733e Mon Sep 17 00:00:00 2001 From: Andrey Shvetsov Date: Thu, 16 Jan 2020 18:22:39 +0100 Subject: [PATCH 0644/1055] UPSTREAM: staging: most: net: fix buffer overflow If the length of the socket buffer is 0xFFFFFFFF (max size for an unsigned int), then payload_len becomes 0xFFFFFFF1 after subtracting 14 (ETH_HLEN). Then, mdp_len is set to payload_len + 16 (MDP_HDR_LEN) which overflows and results in a value of 2. These values for payload_len and mdp_len will pass current buffer size checks. This patch checks if derived from skb->len sum may overflow. The check is based on the following idea: For any `unsigned V1, V2` and derived `unsigned SUM = V1 + V2`, `V1 + V2` overflows iif `SUM < V1`. Bug: 143560807 Reported-by: Greg Kroah-Hartman Signed-off-by: Andrey Shvetsov Cc: stable Link: https://lore.kernel.org/r/20200116172238.6046-1-andrey.shvetsov@microchip.com Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 4d1356ac12f4d5180d0df345d85ff0ee42b89c72) Signed-off-by: Greg Kroah-Hartman Change-Id: I71197b2963735ba181314332737fc0c1ca2cab96 --- drivers/staging/most/aim-network/networking.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/staging/most/aim-network/networking.c b/drivers/staging/most/aim-network/networking.c index 936f013c350e..6398c27563c9 100644 --- a/drivers/staging/most/aim-network/networking.c +++ b/drivers/staging/most/aim-network/networking.c @@ -85,6 +85,11 @@ static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo) unsigned int payload_len = skb->len - ETH_HLEN; unsigned int mdp_len = payload_len + MDP_HDR_LEN; + if (mdp_len < skb->len) { + pr_err("drop: too large packet! (%u)\n", skb->len); + return -EINVAL; + } + if (mbo->buffer_length < mdp_len) { pr_err("drop: too small buffer! (%d for %d)\n", mbo->buffer_length, mdp_len); @@ -132,6 +137,11 @@ static int skb_to_mep(const struct sk_buff *skb, struct mbo *mbo) u8 *buff = mbo->virt_address; unsigned int mep_len = skb->len + MEP_HDR_LEN; + if (mep_len < skb->len) { + pr_err("drop: too large packet! (%u)\n", skb->len); + return -EINVAL; + } + if (mbo->buffer_length < mep_len) { pr_err("drop: too small buffer! (%d for %d)\n", mbo->buffer_length, mep_len); -- GitLab From c39c4e9116943faf30fb7fb9cc1e739c732b4443 Mon Sep 17 00:00:00 2001 From: Richard Palethorpe Date: Tue, 21 Jan 2020 14:42:58 +0100 Subject: [PATCH 0645/1055] can, slip: Protect tty->disc_data in write_wakeup and close with RCU [ Upstream commit 0ace17d56824165c7f4c68785d6b58971db954dd ] write_wakeup can happen in parallel with close/hangup where tty->disc_data is set to NULL and the netdevice is freed thus also freeing disc_data. write_wakeup accesses disc_data so we must prevent close from freeing the netdev while write_wakeup has a non-NULL view of tty->disc_data. We also need to make sure that accesses to disc_data are atomic. Which can all be done with RCU. This problem was found by Syzkaller on SLCAN, but the same issue is reproducible with the SLIP line discipline using an LTP test based on the Syzkaller reproducer. A fix which didn't use RCU was posted by Hillf Danton. Fixes: 661f7fda21b1 ("slip: Fix deadlock in write_wakeup") Fixes: a8e83b17536a ("slcan: Port write_wakeup deadlock fix from slip") Reported-by: syzbot+017e491ae13c0068598a@syzkaller.appspotmail.com Signed-off-by: Richard Palethorpe Cc: Wolfgang Grandegger Cc: Marc Kleine-Budde Cc: "David S. Miller" Cc: Tyler Hall Cc: linux-can@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: syzkaller@googlegroups.com Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/slcan.c | 12 ++++++++++-- drivers/net/slip/slip.c | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index a42737b4ac79..35564a9561b7 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -343,9 +343,16 @@ static void slcan_transmit(struct work_struct *work) */ static void slcan_write_wakeup(struct tty_struct *tty) { - struct slcan *sl = tty->disc_data; + struct slcan *sl; + + rcu_read_lock(); + sl = rcu_dereference(tty->disc_data); + if (!sl) + goto out; schedule_work(&sl->tx_work); +out: + rcu_read_unlock(); } /* Send a can_frame to a TTY queue. */ @@ -640,10 +647,11 @@ static void slcan_close(struct tty_struct *tty) return; spin_lock_bh(&sl->lock); - tty->disc_data = NULL; + rcu_assign_pointer(tty->disc_data, NULL); sl->tty = NULL; spin_unlock_bh(&sl->lock); + synchronize_rcu(); flush_work(&sl->tx_work); /* Flush network side */ diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index d6dc00b4ba55..b07f367abd91 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -452,9 +452,16 @@ static void slip_transmit(struct work_struct *work) */ static void slip_write_wakeup(struct tty_struct *tty) { - struct slip *sl = tty->disc_data; + struct slip *sl; + + rcu_read_lock(); + sl = rcu_dereference(tty->disc_data); + if (!sl) + goto out; schedule_work(&sl->tx_work); +out: + rcu_read_unlock(); } static void sl_tx_timeout(struct net_device *dev) @@ -886,10 +893,11 @@ static void slip_close(struct tty_struct *tty) return; spin_lock_bh(&sl->lock); - tty->disc_data = NULL; + rcu_assign_pointer(tty->disc_data, NULL); sl->tty = NULL; spin_unlock_bh(&sl->lock); + synchronize_rcu(); flush_work(&sl->tx_work); /* VSV = very important to remove timers */ -- GitLab From 70a985445d62b014970304080551c3697e7bd00e Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Sat, 25 Jan 2020 14:33:29 +0000 Subject: [PATCH 0646/1055] firestream: fix memory leaks [ Upstream commit fa865ba183d61c1ec8cbcab8573159c3b72b89a4 ] In fs_open(), 'vcc' is allocated through kmalloc() and assigned to 'atm_vcc->dev_data.' In the following execution, if an error occurs, e.g., there is no more free channel, an error code EBUSY or ENOMEM will be returned. However, 'vcc' is not deallocated, leading to memory leaks. Note that, in normal cases where fs_open() returns 0, 'vcc' will be deallocated in fs_close(). But, if fs_open() fails, there is no guarantee that fs_close() will be invoked. To fix this issue, deallocate 'vcc' before the error code is returned. Signed-off-by: Wenwen Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/atm/firestream.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 6b6368a56526..0e449ee11ac7 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -927,6 +927,7 @@ static int fs_open(struct atm_vcc *atm_vcc) } if (!to) { printk ("No more free channels for FS50..\n"); + kfree(vcc); return -EBUSY; } vcc->channo = dev->channo; @@ -937,6 +938,7 @@ static int fs_open(struct atm_vcc *atm_vcc) if (((DO_DIRECTION(rxtp) && dev->atm_vccs[vcc->channo])) || ( DO_DIRECTION(txtp) && test_bit (vcc->channo, dev->tx_inuse))) { printk ("Channel is in use for FS155.\n"); + kfree(vcc); return -EBUSY; } } @@ -950,6 +952,7 @@ static int fs_open(struct atm_vcc *atm_vcc) tc, sizeof (struct fs_transmit_config)); if (!tc) { fs_dprintk (FS_DEBUG_OPEN, "fs: can't alloc transmit_config.\n"); + kfree(vcc); return -ENOMEM; } -- GitLab From 4f0996db42deebaf7e58dc01a6e197dfa562aa9d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 21 Jan 2020 23:17:14 -0800 Subject: [PATCH 0647/1055] gtp: make sure only SOCK_DGRAM UDP sockets are accepted [ Upstream commit 940ba14986657a50c15f694efca1beba31fa568f ] A malicious user could use RAW sockets and fool GTP using them as standard SOCK_DGRAM UDP sockets. BUG: KMSAN: uninit-value in udp_tunnel_encap_enable include/net/udp_tunnel.h:174 [inline] BUG: KMSAN: uninit-value in setup_udp_tunnel_sock+0x45e/0x6f0 net/ipv4/udp_tunnel.c:85 CPU: 0 PID: 11262 Comm: syz-executor613 Not tainted 5.5.0-rc5-syzkaller #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+0x1c9/0x220 lib/dump_stack.c:118 kmsan_report+0xf7/0x1e0 mm/kmsan/kmsan_report.c:118 __msan_warning+0x58/0xa0 mm/kmsan/kmsan_instr.c:215 udp_tunnel_encap_enable include/net/udp_tunnel.h:174 [inline] setup_udp_tunnel_sock+0x45e/0x6f0 net/ipv4/udp_tunnel.c:85 gtp_encap_enable_socket+0x37f/0x5a0 drivers/net/gtp.c:827 gtp_encap_enable drivers/net/gtp.c:844 [inline] gtp_newlink+0xfb/0x1e50 drivers/net/gtp.c:666 __rtnl_newlink net/core/rtnetlink.c:3305 [inline] rtnl_newlink+0x2973/0x3920 net/core/rtnetlink.c:3363 rtnetlink_rcv_msg+0x1153/0x1570 net/core/rtnetlink.c:5424 netlink_rcv_skb+0x451/0x650 net/netlink/af_netlink.c:2477 rtnetlink_rcv+0x50/0x60 net/core/rtnetlink.c:5442 netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline] netlink_unicast+0xf9e/0x1100 net/netlink/af_netlink.c:1328 netlink_sendmsg+0x1248/0x14d0 net/netlink/af_netlink.c:1917 sock_sendmsg_nosec net/socket.c:639 [inline] sock_sendmsg net/socket.c:659 [inline] ____sys_sendmsg+0x12b6/0x1350 net/socket.c:2330 ___sys_sendmsg net/socket.c:2384 [inline] __sys_sendmsg+0x451/0x5f0 net/socket.c:2417 __do_sys_sendmsg net/socket.c:2426 [inline] __se_sys_sendmsg+0x97/0xb0 net/socket.c:2424 __x64_sys_sendmsg+0x4a/0x70 net/socket.c:2424 do_syscall_64+0xb8/0x160 arch/x86/entry/common.c:296 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x441359 Code: e8 ac e8 ff ff 48 83 c4 18 c3 0f 1f 80 00 00 00 00 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 eb 08 fc ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007fff1cd0ac28 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 0000000000441359 RDX: 0000000000000000 RSI: 0000000020000100 RDI: 0000000000000003 RBP: 00000000006cb018 R08: 00000000004002c8 R09: 00000000004002c8 R10: 00000000004002c8 R11: 0000000000000246 R12: 00000000004020d0 R13: 0000000000402160 R14: 0000000000000000 R15: 0000000000000000 Uninit was created at: kmsan_save_stack_with_flags+0x3c/0x90 mm/kmsan/kmsan.c:144 kmsan_internal_alloc_meta_for_pages mm/kmsan/kmsan_shadow.c:307 [inline] kmsan_alloc_page+0x12a/0x310 mm/kmsan/kmsan_shadow.c:336 __alloc_pages_nodemask+0x57f2/0x5f60 mm/page_alloc.c:4800 alloc_pages_current+0x67d/0x990 mm/mempolicy.c:2207 alloc_pages include/linux/gfp.h:534 [inline] alloc_slab_page+0x111/0x12f0 mm/slub.c:1511 allocate_slab mm/slub.c:1656 [inline] new_slab+0x2bc/0x1130 mm/slub.c:1722 new_slab_objects mm/slub.c:2473 [inline] ___slab_alloc+0x1533/0x1f30 mm/slub.c:2624 __slab_alloc mm/slub.c:2664 [inline] slab_alloc_node mm/slub.c:2738 [inline] slab_alloc mm/slub.c:2783 [inline] kmem_cache_alloc+0xb23/0xd70 mm/slub.c:2788 sk_prot_alloc+0xf2/0x620 net/core/sock.c:1597 sk_alloc+0xf0/0xbe0 net/core/sock.c:1657 inet_create+0x7c7/0x1370 net/ipv4/af_inet.c:321 __sock_create+0x8eb/0xf00 net/socket.c:1420 sock_create net/socket.c:1471 [inline] __sys_socket+0x1a1/0x600 net/socket.c:1513 __do_sys_socket net/socket.c:1522 [inline] __se_sys_socket+0x8d/0xb0 net/socket.c:1520 __x64_sys_socket+0x4a/0x70 net/socket.c:1520 do_syscall_64+0xb8/0x160 arch/x86/entry/common.c:296 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Fixes: 459aa660eb1d ("gtp: add initial driver for datapath of GPRS Tunneling Protocol (GTP-U)") Signed-off-by: Eric Dumazet Cc: Pablo Neira Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/gtp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 25be27826a22..3840f21dd635 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -807,19 +807,21 @@ static struct sock *gtp_encap_enable_socket(int fd, int type, return NULL; } - if (sock->sk->sk_protocol != IPPROTO_UDP) { + sk = sock->sk; + if (sk->sk_protocol != IPPROTO_UDP || + sk->sk_type != SOCK_DGRAM || + (sk->sk_family != AF_INET && sk->sk_family != AF_INET6)) { pr_debug("socket fd=%d not UDP\n", fd); sk = ERR_PTR(-EINVAL); goto out_sock; } - lock_sock(sock->sk); - if (sock->sk->sk_user_data) { + lock_sock(sk); + if (sk->sk_user_data) { sk = ERR_PTR(-EBUSY); goto out_rel_sock; } - sk = sock->sk; sock_hold(sk); tuncfg.sk_user_data = gtp; -- GitLab From 8dbd5ab8ff84311023712f8aec21937e2d36a527 Mon Sep 17 00:00:00 2001 From: Yuki Taguchi Date: Mon, 20 Jan 2020 13:48:37 +0900 Subject: [PATCH 0648/1055] ipv6: sr: remove SKB_GSO_IPXIP6 on End.D* actions [ Upstream commit 62ebaeaedee7591c257543d040677a60e35c7aec ] After LRO/GRO is applied, SRv6 encapsulated packets have SKB_GSO_IPXIP6 feature flag, and this flag must be removed right after decapulation procedure. Currently, SKB_GSO_IPXIP6 flag is not removed on End.D* actions, which creates inconsistent packet state, that is, a normal TCP/IP packets have the SKB_GSO_IPXIP6 flag. This behavior can cause unexpected fallback to GSO on routing to netdevices that do not support SKB_GSO_IPXIP6. For example, on inter-VRF forwarding, decapsulated packets separated into small packets by GSO because VRF devices do not support TSO for packets with SKB_GSO_IPXIP6 flag, and this degrades forwarding performance. This patch removes encapsulation related GSO flags from the skb right after the End.D* action is applied. Fixes: d7a669dd2f8b ("ipv6: sr: add helper functions for seg6local") Signed-off-by: Yuki Taguchi Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/seg6_local.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c index 825b8e01f947..9a01f72d907f 100644 --- a/net/ipv6/seg6_local.c +++ b/net/ipv6/seg6_local.c @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef CONFIG_IPV6_SEG6_HMAC #include #endif @@ -126,7 +127,8 @@ static bool decap_and_validate(struct sk_buff *skb, int proto) skb_reset_network_header(skb); skb_reset_transport_header(skb); - skb->encapsulation = 0; + if (iptunnel_pull_offloads(skb)) + return false; return true; } -- GitLab From 4f26a3a8f99951d961424b7d241a73d53691dcd1 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 24 Jan 2020 20:41:44 +1100 Subject: [PATCH 0649/1055] net: cxgb3_main: Add CAP_NET_ADMIN check to CHELSIO_GET_MEM [ Upstream commit 3546d8f1bbe992488ed91592cf6bf76e7114791a = The cxgb3 driver for "Chelsio T3-based gigabit and 10Gb Ethernet adapters" implements a custom ioctl as SIOCCHIOCTL/SIOCDEVPRIVATE in cxgb_extension_ioctl(). One of the subcommands of the ioctl is CHELSIO_GET_MEM, which appears to read memory directly out of the adapter and return it to userspace. It's not entirely clear what the contents of the adapter memory contains, but the assumption is that it shouldn't be accessible to all users. So add a CAP_NET_ADMIN check to the CHELSIO_GET_MEM case. Put it after the is_offload() check, which matches two of the other subcommands in the same function which also check for is_offload() and CAP_NET_ADMIN. Found by Ilja by code inspection, not tested as I don't have the required hardware. Reported-by: Ilja Van Sprundel Signed-off-by: Michael Ellerman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index 338683e5ef1e..b8779afb8550 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -2449,6 +2449,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) if (!is_offload(adapter)) return -EOPNOTSUPP; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; if (!(adapter->flags & FULL_INIT_DONE)) return -EIO; /* need the memory controllers */ if (copy_from_user(&t, useraddr, sizeof(t))) -- GitLab From 1cc40dfad03c1dbf4b716d2d1615573964f502ab Mon Sep 17 00:00:00 2001 From: William Dauchy Date: Tue, 21 Jan 2020 21:49:54 +0100 Subject: [PATCH 0650/1055] net, ip6_tunnel: fix namespaces move [ Upstream commit 5311a69aaca30fa849c3cc46fb25f75727fb72d0 ] in the same manner as commit d0f418516022 ("net, ip_tunnel: fix namespaces move"), fix namespace moving as it was broken since commit 8d79266bc48c ("ip6_tunnel: add collect_md mode to IPv6 tunnel"), but for ipv6 this time; there is no reason to keep it for ip6_tunnel. Fixes: 8d79266bc48c ("ip6_tunnel: add collect_md mode to IPv6 tunnel") Signed-off-by: William Dauchy Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_tunnel.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 5bc2788e6ba4..c2644405bab1 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1878,10 +1878,8 @@ static int ip6_tnl_dev_init(struct net_device *dev) if (err) return err; ip6_tnl_link_config(t); - if (t->parms.collect_md) { - dev->features |= NETIF_F_NETNS_LOCAL; + if (t->parms.collect_md) netif_keep_dst(dev); - } return 0; } -- GitLab From 426d5d62459db84634490bfeeb8a13dbc266e845 Mon Sep 17 00:00:00 2001 From: William Dauchy Date: Tue, 21 Jan 2020 15:26:24 +0100 Subject: [PATCH 0651/1055] net, ip_tunnel: fix namespaces move [ Upstream commit d0f418516022c32ecceaf4275423e5bd3f8743a9 ] in the same manner as commit 690afc165bb3 ("net: ip6_gre: fix moving ip6gre between namespaces"), fix namespace moving as it was broken since commit 2e15ea390e6f ("ip_gre: Add support to collect tunnel metadata."). Indeed, the ip6_gre commit removed the local flag for collect_md condition, so there is no reason to keep it for ip_gre/ip_tunnel. this patch will fix both ip_tunnel and ip_gre modules. Fixes: 2e15ea390e6f ("ip_gre: Add support to collect tunnel metadata.") Signed-off-by: William Dauchy Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_tunnel.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index f1784162acc2..404dc765f2bf 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -1202,10 +1202,8 @@ int ip_tunnel_init(struct net_device *dev) iph->version = 4; iph->ihl = 5; - if (tunnel->collect_md) { - dev->features |= NETIF_F_NETNS_LOCAL; + if (tunnel->collect_md) netif_keep_dst(dev); - } return 0; } EXPORT_SYMBOL_GPL(ip_tunnel_init); -- GitLab From 24ac271a627ff257265bcd061b33b513260018af Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Wed, 22 Jan 2020 15:42:02 -0800 Subject: [PATCH 0652/1055] net_sched: fix datalen for ematch [ Upstream commit 61678d28d4a45ef376f5d02a839cc37509ae9281 ] syzbot reported an out-of-bound access in em_nbyte. As initially analyzed by Eric, this is because em_nbyte sets its own em->datalen in em_nbyte_change() other than the one specified by user, but this value gets overwritten later by its caller tcf_em_validate(). We should leave em->datalen untouched to respect their choices. I audit all the in-tree ematch users, all of those implement ->change() set em->datalen, so we can just avoid setting it twice in this case. Reported-and-tested-by: syzbot+5af9a90dad568aa9f611@syzkaller.appspotmail.com Reported-by: syzbot+2f07903a5b05e7f36410@syzkaller.appspotmail.com Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: Eric Dumazet Signed-off-by: Cong Wang Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/ematch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/ematch.c b/net/sched/ematch.c index 03b677bc0700..60f2354c1789 100644 --- a/net/sched/ematch.c +++ b/net/sched/ematch.c @@ -267,12 +267,12 @@ static int tcf_em_validate(struct tcf_proto *tp, } em->data = (unsigned long) v; } + em->datalen = data_len; } } em->matchid = em_hdr->matchid; em->flags = em_hdr->flags; - em->datalen = data_len; em->net = net; err = 0; -- GitLab From 7ac7cc5e78444a84e5786e822ca6643ad4cd55f7 Mon Sep 17 00:00:00 2001 From: Jouni Hogander Date: Wed, 20 Nov 2019 09:08:16 +0200 Subject: [PATCH 0653/1055] net-sysfs: Fix reference count leak in rx|netdev_queue_add_kobject commit b8eb718348b8fb30b5a7d0a8fce26fb3f4ac741b upstream. kobject_init_and_add takes reference even when it fails. This has to be given up by the caller in error handling. Otherwise memory allocated by kobject_init_and_add is never freed. Originally found by Syzkaller: BUG: memory leak unreferenced object 0xffff8880679f8b08 (size 8): comm "netdev_register", pid 269, jiffies 4294693094 (age 12.132s) hex dump (first 8 bytes): 72 78 2d 30 00 36 20 d4 rx-0.6 . backtrace: [<000000008c93818e>] __kmalloc_track_caller+0x16e/0x290 [<000000001f2e4e49>] kvasprintf+0xb1/0x140 [<000000007f313394>] kvasprintf_const+0x56/0x160 [<00000000aeca11c8>] kobject_set_name_vargs+0x5b/0x140 [<0000000073a0367c>] kobject_init_and_add+0xd8/0x170 [<0000000088838e4b>] net_rx_queue_update_kobjects+0x152/0x560 [<000000006be5f104>] netdev_register_kobject+0x210/0x380 [<00000000e31dab9d>] register_netdevice+0xa1b/0xf00 [<00000000f68b2465>] __tun_chr_ioctl+0x20d5/0x3dd0 [<000000004c50599f>] tun_chr_ioctl+0x2f/0x40 [<00000000bbd4c317>] do_vfs_ioctl+0x1c7/0x1510 [<00000000d4c59e8f>] ksys_ioctl+0x99/0xb0 [<00000000946aea81>] __x64_sys_ioctl+0x78/0xb0 [<0000000038d946e5>] do_syscall_64+0x16f/0x580 [<00000000e0aa5d8f>] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [<00000000285b3d1a>] 0xffffffffffffffff Cc: David Miller Cc: Lukas Bulwahn Signed-off-by: Jouni Hogander Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/net-sysfs.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index dee57c5ff738..3f015e736fa4 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -915,21 +915,23 @@ static int rx_queue_add_kobject(struct net_device *dev, int index) error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, "rx-%u", index); if (error) - return error; + goto err; dev_hold(queue->dev); if (dev->sysfs_rx_queue_group) { error = sysfs_create_group(kobj, dev->sysfs_rx_queue_group); - if (error) { - kobject_put(kobj); - return error; - } + if (error) + goto err; } kobject_uevent(kobj, KOBJ_ADD); return error; + +err: + kobject_put(kobj); + return error; } #endif /* CONFIG_SYSFS */ @@ -1326,21 +1328,21 @@ static int netdev_queue_add_kobject(struct net_device *dev, int index) error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, "tx-%u", index); if (error) - return error; + goto err; dev_hold(queue->dev); #ifdef CONFIG_BQL error = sysfs_create_group(kobj, &dql_group); - if (error) { - kobject_put(kobj); - return error; - } + if (error) + goto err; #endif kobject_uevent(kobj, KOBJ_ADD); - return 0; +err: + kobject_put(kobj); + return error; } #endif /* CONFIG_SYSFS */ -- GitLab From 5f36336849edd9c3294adc4f93141c0261b98034 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 20 Nov 2019 19:19:07 -0800 Subject: [PATCH 0654/1055] net-sysfs: fix netdev_queue_add_kobject() breakage commit 48a322b6f9965b2f1e4ce81af972f0e287b07ed0 upstream. kobject_put() should only be called in error path. Fixes: b8eb718348b8 ("net-sysfs: Fix reference count leak in rx|netdev_queue_add_kobject") Signed-off-by: Eric Dumazet Cc: Jouni Hogander Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/net-sysfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 3f015e736fa4..3a22fa4ec7ff 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -1339,6 +1339,7 @@ static int netdev_queue_add_kobject(struct net_device *dev, int index) #endif kobject_uevent(kobj, KOBJ_ADD); + return 0; err: kobject_put(kobj); -- GitLab From 8ba773a2866a929542574b4578a0433bc3d6f0ac Mon Sep 17 00:00:00 2001 From: Jouni Hogander Date: Thu, 5 Dec 2019 15:57:07 +0200 Subject: [PATCH 0655/1055] net-sysfs: Call dev_hold always in netdev_queue_add_kobject commit e0b60903b434a7ee21ba8d8659f207ed84101e89 upstream. Dev_hold has to be called always in netdev_queue_add_kobject. Otherwise usage count drops below 0 in case of failure in kobject_init_and_add. Fixes: b8eb718348b8 ("net-sysfs: Fix reference count leak in rx|netdev_queue_add_kobject") Reported-by: Hulk Robot Cc: Tetsuo Handa Cc: David Miller Cc: Lukas Bulwahn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/net-sysfs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 3a22fa4ec7ff..7a042847ec9b 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -1324,14 +1324,17 @@ static int netdev_queue_add_kobject(struct net_device *dev, int index) struct kobject *kobj = &queue->kobj; int error = 0; + /* Kobject_put later will trigger netdev_queue_release call + * which decreases dev refcount: Take that reference here + */ + dev_hold(queue->dev); + kobj->kset = dev->queues_kset; error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, "tx-%u", index); if (error) goto err; - dev_hold(queue->dev); - #ifdef CONFIG_BQL error = sysfs_create_group(kobj, &dql_group); if (error) -- GitLab From 8aca069fb05e2a65a264070efb9989cc72ab1694 Mon Sep 17 00:00:00 2001 From: Jouni Hogander Date: Tue, 17 Dec 2019 13:46:34 +0200 Subject: [PATCH 0656/1055] net-sysfs: Call dev_hold always in rx_queue_add_kobject commit ddd9b5e3e765d8ed5a35786a6cb00111713fe161 upstream. Dev_hold has to be called always in rx_queue_add_kobject. Otherwise usage count drops below 0 in case of failure in kobject_init_and_add. Fixes: b8eb718348b8 ("net-sysfs: Fix reference count leak in rx|netdev_queue_add_kobject") Reported-by: syzbot Cc: Tetsuo Handa Cc: David Miller Cc: Lukas Bulwahn Signed-off-by: Jouni Hogander Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/net-sysfs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 7a042847ec9b..baf771d2d088 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -911,14 +911,17 @@ static int rx_queue_add_kobject(struct net_device *dev, int index) struct kobject *kobj = &queue->kobj; int error = 0; + /* Kobject_put later will trigger rx_queue_release call which + * decreases dev refcount: Take that reference here + */ + dev_hold(queue->dev); + kobj->kset = dev->queues_kset; error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, "rx-%u", index); if (error) goto err; - dev_hold(queue->dev); - if (dev->sysfs_rx_queue_group) { error = sysfs_create_group(kobj, dev->sysfs_rx_queue_group); if (error) -- GitLab From c5fd8a37e97100254a2178e470e9641c51e91dbb Mon Sep 17 00:00:00 2001 From: Jouni Hogander Date: Mon, 20 Jan 2020 09:51:03 +0200 Subject: [PATCH 0657/1055] net-sysfs: Fix reference count leak [ Upstream commit cb626bf566eb4433318d35681286c494f04fedcc ] Netdev_register_kobject is calling device_initialize. In case of error reference taken by device_initialize is not given up. Drivers are supposed to call free_netdev in case of error. In non-error case the last reference is given up there and device release sequence is triggered. In error case this reference is kept and the release sequence is never started. Fix this by setting reg_state as NETREG_UNREGISTERED if registering fails. This is the rootcause for couple of memory leaks reported by Syzkaller: BUG: memory leak unreferenced object 0xffff8880675ca008 (size 256): comm "netdev_register", pid 281, jiffies 4294696663 (age 6.808s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<0000000058ca4711>] kmem_cache_alloc_trace+0x167/0x280 [<000000002340019b>] device_add+0x882/0x1750 [<000000001d588c3a>] netdev_register_kobject+0x128/0x380 [<0000000011ef5535>] register_netdevice+0xa1b/0xf00 [<000000007fcf1c99>] __tun_chr_ioctl+0x20d5/0x3dd0 [<000000006a5b7b2b>] tun_chr_ioctl+0x2f/0x40 [<00000000f30f834a>] do_vfs_ioctl+0x1c7/0x1510 [<00000000fba062ea>] ksys_ioctl+0x99/0xb0 [<00000000b1c1b8d2>] __x64_sys_ioctl+0x78/0xb0 [<00000000984cabb9>] do_syscall_64+0x16f/0x580 [<000000000bde033d>] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [<00000000e6ca2d9f>] 0xffffffffffffffff BUG: memory leak unreferenced object 0xffff8880668ba588 (size 8): comm "kobject_set_nam", pid 286, jiffies 4294725297 (age 9.871s) hex dump (first 8 bytes): 6e 72 30 00 cc be df 2b nr0....+ backtrace: [<00000000a322332a>] __kmalloc_track_caller+0x16e/0x290 [<00000000236fd26b>] kstrdup+0x3e/0x70 [<00000000dd4a2815>] kstrdup_const+0x3e/0x50 [<0000000049a377fc>] kvasprintf_const+0x10e/0x160 [<00000000627fc711>] kobject_set_name_vargs+0x5b/0x140 [<0000000019eeab06>] dev_set_name+0xc0/0xf0 [<0000000069cb12bc>] netdev_register_kobject+0xc8/0x320 [<00000000f2e83732>] register_netdevice+0xa1b/0xf00 [<000000009e1f57cc>] __tun_chr_ioctl+0x20d5/0x3dd0 [<000000009c560784>] tun_chr_ioctl+0x2f/0x40 [<000000000d759e02>] do_vfs_ioctl+0x1c7/0x1510 [<00000000351d7c31>] ksys_ioctl+0x99/0xb0 [<000000008390040a>] __x64_sys_ioctl+0x78/0xb0 [<0000000052d196b7>] do_syscall_64+0x16f/0x580 [<0000000019af9236>] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [<00000000bc384531>] 0xffffffffffffffff v3 -> v4: Set reg_state to NETREG_UNREGISTERED if registering fails v2 -> v3: * Replaced BUG_ON with WARN_ON in free_netdev and netdev_release v1 -> v2: * Relying on driver calling free_netdev rather than calling put_device directly in error path Reported-by: syzbot+ad8ca40ecd77896d51e2@syzkaller.appspotmail.com Cc: David Miller Cc: Greg Kroah-Hartman Cc: Lukas Bulwahn Signed-off-by: Jouni Hogander Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index f9f05b3df460..737211f1b29c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -7667,8 +7667,10 @@ int register_netdevice(struct net_device *dev) goto err_uninit; ret = netdev_register_kobject(dev); - if (ret) + if (ret) { + dev->reg_state = NETREG_UNREGISTERED; goto err_uninit; + } dev->reg_state = NETREG_REGISTERED; __netdev_update_features(dev); -- GitLab From d6502fc298460df8e72f525778cff3dd40daaab3 Mon Sep 17 00:00:00 2001 From: James Hughes Date: Mon, 20 Jan 2020 11:12:40 +0000 Subject: [PATCH 0658/1055] net: usb: lan78xx: Add .ndo_features_check [ Upstream commit ce896476c65d72b4b99fa09c2f33436b4198f034 ] As reported by Eric Dumazet, there are still some outstanding cases where the driver does not handle TSO correctly when skb's are over a certain size. Most cases have been fixed, this patch should ensure that forwarded SKB's that are greater than MAX_SINGLE_PACKET_SIZE - TX_OVERHEAD are software segmented and handled correctly. Signed-off-by: James Hughes Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/lan78xx.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index ee7194a9e231..b179a96ea08c 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -3525,6 +3526,19 @@ static void lan78xx_tx_timeout(struct net_device *net) tasklet_schedule(&dev->bh); } +static netdev_features_t lan78xx_features_check(struct sk_buff *skb, + struct net_device *netdev, + netdev_features_t features) +{ + if (skb->len + TX_OVERHEAD > MAX_SINGLE_PACKET_SIZE) + features &= ~NETIF_F_GSO_MASK; + + features = vlan_features_check(skb, features); + features = vxlan_features_check(skb, features); + + return features; +} + static const struct net_device_ops lan78xx_netdev_ops = { .ndo_open = lan78xx_open, .ndo_stop = lan78xx_stop, @@ -3538,6 +3552,7 @@ static const struct net_device_ops lan78xx_netdev_ops = { .ndo_set_features = lan78xx_set_features, .ndo_vlan_rx_add_vid = lan78xx_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = lan78xx_vlan_rx_kill_vid, + .ndo_features_check = lan78xx_features_check, }; static void lan78xx_stat_monitor(unsigned long param) -- GitLab From 7e70784f1702cd9f438e23168ae937397c2d323a Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Mon, 20 Jan 2020 18:04:56 +0800 Subject: [PATCH 0659/1055] tcp_bbr: improve arithmetic division in bbr_update_bw() [ Upstream commit 5b2f1f3070b6447b76174ea8bfb7390dc6253ebd ] do_div() does a 64-by-32 division. Use div64_long() instead of it if the divisor is long, to avoid truncation to 32-bit. And as a nice side effect also cleans up the function a bit. Signed-off-by: Wen Yang Cc: Eric Dumazet Cc: "David S. Miller" Cc: Alexey Kuznetsov Cc: Hideaki YOSHIFUJI Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_bbr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv4/tcp_bbr.c b/net/ipv4/tcp_bbr.c index 06f247ca9197..434ad1e72447 100644 --- a/net/ipv4/tcp_bbr.c +++ b/net/ipv4/tcp_bbr.c @@ -678,8 +678,7 @@ static void bbr_update_bw(struct sock *sk, const struct rate_sample *rs) * bandwidth sample. Delivered is in packets and interval_us in uS and * ratio will be <<1 for most connections. So delivered is first scaled. */ - bw = (u64)rs->delivered * BW_UNIT; - do_div(bw, rs->interval_us); + bw = div64_long((u64)rs->delivered * BW_UNIT, rs->interval_us); /* If this sample is application-limited, it is likely to have a very * low delivered count that represents application behavior rather than -- GitLab From e841252840c48e9a0e5add9d82796b1d55c0f653 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 21 Jan 2020 22:47:29 -0800 Subject: [PATCH 0660/1055] net: rtnetlink: validate IFLA_MTU attribute in rtnl_create_link() [ Upstream commit d836f5c69d87473ff65c06a6123e5b2cf5e56f5b ] rtnl_create_link() needs to apply dev->min_mtu and dev->max_mtu checks that we apply in do_setlink() Otherwise malicious users can crash the kernel, for example after an integer overflow : BUG: KASAN: use-after-free in memset include/linux/string.h:365 [inline] BUG: KASAN: use-after-free in __alloc_skb+0x37b/0x5e0 net/core/skbuff.c:238 Write of size 32 at addr ffff88819f20b9c0 by task swapper/0/0 CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.5.0-rc1-syzkaller #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+0x197/0x210 lib/dump_stack.c:118 print_address_description.constprop.0.cold+0xd4/0x30b mm/kasan/report.c:374 __kasan_report.cold+0x1b/0x41 mm/kasan/report.c:506 kasan_report+0x12/0x20 mm/kasan/common.c:639 check_memory_region_inline mm/kasan/generic.c:185 [inline] check_memory_region+0x134/0x1a0 mm/kasan/generic.c:192 memset+0x24/0x40 mm/kasan/common.c:108 memset include/linux/string.h:365 [inline] __alloc_skb+0x37b/0x5e0 net/core/skbuff.c:238 alloc_skb include/linux/skbuff.h:1049 [inline] alloc_skb_with_frags+0x93/0x590 net/core/skbuff.c:5664 sock_alloc_send_pskb+0x7ad/0x920 net/core/sock.c:2242 sock_alloc_send_skb+0x32/0x40 net/core/sock.c:2259 mld_newpack+0x1d7/0x7f0 net/ipv6/mcast.c:1609 add_grhead.isra.0+0x299/0x370 net/ipv6/mcast.c:1713 add_grec+0x7db/0x10b0 net/ipv6/mcast.c:1844 mld_send_cr net/ipv6/mcast.c:1970 [inline] mld_ifc_timer_expire+0x3d3/0x950 net/ipv6/mcast.c:2477 call_timer_fn+0x1ac/0x780 kernel/time/timer.c:1404 expire_timers kernel/time/timer.c:1449 [inline] __run_timers kernel/time/timer.c:1773 [inline] __run_timers kernel/time/timer.c:1740 [inline] run_timer_softirq+0x6c3/0x1790 kernel/time/timer.c:1786 __do_softirq+0x262/0x98c kernel/softirq.c:292 invoke_softirq kernel/softirq.c:373 [inline] irq_exit+0x19b/0x1e0 kernel/softirq.c:413 exiting_irq arch/x86/include/asm/apic.h:536 [inline] smp_apic_timer_interrupt+0x1a3/0x610 arch/x86/kernel/apic/apic.c:1137 apic_timer_interrupt+0xf/0x20 arch/x86/entry/entry_64.S:829 RIP: 0010:native_safe_halt+0xe/0x10 arch/x86/include/asm/irqflags.h:61 Code: 98 6b ea f9 eb 8a cc cc cc cc cc cc e9 07 00 00 00 0f 00 2d 44 1c 60 00 f4 c3 66 90 e9 07 00 00 00 0f 00 2d 34 1c 60 00 fb f4 cc 55 48 89 e5 41 57 41 56 41 55 41 54 53 e8 4e 5d 9a f9 e8 79 RSP: 0018:ffffffff89807ce8 EFLAGS: 00000286 ORIG_RAX: ffffffffffffff13 RAX: 1ffffffff13266ae RBX: ffffffff8987a1c0 RCX: 0000000000000000 RDX: dffffc0000000000 RSI: 0000000000000006 RDI: ffffffff8987aa54 RBP: ffffffff89807d18 R08: ffffffff8987a1c0 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: dffffc0000000000 R13: ffffffff8a799980 R14: 0000000000000000 R15: 0000000000000000 arch_cpu_idle+0xa/0x10 arch/x86/kernel/process.c:690 default_idle_call+0x84/0xb0 kernel/sched/idle.c:94 cpuidle_idle_call kernel/sched/idle.c:154 [inline] do_idle+0x3c8/0x6e0 kernel/sched/idle.c:269 cpu_startup_entry+0x1b/0x20 kernel/sched/idle.c:361 rest_init+0x23b/0x371 init/main.c:451 arch_call_rest_init+0xe/0x1b start_kernel+0x904/0x943 init/main.c:784 x86_64_start_reservations+0x29/0x2b arch/x86/kernel/head64.c:490 x86_64_start_kernel+0x77/0x7b arch/x86/kernel/head64.c:471 secondary_startup_64+0xa4/0xb0 arch/x86/kernel/head_64.S:242 The buggy address belongs to the page: page:ffffea00067c82c0 refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 raw: 057ffe0000000000 ffffea00067c82c8 ffffea00067c82c8 0000000000000000 raw: 0000000000000000 0000000000000000 00000000ffffffff 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff88819f20b880: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ffff88819f20b900: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff >ffff88819f20b980: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ^ ffff88819f20ba00: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ffff88819f20ba80: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff Fixes: 61e84623ace3 ("net: centralize net_device min/max MTU checking") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/netdevice.h | 1 + net/core/dev.c | 32 ++++++++++++++++++++------------ net/core/rtnetlink.c | 13 +++++++++++-- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8818291815bc..31fc54757bf2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3313,6 +3313,7 @@ int dev_set_alias(struct net_device *, const char *, size_t); int dev_change_net_namespace(struct net_device *, struct net *, const char *); int __dev_set_mtu(struct net_device *, int); int dev_set_mtu(struct net_device *, int); +int dev_validate_mtu(struct net_device *dev, int mtu); void dev_set_group(struct net_device *, int); int dev_set_mac_address(struct net_device *, struct sockaddr *); int dev_change_carrier(struct net_device *, bool new_carrier); diff --git a/net/core/dev.c b/net/core/dev.c index 737211f1b29c..36d926d2d5f0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6896,18 +6896,9 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) if (new_mtu == dev->mtu) return 0; - /* MTU must be positive, and in range */ - if (new_mtu < 0 || new_mtu < dev->min_mtu) { - net_err_ratelimited("%s: Invalid MTU %d requested, hw min %d\n", - dev->name, new_mtu, dev->min_mtu); - return -EINVAL; - } - - if (dev->max_mtu > 0 && new_mtu > dev->max_mtu) { - net_err_ratelimited("%s: Invalid MTU %d requested, hw max %d\n", - dev->name, new_mtu, dev->max_mtu); - return -EINVAL; - } + err = dev_validate_mtu(dev, new_mtu); + if (err) + return err; if (!netif_device_present(dev)) return -ENODEV; @@ -7769,6 +7760,23 @@ int init_dummy_netdev(struct net_device *dev) EXPORT_SYMBOL_GPL(init_dummy_netdev); +int dev_validate_mtu(struct net_device *dev, int new_mtu) +{ + /* MTU must be positive, and in range */ + if (new_mtu < 0 || new_mtu < dev->min_mtu) { + net_err_ratelimited("%s: Invalid MTU %d requested, hw min %d\n", + dev->name, new_mtu, dev->min_mtu); + return -EINVAL; + } + + if (dev->max_mtu > 0 && new_mtu > dev->max_mtu) { + net_err_ratelimited("%s: Invalid MTU %d requested, hw max %d\n", + dev->name, new_mtu, dev->max_mtu); + return -EINVAL; + } + return 0; +} + /** * register_netdev - register a network device * @dev: device to register diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index b598e9909fec..7c479c1ffd77 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2466,8 +2466,17 @@ struct net_device *rtnl_create_link(struct net *net, dev->rtnl_link_ops = ops; dev->rtnl_link_state = RTNL_LINK_INITIALIZING; - if (tb[IFLA_MTU]) - dev->mtu = nla_get_u32(tb[IFLA_MTU]); + if (tb[IFLA_MTU]) { + u32 mtu = nla_get_u32(tb[IFLA_MTU]); + int err; + + err = dev_validate_mtu(dev, mtu); + if (err) { + free_netdev(dev); + return ERR_PTR(err); + } + dev->mtu = mtu; + } if (tb[IFLA_ADDRESS]) { memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]), nla_len(tb[IFLA_ADDRESS])); -- GitLab From 6090ac18fcc58ed264ffdd00f6fdd6042475b6a4 Mon Sep 17 00:00:00 2001 From: Luuk Paulussen Date: Fri, 6 Dec 2019 12:16:59 +1300 Subject: [PATCH 0661/1055] hwmon: (adt7475) Make volt2reg return same reg as reg2volt input commit cf3ca1877574a306c0207cbf7fdf25419d9229df upstream. reg2volt returns the voltage that matches a given register value. Converting this back the other way with volt2reg didn't return the same register value because it used truncation instead of rounding. This meant that values read from sysfs could not be written back to sysfs to set back the same register value. With this change, volt2reg will return the same value for every voltage previously returned by reg2volt (for the set of possible input values) Signed-off-by: Luuk Paulussen Link: https://lore.kernel.org/r/20191205231659.1301-1-luuk.paulussen@alliedtelesis.co.nz cc: stable@vger.kernel.org Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/adt7475.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 37db2eb66ed7..d7d1f2467100 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -297,9 +297,10 @@ static inline u16 volt2reg(int channel, long volt, u8 bypass_attn) long reg; if (bypass_attn & (1 << channel)) - reg = (volt * 1024) / 2250; + reg = DIV_ROUND_CLOSEST(volt * 1024, 2250); else - reg = (volt * r[1] * 1024) / ((r[0] + r[1]) * 2250); + reg = DIV_ROUND_CLOSEST(volt * r[1] * 1024, + (r[0] + r[1]) * 2250); return clamp_val(reg, 0, 1023) & (0xff << 2); } -- GitLab From 4c7b99b4c03b546c4ea2e7562ee083e5f3a2c0e6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 5 Dec 2017 09:36:14 +0100 Subject: [PATCH 0662/1055] hwmon: Deal with errors from the thermal subsystem commit 47c332deb8e89f6c59b0bb2615945c6e7fad1a60 upstream. If the thermal subsystem returne -EPROBE_DEFER or any other error when hwmon calls devm_thermal_zone_of_sensor_register(), this is silently ignored. I ran into this with an incorrectly defined thermal zone, making it non-existing and thus this call failed with -EPROBE_DEFER assuming it would appear later. The sensor was still added which is incorrect: sensors must strictly be added after the thermal zones, so deferred probe must be respected. Fixes: d560168b5d0f ("hwmon: (core) New hwmon registration API") Signed-off-by: Linus Walleij Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/hwmon.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 7b53065e9882..b7f9e2adc2a2 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -143,6 +143,7 @@ static int hwmon_thermal_add_sensor(struct device *dev, struct hwmon_device *hwdev, int index) { struct hwmon_thermal_data *tdata; + struct thermal_zone_device *tzd; tdata = devm_kzalloc(dev, sizeof(*tdata), GFP_KERNEL); if (!tdata) @@ -151,8 +152,14 @@ static int hwmon_thermal_add_sensor(struct device *dev, tdata->hwdev = hwdev; tdata->index = index; - devm_thermal_zone_of_sensor_register(&hwdev->dev, index, tdata, - &hwmon_thermal_ops); + tzd = devm_thermal_zone_of_sensor_register(&hwdev->dev, index, tdata, + &hwmon_thermal_ops); + /* + * If CONFIG_THERMAL_OF is disabled, this returns -ENODEV, + * so ignore that error but forward any other error. + */ + if (IS_ERR(tzd) && (PTR_ERR(tzd) != -ENODEV)) + return PTR_ERR(tzd); return 0; } @@ -621,14 +628,20 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, if (!chip->ops->is_visible(drvdata, hwmon_temp, hwmon_temp_input, j)) continue; - if (info[i]->config[j] & HWMON_T_INPUT) - hwmon_thermal_add_sensor(dev, hwdev, j); + if (info[i]->config[j] & HWMON_T_INPUT) { + err = hwmon_thermal_add_sensor(dev, + hwdev, j); + if (err) + goto free_device; + } } } } return hdev; +free_device: + device_unregister(hdev); free_hwmon: kfree(hwdev); ida_remove: -- GitLab From ffea8daac4c58e21e0196e72a84b53e3fbc363f7 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 24 Oct 2018 22:37:13 +0300 Subject: [PATCH 0663/1055] hwmon: (core) Fix double-free in __hwmon_device_register() commit 74e3512731bd5c9673176425a76a7cc5efa8ddb6 upstream. Fix double-free that happens when thermal zone setup fails, see KASAN log below. ================================================================== BUG: KASAN: double-free or invalid-free in __hwmon_device_register+0x5dc/0xa7c CPU: 0 PID: 132 Comm: kworker/0:2 Tainted: G B 4.19.0-rc8-next-20181016-00042-gb52cd80401e9-dirty #41 Hardware name: NVIDIA Tegra SoC (Flattened Device Tree) Workqueue: events deferred_probe_work_func Backtrace: [] (dump_backtrace) from [] (show_stack+0x20/0x24) [] (show_stack) from [] (dump_stack+0x9c/0xb0) [] (dump_stack) from [] (print_address_description+0x68/0x250) [] (print_address_description) from [] (kasan_report_invalid_free+0x68/0x88) [] (kasan_report_invalid_free) from [] (__kasan_slab_free+0x1f4/0x200) [] (__kasan_slab_free) from [] (kasan_slab_free+0x14/0x18) [] (kasan_slab_free) from [] (kfree+0x90/0x294) [] (kfree) from [] (__hwmon_device_register+0x5dc/0xa7c) [] (__hwmon_device_register) from [] (hwmon_device_register_with_info+0xa0/0xa8) [] (hwmon_device_register_with_info) from [] (devm_hwmon_device_register_with_info+0x74/0xb4) [] (devm_hwmon_device_register_with_info) from [] (lm90_probe+0x414/0x578) [] (lm90_probe) from [] (i2c_device_probe+0x35c/0x384) [] (i2c_device_probe) from [] (really_probe+0x290/0x3e4) [] (really_probe) from [] (driver_probe_device+0x80/0x1c4) [] (driver_probe_device) from [] (__device_attach_driver+0x104/0x11c) [] (__device_attach_driver) from [] (bus_for_each_drv+0xa4/0xc8) [] (bus_for_each_drv) from [] (__device_attach+0xf0/0x15c) [] (__device_attach) from [] (device_initial_probe+0x1c/0x20) [] (device_initial_probe) from [] (bus_probe_device+0xdc/0xec) [] (bus_probe_device) from [] (deferred_probe_work_func+0xa8/0xd4) [] (deferred_probe_work_func) from [] (process_one_work+0x3dc/0x96c) [] (process_one_work) from [] (worker_thread+0x4ec/0x8bc) [] (worker_thread) from [] (kthread+0x230/0x240) [] (kthread) from [] (ret_from_fork+0x14/0x38) Exception stack(0xcf743fb0 to 0xcf743ff8) 3fa0: 00000000 00000000 00000000 00000000 3fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 3fe0: 00000000 00000000 00000000 00000000 00000013 00000000 Allocated by task 132: kasan_kmalloc.part.1+0x58/0xf4 kasan_kmalloc+0x90/0xa4 kmem_cache_alloc_trace+0x90/0x2a0 __hwmon_device_register+0xbc/0xa7c hwmon_device_register_with_info+0xa0/0xa8 devm_hwmon_device_register_with_info+0x74/0xb4 lm90_probe+0x414/0x578 i2c_device_probe+0x35c/0x384 really_probe+0x290/0x3e4 driver_probe_device+0x80/0x1c4 __device_attach_driver+0x104/0x11c bus_for_each_drv+0xa4/0xc8 __device_attach+0xf0/0x15c device_initial_probe+0x1c/0x20 bus_probe_device+0xdc/0xec deferred_probe_work_func+0xa8/0xd4 process_one_work+0x3dc/0x96c worker_thread+0x4ec/0x8bc kthread+0x230/0x240 ret_from_fork+0x14/0x38 (null) Freed by task 132: __kasan_slab_free+0x12c/0x200 kasan_slab_free+0x14/0x18 kfree+0x90/0x294 hwmon_dev_release+0x1c/0x20 device_release+0x4c/0xe8 kobject_put+0xac/0x11c device_unregister+0x2c/0x30 __hwmon_device_register+0xa58/0xa7c hwmon_device_register_with_info+0xa0/0xa8 devm_hwmon_device_register_with_info+0x74/0xb4 lm90_probe+0x414/0x578 i2c_device_probe+0x35c/0x384 really_probe+0x290/0x3e4 driver_probe_device+0x80/0x1c4 __device_attach_driver+0x104/0x11c bus_for_each_drv+0xa4/0xc8 __device_attach+0xf0/0x15c device_initial_probe+0x1c/0x20 bus_probe_device+0xdc/0xec deferred_probe_work_func+0xa8/0xd4 process_one_work+0x3dc/0x96c worker_thread+0x4ec/0x8bc kthread+0x230/0x240 ret_from_fork+0x14/0x38 (null) Cc: # v4.15+ Fixes: 47c332deb8e8 ("hwmon: Deal with errors from the thermal subsystem") Signed-off-by: Dmitry Osipenko Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/hwmon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index b7f9e2adc2a2..6b2c72f4a834 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -631,8 +631,10 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, if (info[i]->config[j] & HWMON_T_INPUT) { err = hwmon_thermal_add_sensor(dev, hwdev, j); - if (err) - goto free_device; + if (err) { + device_unregister(hdev); + goto ida_remove; + } } } } @@ -640,8 +642,6 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, return hdev; -free_device: - device_unregister(hdev); free_hwmon: kfree(hwdev); ida_remove: -- GitLab From 0a36cb84e2f4250d92be7e92920128474e49850d Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 16 Jan 2020 10:44:17 -0800 Subject: [PATCH 0664/1055] hwmon: (core) Do not use device managed functions for memory allocations commit 3bf8bdcf3bada771eb12b57f2a30caee69e8ab8d upstream. The hwmon core uses device managed functions, tied to the hwmon parent device, for various internal memory allocations. This is problematic since hwmon device lifetime does not necessarily match its parent's device lifetime. If there is a mismatch, memory leaks will accumulate until the parent device is released. Fix the problem by managing all memory allocations internally. The only exception is memory allocation for thermal device registration, which can be tied to the hwmon device, along with thermal device registration itself. Fixes: d560168b5d0f ("hwmon: (core) New hwmon registration API") Cc: stable@vger.kernel.org # v4.14.x: 47c332deb8e8: hwmon: Deal with errors from the thermal subsystem Cc: stable@vger.kernel.org # v4.14.x: 74e3512731bd: hwmon: (core) Fix double-free in __hwmon_device_register() Cc: stable@vger.kernel.org # v4.9.x: 3a412d5e4a1c: hwmon: (core) Simplify sysfs attribute name allocation Cc: stable@vger.kernel.org # v4.9.x: 47c332deb8e8: hwmon: Deal with errors from the thermal subsystem Cc: stable@vger.kernel.org # v4.9.x: 74e3512731bd: hwmon: (core) Fix double-free in __hwmon_device_register() Cc: stable@vger.kernel.org # v4.9+ Cc: Martin K. Petersen Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/hwmon.c | 68 ++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 6b2c72f4a834..652973d83a07 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -51,6 +51,7 @@ struct hwmon_device_attribute { #define to_hwmon_attr(d) \ container_of(d, struct hwmon_device_attribute, dev_attr) +#define to_dev_attr(a) container_of(a, struct device_attribute, attr) /* * Thermal zone information @@ -58,7 +59,7 @@ struct hwmon_device_attribute { * also provides the sensor index. */ struct hwmon_thermal_data { - struct hwmon_device *hwdev; /* Reference to hwmon device */ + struct device *dev; /* Reference to hwmon device */ int index; /* sensor index */ }; @@ -95,9 +96,27 @@ static const struct attribute_group *hwmon_dev_attr_groups[] = { NULL }; +static void hwmon_free_attrs(struct attribute **attrs) +{ + int i; + + for (i = 0; attrs[i]; i++) { + struct device_attribute *dattr = to_dev_attr(attrs[i]); + struct hwmon_device_attribute *hattr = to_hwmon_attr(dattr); + + kfree(hattr); + } + kfree(attrs); +} + static void hwmon_dev_release(struct device *dev) { - kfree(to_hwmon_device(dev)); + struct hwmon_device *hwdev = to_hwmon_device(dev); + + if (hwdev->group.attrs) + hwmon_free_attrs(hwdev->group.attrs); + kfree(hwdev->groups); + kfree(hwdev); } static struct class hwmon_class = { @@ -121,11 +140,11 @@ static DEFINE_IDA(hwmon_ida); static int hwmon_thermal_get_temp(void *data, int *temp) { struct hwmon_thermal_data *tdata = data; - struct hwmon_device *hwdev = tdata->hwdev; + struct hwmon_device *hwdev = to_hwmon_device(tdata->dev); int ret; long t; - ret = hwdev->chip->ops->read(&hwdev->dev, hwmon_temp, hwmon_temp_input, + ret = hwdev->chip->ops->read(tdata->dev, hwmon_temp, hwmon_temp_input, tdata->index, &t); if (ret < 0) return ret; @@ -139,8 +158,7 @@ static const struct thermal_zone_of_device_ops hwmon_thermal_ops = { .get_temp = hwmon_thermal_get_temp, }; -static int hwmon_thermal_add_sensor(struct device *dev, - struct hwmon_device *hwdev, int index) +static int hwmon_thermal_add_sensor(struct device *dev, int index) { struct hwmon_thermal_data *tdata; struct thermal_zone_device *tzd; @@ -149,10 +167,10 @@ static int hwmon_thermal_add_sensor(struct device *dev, if (!tdata) return -ENOMEM; - tdata->hwdev = hwdev; + tdata->dev = dev; tdata->index = index; - tzd = devm_thermal_zone_of_sensor_register(&hwdev->dev, index, tdata, + tzd = devm_thermal_zone_of_sensor_register(dev, index, tdata, &hwmon_thermal_ops); /* * If CONFIG_THERMAL_OF is disabled, this returns -ENODEV, @@ -164,8 +182,7 @@ static int hwmon_thermal_add_sensor(struct device *dev, return 0; } #else -static int hwmon_thermal_add_sensor(struct device *dev, - struct hwmon_device *hwdev, int index) +static int hwmon_thermal_add_sensor(struct device *dev, int index) { return 0; } @@ -242,8 +259,7 @@ static bool is_string_attr(enum hwmon_sensor_types type, u32 attr) (type == hwmon_fan && attr == hwmon_fan_label); } -static struct attribute *hwmon_genattr(struct device *dev, - const void *drvdata, +static struct attribute *hwmon_genattr(const void *drvdata, enum hwmon_sensor_types type, u32 attr, int index, @@ -271,7 +287,7 @@ static struct attribute *hwmon_genattr(struct device *dev, if ((mode & S_IWUGO) && !ops->write) return ERR_PTR(-EINVAL); - hattr = devm_kzalloc(dev, sizeof(*hattr), GFP_KERNEL); + hattr = kzalloc(sizeof(*hattr), GFP_KERNEL); if (!hattr) return ERR_PTR(-ENOMEM); @@ -474,8 +490,7 @@ static int hwmon_num_channel_attrs(const struct hwmon_channel_info *info) return n; } -static int hwmon_genattrs(struct device *dev, - const void *drvdata, +static int hwmon_genattrs(const void *drvdata, struct attribute **attrs, const struct hwmon_ops *ops, const struct hwmon_channel_info *info) @@ -501,7 +516,7 @@ static int hwmon_genattrs(struct device *dev, attr_mask &= ~BIT(attr); if (attr >= template_size) return -EINVAL; - a = hwmon_genattr(dev, drvdata, info->type, attr, i, + a = hwmon_genattr(drvdata, info->type, attr, i, templates[attr], ops); if (IS_ERR(a)) { if (PTR_ERR(a) != -ENOENT) @@ -515,8 +530,7 @@ static int hwmon_genattrs(struct device *dev, } static struct attribute ** -__hwmon_create_attrs(struct device *dev, const void *drvdata, - const struct hwmon_chip_info *chip) +__hwmon_create_attrs(const void *drvdata, const struct hwmon_chip_info *chip) { int ret, i, aindex = 0, nattrs = 0; struct attribute **attrs; @@ -527,15 +541,17 @@ __hwmon_create_attrs(struct device *dev, const void *drvdata, if (nattrs == 0) return ERR_PTR(-EINVAL); - attrs = devm_kcalloc(dev, nattrs + 1, sizeof(*attrs), GFP_KERNEL); + attrs = kcalloc(nattrs + 1, sizeof(*attrs), GFP_KERNEL); if (!attrs) return ERR_PTR(-ENOMEM); for (i = 0; chip->info[i]; i++) { - ret = hwmon_genattrs(dev, drvdata, &attrs[aindex], chip->ops, + ret = hwmon_genattrs(drvdata, &attrs[aindex], chip->ops, chip->info[i]); - if (ret < 0) + if (ret < 0) { + hwmon_free_attrs(attrs); return ERR_PTR(ret); + } aindex += ret; } @@ -577,14 +593,13 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, for (i = 0; groups[i]; i++) ngroups++; - hwdev->groups = devm_kcalloc(dev, ngroups, sizeof(*groups), - GFP_KERNEL); + hwdev->groups = kcalloc(ngroups, sizeof(*groups), GFP_KERNEL); if (!hwdev->groups) { err = -ENOMEM; goto free_hwmon; } - attrs = __hwmon_create_attrs(dev, drvdata, chip); + attrs = __hwmon_create_attrs(drvdata, chip); if (IS_ERR(attrs)) { err = PTR_ERR(attrs); goto free_hwmon; @@ -629,8 +644,7 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, hwmon_temp_input, j)) continue; if (info[i]->config[j] & HWMON_T_INPUT) { - err = hwmon_thermal_add_sensor(dev, - hwdev, j); + err = hwmon_thermal_add_sensor(hdev, j); if (err) { device_unregister(hdev); goto ida_remove; @@ -643,7 +657,7 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, return hdev; free_hwmon: - kfree(hwdev); + hwmon_dev_release(hdev); ida_remove: ida_simple_remove(&hwmon_ida, id); return ERR_PTR(err); -- GitLab From 68c538b4a1cb84906fbcbffc62d4d6064ec8c9f8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Jan 2020 10:38:57 -0800 Subject: [PATCH 0665/1055] Input: keyspan-remote - fix control-message timeouts commit ba9a103f40fc4a3ec7558ec9b0b97d4f92034249 upstream. The driver was issuing synchronous uninterruptible control requests without using a timeout. This could lead to the driver hanging on probe due to a malfunctioning (or malicious) device until the device is physically disconnected. While sleeping in probe the driver prevents other devices connected to the same hub from being added to (or removed from) the bus. The USB upper limit of five seconds per request should be more than enough. Fixes: 99f83c9c9ac9 ("[PATCH] USB: add driver for Keyspan Digital Remote") Signed-off-by: Johan Hovold Reviewed-by: Greg Kroah-Hartman Cc: stable # 2.6.13 Link: https://lore.kernel.org/r/20200113171715.30621-1-johan@kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/misc/keyspan_remote.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c index 77c47d6325fe..a9ee813eef10 100644 --- a/drivers/input/misc/keyspan_remote.c +++ b/drivers/input/misc/keyspan_remote.c @@ -344,7 +344,8 @@ static int keyspan_setup(struct usb_device* dev) int retval = 0; retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0); + 0x11, 0x40, 0x5601, 0x0, NULL, 0, + USB_CTRL_SET_TIMEOUT); if (retval) { dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n", __func__, retval); @@ -352,7 +353,8 @@ static int keyspan_setup(struct usb_device* dev) } retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x44, 0x40, 0x0, 0x0, NULL, 0, 0); + 0x44, 0x40, 0x0, 0x0, NULL, 0, + USB_CTRL_SET_TIMEOUT); if (retval) { dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n", __func__, retval); @@ -360,7 +362,8 @@ static int keyspan_setup(struct usb_device* dev) } retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x22, 0x40, 0x0, 0x0, NULL, 0, 0); + 0x22, 0x40, 0x0, 0x0, NULL, 0, + USB_CTRL_SET_TIMEOUT); if (retval) { dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n", __func__, retval); -- GitLab From ac390c982915393d87a1e52229865c17ae2458e2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 16 Jan 2020 20:12:27 -0800 Subject: [PATCH 0666/1055] Revert "Input: synaptics-rmi4 - don't increment rmiaddr for SMBus transfers" commit 8ff771f8c8d55d95f102cf88a970e541a8bd6bcf upstream. This reverts commit a284e11c371e446371675668d8c8120a27227339. This causes problems (drifting cursor) with at least the F11 function that reads more than 32 bytes. The real issue is in the F54 driver, and so this should be fixed there, and not in rmi_smbus.c. So first revert this bad commit, then fix the real problem in F54 in another patch. Signed-off-by: Hans Verkuil Reported-by: Timo Kaufmann Fixes: a284e11c371e ("Input: synaptics-rmi4 - don't increment rmiaddr for SMBus transfers") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20200115124819.3191024-2-hverkuil-cisco@xs4all.nl Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/rmi4/rmi_smbus.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c index 4b2466cf2fb1..b6ccf39c6a7b 100644 --- a/drivers/input/rmi4/rmi_smbus.c +++ b/drivers/input/rmi4/rmi_smbus.c @@ -166,6 +166,7 @@ static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr, /* prepare to write next block of bytes */ cur_len -= SMB_MAX_COUNT; databuff += SMB_MAX_COUNT; + rmiaddr += SMB_MAX_COUNT; } exit: mutex_unlock(&rmi_smb->page_mutex); @@ -217,6 +218,7 @@ static int rmi_smb_read_block(struct rmi_transport_dev *xport, u16 rmiaddr, /* prepare to read next block of bytes */ cur_len -= SMB_MAX_COUNT; databuff += SMB_MAX_COUNT; + rmiaddr += SMB_MAX_COUNT; } retval = 0; -- GitLab From bb4768b0583e717aae6c19ab7d6dd3244d7ccc2d Mon Sep 17 00:00:00 2001 From: Alex Sverdlin Date: Wed, 8 Jan 2020 15:57:47 +0100 Subject: [PATCH 0667/1055] ARM: 8950/1: ftrace/recordmcount: filter relocation types commit 927d780ee371d7e121cea4fc7812f6ef2cea461c upstream. Scenario 1, ARMv7 ================= If code in arch/arm/kernel/ftrace.c would operate on mcount() pointer the following may be generated: 00000230 : 230: b5f8 push {r3, r4, r5, r6, r7, lr} 232: b500 push {lr} 234: f7ff fffe bl 0 <__gnu_mcount_nc> 234: R_ARM_THM_CALL __gnu_mcount_nc 238: f240 0600 movw r6, #0 238: R_ARM_THM_MOVW_ABS_NC __gnu_mcount_nc 23c: f8d0 1180 ldr.w r1, [r0, #384] ; 0x180 FTRACE currently is not able to deal with it: WARNING: CPU: 0 PID: 0 at .../kernel/trace/ftrace.c:1979 ftrace_bug+0x1ad/0x230() ... CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.4.116-... #1 ... [] (unwind_backtrace) from [] (show_stack+0x11/0x14) [] (show_stack) from [] (dump_stack+0x81/0xa8) [] (dump_stack) from [] (warn_slowpath_common+0x69/0x90) [] (warn_slowpath_common) from [] (warn_slowpath_null+0x17/0x1c) [] (warn_slowpath_null) from [] (ftrace_bug+0x1ad/0x230) [] (ftrace_bug) from [] (ftrace_process_locs+0x27d/0x444) [] (ftrace_process_locs) from [] (ftrace_init+0x91/0xe8) [] (ftrace_init) from [] (start_kernel+0x34b/0x358) [] (start_kernel) from [<00308095>] (0x308095) ---[ end trace cb88537fdc8fa200 ]--- ftrace failed to modify [] prealloc_fixed_plts+0x8/0x60 actual: 44:f2:e1:36 ftrace record flags: 0 (0) expected tramp: c03143e9 Scenario 2, ARMv4T ================== ftrace: allocating 14435 entries in 43 pages ------------[ cut here ]------------ WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:2029 ftrace_bug+0x204/0x310 CPU: 0 PID: 0 Comm: swapper Not tainted 4.19.5 #1 Hardware name: Cirrus Logic EDB9302 Evaluation Board [] (unwind_backtrace) from [] (show_stack+0x20/0x2c) [] (show_stack) from [] (dump_stack+0x20/0x30) [] (dump_stack) from [] (__warn+0xdc/0x104) [] (__warn) from [] (warn_slowpath_null+0x4c/0x5c) [] (warn_slowpath_null) from [] (ftrace_bug+0x204/0x310) [] (ftrace_bug) from [] (ftrace_init+0x3b4/0x4d4) [] (ftrace_init) from [] (start_kernel+0x20c/0x410) [] (start_kernel) from [<00000000>] ( (null)) ---[ end trace 0506a2f5dae6b341 ]--- ftrace failed to modify [] perf_trace_sys_exit+0x5c/0xe8 actual: 1e:ff:2f:e1 Initializing ftrace call sites ftrace record flags: 0 (0) expected tramp: c000fb24 The analysis for this problem has been already performed previously, refer to the link below. Fix the above problems by allowing only selected reloc types in __mcount_loc. The list itself comes from the legacy recordmcount.pl script. Link: https://lore.kernel.org/lkml/56961010.6000806@pengutronix.de/ Cc: stable@vger.kernel.org Fixes: ed60453fa8f8 ("ARM: 6511/1: ftrace: add ARM support for C version of recordmcount") Signed-off-by: Alexander Sverdlin Acked-by: Steven Rostedt (VMware) Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- scripts/recordmcount.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 16e086dcc567..a4888e955466 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -53,6 +53,10 @@ #define R_AARCH64_ABS64 257 #endif +#define R_ARM_PC24 1 +#define R_ARM_THM_CALL 10 +#define R_ARM_CALL 28 + static int fd_map; /* File descriptor for file being modified. */ static int mmap_failed; /* Boolean flag. */ static char gpfx; /* prefix for global symbol name (sometimes '_') */ @@ -428,6 +432,18 @@ is_mcounted_section_name(char const *const txtname) #define RECORD_MCOUNT_64 #include "recordmcount.h" +static int arm_is_fake_mcount(Elf32_Rel const *rp) +{ + switch (ELF32_R_TYPE(w(rp->r_info))) { + case R_ARM_THM_CALL: + case R_ARM_CALL: + case R_ARM_PC24: + return 0; + } + + return 1; +} + /* 64-bit EM_MIPS has weird ELF64_Rela.r_info. * http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf * We interpret Table 29 Relocation Operation (Elf64_Rel, Elf64_Rela) [p.40] @@ -529,6 +545,7 @@ do_file(char const *const fname) altmcount = "__gnu_mcount_nc"; make_nop = make_nop_arm; rel_type_nop = R_ARM_NONE; + is_fake_mcount32 = arm_is_fake_mcount; break; case EM_AARCH64: reltype = R_AARCH64_ABS64; -- GitLab From dd5d5e77f725b32a93eb4d760736f4a47a680c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Tue, 7 Jan 2020 10:47:34 +0100 Subject: [PATCH 0668/1055] mmc: tegra: fix SDR50 tuning override MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f571389c0b015e76f91c697c4c1700aba860d34f upstream. Commit 7ad2ed1dfcbe inadvertently mixed up a quirk flag's name and broke SDR50 tuning override. Use correct NVQUIRK_ name. Fixes: 7ad2ed1dfcbe ("mmc: tegra: enable UHS-I modes") Cc: Acked-by: Adrian Hunter Reviewed-by: Thierry Reding Tested-by: Thierry Reding Signed-off-by: Michał Mirosław Link: https://lore.kernel.org/r/9aff1d859935e59edd81e4939e40d6c55e0b55f6.1578390388.git.mirq-linux@rere.qmqm.pl Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index ce3f344d2b66..d2b0a62bfce1 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -177,7 +177,7 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50; if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104) misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104; - if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50) + if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50) clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE; } -- GitLab From da6b467e112957eea049c400eff84e3cfb89008d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Wed, 15 Jan 2020 10:54:35 +0100 Subject: [PATCH 0669/1055] mmc: sdhci: fix minimum clock rate for v3 controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 2a187d03352086e300daa2044051db00044cd171 upstream. For SDHCIv3+ with programmable clock mode, minimal clock frequency is still base clock / max(divider). Minimal programmable clock frequency is always greater than minimal divided clock frequency. Without this patch, SDHCI uses out-of-spec initial frequency when multiplier is big enough: mmc1: mmc_rescan_try_freq: trying to init card at 468750 Hz [for 480 MHz source clock divided by 1024] The code in sdhci_calc_clk() already chooses a correct SDCLK clock mode. Fixes: c3ed3877625f ("mmc: sdhci: add support for programmable clock mode") Cc: # 4f6aa3264af4: mmc: tegra: Only advertise UHS modes if IO regulator is present Cc: Signed-off-by: Michał Mirosław Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/ffb489519a446caffe7a0a05c4b9372bd52397bb.1579082031.git.mirq-linux@rere.qmqm.pl Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 645775dd4edb..4f1c884c0b50 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3592,11 +3592,13 @@ int sdhci_setup_host(struct sdhci_host *host) if (host->ops->get_min_clock) mmc->f_min = host->ops->get_min_clock(host); else if (host->version >= SDHCI_SPEC_300) { - if (host->clk_mul) { - mmc->f_min = (host->max_clk * host->clk_mul) / 1024; + if (host->clk_mul) max_clk = host->max_clk * host->clk_mul; - } else - mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300; + /* + * Divided Clock Mode minimum clock rate is always less than + * Programmable Clock Mode minimum clock rate. + */ + mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300; } else mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; -- GitLab From c57b0f88fce8b4f697f323cfb3b7acc195b7560f Mon Sep 17 00:00:00 2001 From: Jeremy Linton Date: Fri, 25 Jan 2019 12:07:00 -0600 Subject: [PATCH 0670/1055] Documentation: Document arm64 kpti control commit de19055564c8f8f9d366f8db3395836da0b2176c upstream. For a while Arm64 has been capable of force enabling or disabling the kpti mitigations. Lets make sure the documentation reflects that. Signed-off-by: Jeremy Linton Reviewed-by: Andre Przywara Signed-off-by: Jonathan Corbet Signed-off-by: Greg Kroah-Hartman --- Documentation/admin-guide/kernel-parameters.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 933465eff40e..7e0a4be3503d 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1845,6 +1845,12 @@ Built with CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y, the default is off. + kpti= [ARM64] Control page table isolation of user + and kernel address spaces. + Default: enabled on cores which need mitigation. + 0: force disabled + 1: force enabled + kvm.ignore_msrs=[KVM] Ignore guest accesses to unhandled MSRs. Default is 0 (don't ignore, but inject #GP) -- GitLab From 1130377fb5a8095a13c23018edadbabbec7f7fef Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Fri, 17 Jan 2020 13:40:36 -0800 Subject: [PATCH 0671/1055] Input: pm8xxx-vib - fix handling of separate enable register commit 996d5d5f89a558a3608a46e73ccd1b99f1b1d058 upstream. Setting the vibrator enable_mask is not implemented correctly: For regmap_update_bits(map, reg, mask, val) we give in either regs->enable_mask or 0 (= no-op) as mask and "val" as value. But "val" actually refers to the vibrator voltage control register, which has nothing to do with the enable_mask. So we usually end up doing nothing when we really wanted to enable the vibrator. We want to set or clear the enable_mask (to enable/disable the vibrator). Therefore, change the call to always modify the enable_mask and set the bits only if we want to enable the vibrator. Fixes: d4c7c5c96c92 ("Input: pm8xxx-vib - handle separate enable register") Signed-off-by: Stephan Gerhold Link: https://lore.kernel.org/r/20200114183442.45720-1-stephan@gerhold.net Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/misc/pm8xxx-vibrator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index 7dd1c1fbe42a..27b3db154a33 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -98,7 +98,7 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) if (regs->enable_mask) rc = regmap_update_bits(vib->regmap, regs->enable_addr, - on ? regs->enable_mask : 0, val); + regs->enable_mask, on ? ~0 : 0); return rc; } -- GitLab From 0411b242274fabe83298c0242916216b40b2350f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 10 Jan 2020 12:01:27 -0800 Subject: [PATCH 0672/1055] Input: sur40 - fix interface sanity checks commit 6b32391ed675827f8425a414abbc6fbd54ea54fe upstream. Make sure to use the current alternate setting when verifying the interface descriptors to avoid binding to an invalid interface. This in turn could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on. Fixes: bdb5c57f209c ("Input: add sur40 driver for Samsung SUR40 (aka MS Surface 2.0/Pixelsense)") Signed-off-by: Johan Hovold Acked-by: Vladis Dronov Link: https://lore.kernel.org/r/20191210113737.4016-8-johan@kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/touchscreen/sur40.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index f16f8358c70a..98e03d0ca03c 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -537,7 +537,7 @@ static int sur40_probe(struct usb_interface *interface, int error; /* Check if we really have the right interface. */ - iface_desc = &interface->altsetting[0]; + iface_desc = interface->cur_altsetting; if (iface_desc->desc.bInterfaceClass != 0xFF) return -ENODEV; -- GitLab From e11d045f564dec4d26e1db28c7e121ae3b69b29e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 10 Jan 2020 12:00:18 -0800 Subject: [PATCH 0673/1055] Input: gtco - fix endpoint sanity check commit a8eeb74df5a6bdb214b2b581b14782c5f5a0cf83 upstream. The driver was checking the number of endpoints of the first alternate setting instead of the current one, something which could lead to the driver binding to an invalid interface. This in turn could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on. Fixes: 162f98dea487 ("Input: gtco - fix crash on detecting device without endpoints") Signed-off-by: Johan Hovold Acked-by: Vladis Dronov Link: https://lore.kernel.org/r/20191210113737.4016-5-johan@kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/tablet/gtco.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index 35031228a6d0..799c94dda651 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -875,18 +875,14 @@ static int gtco_probe(struct usb_interface *usbinterface, } /* Sanity check that a device has an endpoint */ - if (usbinterface->altsetting[0].desc.bNumEndpoints < 1) { + if (usbinterface->cur_altsetting->desc.bNumEndpoints < 1) { dev_err(&usbinterface->dev, "Invalid number of endpoints\n"); error = -EINVAL; goto err_free_urb; } - /* - * The endpoint is always altsetting 0, we know this since we know - * this device only has one interrupt endpoint - */ - endpoint = &usbinterface->altsetting[0].endpoint[0].desc; + endpoint = &usbinterface->cur_altsetting->endpoint[0].desc; /* Some debug */ dev_dbg(&usbinterface->dev, "gtco # interfaces: %d\n", usbinterface->num_altsetting); @@ -973,7 +969,7 @@ static int gtco_probe(struct usb_interface *usbinterface, input_dev->dev.parent = &usbinterface->dev; /* Setup the URB, it will be posted later on open of input device */ - endpoint = &usbinterface->altsetting[0].endpoint[0].desc; + endpoint = &usbinterface->cur_altsetting->endpoint[0].desc; usb_fill_int_urb(gtco->urbinfo, udev, -- GitLab From c2764d4449e8634c0d020dcf68aabae2f5ffd85d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 10 Jan 2020 11:59:32 -0800 Subject: [PATCH 0674/1055] Input: aiptek - fix endpoint sanity check commit 3111491fca4f01764e0c158c5e0f7ced808eef51 upstream. The driver was checking the number of endpoints of the first alternate setting instead of the current one, something which could lead to the driver binding to an invalid interface. This in turn could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on. Fixes: 8e20cf2bce12 ("Input: aiptek - fix crash on detecting device without endpoints") Signed-off-by: Johan Hovold Acked-by: Vladis Dronov Link: https://lore.kernel.org/r/20191210113737.4016-3-johan@kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/tablet/aiptek.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 0b55e1f375b3..fbe2df91aad3 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -1822,14 +1822,14 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0); /* Verify that a device really has an endpoint */ - if (intf->altsetting[0].desc.bNumEndpoints < 1) { + if (intf->cur_altsetting->desc.bNumEndpoints < 1) { dev_err(&intf->dev, "interface has %d endpoints, but must have minimum 1\n", - intf->altsetting[0].desc.bNumEndpoints); + intf->cur_altsetting->desc.bNumEndpoints); err = -EINVAL; goto fail3; } - endpoint = &intf->altsetting[0].endpoint[0].desc; + endpoint = &intf->cur_altsetting->endpoint[0].desc; /* Go set up our URB, which is called when the tablet receives * input. -- GitLab From f4c64034ef354509f80e7038924eda37c763af6d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 10 Jan 2020 11:55:47 -0800 Subject: [PATCH 0675/1055] Input: pegasus_notetaker - fix endpoint sanity check commit bcfcb7f9b480dd0be8f0df2df17340ca92a03b98 upstream. The driver was checking the number of endpoints of the first alternate setting instead of the current one, something which could be used by a malicious device (or USB descriptor fuzzer) to trigger a NULL-pointer dereference. Fixes: 1afca2b66aac ("Input: add Pegasus Notetaker tablet driver") Signed-off-by: Johan Hovold Acked-by: Martin Kepplinger Acked-by: Vladis Dronov Link: https://lore.kernel.org/r/20191210113737.4016-2-johan@kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/tablet/pegasus_notetaker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/tablet/pegasus_notetaker.c b/drivers/input/tablet/pegasus_notetaker.c index 47de5a81172f..2319144802c9 100644 --- a/drivers/input/tablet/pegasus_notetaker.c +++ b/drivers/input/tablet/pegasus_notetaker.c @@ -260,7 +260,7 @@ static int pegasus_probe(struct usb_interface *intf, return -ENODEV; /* Sanity check that the device has an endpoint */ - if (intf->altsetting[0].desc.bNumEndpoints < 1) { + if (intf->cur_altsetting->desc.bNumEndpoints < 1) { dev_err(&intf->dev, "Invalid number of endpoints\n"); return -EINVAL; } -- GitLab From 59b27a9f7ee3645df0c3b4c763c77eb0e607504c Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Fri, 10 Jan 2020 10:30:04 -0800 Subject: [PATCH 0676/1055] Input: sun4i-ts - add a check for devm_thermal_zone_of_sensor_register commit 97e24b095348a15ec08c476423c3b3b939186ad7 upstream. The driver misses a check for devm_thermal_zone_of_sensor_register(). Add a check to fix it. Fixes: e28d0c9cd381 ("input: convert sun4i-ts to use devm_thermal_zone_of_sensor_register") Signed-off-by: Chuhong Yuan Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/touchscreen/sun4i-ts.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index d2e14d9e5975..ab44eb0352d0 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -246,6 +246,7 @@ static int sun4i_ts_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct device *hwmon; + struct thermal_zone_device *thermal; int error; u32 reg; bool ts_attached; @@ -365,7 +366,10 @@ static int sun4i_ts_probe(struct platform_device *pdev) if (IS_ERR(hwmon)) return PTR_ERR(hwmon); - devm_thermal_zone_of_sensor_register(ts->dev, 0, ts, &sun4i_ts_tz_ops); + thermal = devm_thermal_zone_of_sensor_register(ts->dev, 0, ts, + &sun4i_ts_tz_ops); + if (IS_ERR(thermal)) + return PTR_ERR(thermal); writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC); -- GitLab From 788a56f8907560f9814b2894b9094a3272abd4a4 Mon Sep 17 00:00:00 2001 From: Gilles Buloz Date: Wed, 27 Nov 2019 18:09:34 +0100 Subject: [PATCH 0677/1055] hwmon: (nct7802) Fix voltage limits to wrong registers commit 7713e62c8623c54dac88d1fa724aa487a38c3efb upstream. in0 thresholds are written to the in2 thresholds registers in2 thresholds to in3 thresholds in3 thresholds to in4 thresholds in4 thresholds to in0 thresholds Signed-off-by: Gilles Buloz Link: https://lore.kernel.org/r/5de0f509.rc0oEvPOMjbfPW1w%gilles.buloz@kontron.com Fixes: 3434f3783580 ("hwmon: Driver for Nuvoton NCT7802Y") Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/nct7802.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index 38ffbdb0a85f..779ec8fdfae0 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -32,8 +32,8 @@ static const u8 REG_VOLTAGE[5] = { 0x09, 0x0a, 0x0c, 0x0d, 0x0e }; static const u8 REG_VOLTAGE_LIMIT_LSB[2][5] = { - { 0x40, 0x00, 0x42, 0x44, 0x46 }, - { 0x3f, 0x00, 0x41, 0x43, 0x45 }, + { 0x46, 0x00, 0x40, 0x42, 0x44 }, + { 0x45, 0x00, 0x3f, 0x41, 0x43 }, }; static const u8 REG_VOLTAGE_LIMIT_MSB[5] = { 0x48, 0x00, 0x47, 0x47, 0x48 }; -- GitLab From 1ff739768a3d524184306fb84f616bc9672db50d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 15 Jan 2020 20:47:37 -0800 Subject: [PATCH 0678/1055] scsi: RDMA/isert: Fix a recently introduced regression related to logout commit 04060db41178c7c244f2c7dcd913e7fd331de915 upstream. iscsit_close_connection() calls isert_wait_conn(). Due to commit e9d3009cb936 both functions call target_wait_for_sess_cmds() although that last function should be called only once. Fix this by removing the target_wait_for_sess_cmds() call from isert_wait_conn() and by only calling isert_wait_conn() after target_wait_for_sess_cmds(). Fixes: e9d3009cb936 ("scsi: target: iscsi: Wait for all commands to finish before freeing a session"). Link: https://lore.kernel.org/r/20200116044737.19507-1-bvanassche@acm.org Reported-by: Rahul Kundu Signed-off-by: Bart Van Assche Tested-by: Mike Marciniszyn Acked-by: Sagi Grimberg Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/isert/ib_isert.c | 12 ------------ drivers/target/iscsi/iscsi_target.c | 6 +++--- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index ee3f630c9217..9b5691f306a2 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -2582,17 +2582,6 @@ isert_wait4logout(struct isert_conn *isert_conn) } } -static void -isert_wait4cmds(struct iscsi_conn *conn) -{ - isert_info("iscsi_conn %p\n", conn); - - if (conn->sess) { - target_sess_cmd_list_set_waiting(conn->sess->se_sess); - target_wait_for_sess_cmds(conn->sess->se_sess); - } -} - /** * isert_put_unsol_pending_cmds() - Drop commands waiting for * unsolicitate dataout @@ -2640,7 +2629,6 @@ static void isert_wait_conn(struct iscsi_conn *conn) ib_drain_qp(isert_conn->qp); isert_put_unsol_pending_cmds(conn); - isert_wait4cmds(conn); isert_wait4logout(isert_conn); queue_work(isert_release_wq, &isert_conn->release_work); diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 21ce92ee1652..37d64acea5e1 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -4155,9 +4155,6 @@ int iscsit_close_connection( iscsit_stop_nopin_response_timer(conn); iscsit_stop_nopin_timer(conn); - if (conn->conn_transport->iscsit_wait_conn) - conn->conn_transport->iscsit_wait_conn(conn); - /* * During Connection recovery drop unacknowledged out of order * commands for this connection, and prepare the other commands @@ -4243,6 +4240,9 @@ int iscsit_close_connection( target_sess_cmd_list_set_waiting(sess->se_sess); target_wait_for_sess_cmds(sess->se_sess); + if (conn->conn_transport->iscsit_wait_conn) + conn->conn_transport->iscsit_wait_conn(conn); + ahash_request_free(conn->conn_tx_hash); if (conn->conn_rx_hash) { struct crypto_ahash *tfm; -- GitLab From 09efdaaca8c613bf7c23ec48dc014906b6b6d296 Mon Sep 17 00:00:00 2001 From: Changbin Du Date: Sun, 12 Jan 2020 11:42:31 +0800 Subject: [PATCH 0679/1055] tracing: xen: Ordered comparison of function pointers commit d0695e2351102affd8efae83989056bc4b275917 upstream. Just as commit 0566e40ce7 ("tracing: initcall: Ordered comparison of function pointers"), this patch fixes another remaining one in xen.h found by clang-9. In file included from arch/x86/xen/trace.c:21: In file included from ./include/trace/events/xen.h:475: In file included from ./include/trace/define_trace.h:102: In file included from ./include/trace/trace_events.h:473: ./include/trace/events/xen.h:69:7: warning: ordered comparison of function \ pointers ('xen_mc_callback_fn_t' (aka 'void (*)(void *)') and 'xen_mc_callback_fn_t') [-Wordered-compare-function-pointers] __field(xen_mc_callback_fn_t, fn) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ./include/trace/trace_events.h:421:29: note: expanded from macro '__field' ^ ./include/trace/trace_events.h:407:6: note: expanded from macro '__field_ext' is_signed_type(type), filter_type); \ ^ ./include/linux/trace_events.h:554:44: note: expanded from macro 'is_signed_type' ^ Fixes: c796f213a6934 ("xen/trace: add multicall tracing") Signed-off-by: Changbin Du Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- include/trace/events/xen.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/trace/events/xen.h b/include/trace/events/xen.h index 2ec9064a2bb7..e5150fc67e91 100644 --- a/include/trace/events/xen.h +++ b/include/trace/events/xen.h @@ -66,7 +66,11 @@ TRACE_EVENT(xen_mc_callback, TP_PROTO(xen_mc_callback_fn_t fn, void *data), TP_ARGS(fn, data), TP_STRUCT__entry( - __field(xen_mc_callback_fn_t, fn) + /* + * Use field_struct to avoid is_signed_type() + * comparison of a function pointer. + */ + __field_struct(xen_mc_callback_fn_t, fn) __field(void *, data) ), TP_fast_assign( -- GitLab From 778de9db9ec2036f0bd82572bbb7b35ec402089c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 26 Jan 2020 09:29:34 -0500 Subject: [PATCH 0680/1055] do_last(): fetch directory ->i_mode and ->i_uid before it's too late commit d0cb50185ae942b03c4327be322055d622dc79f6 upstream. may_create_in_sticky() call is done when we already have dropped the reference to dir. Fixes: 30aba6656f61e (namei: allow restricted O_CREAT of FIFOs and regular files) Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/namei.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index d1e467b7b9de..d648d6d2b635 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1023,7 +1023,8 @@ static int may_linkat(struct path *link) * may_create_in_sticky - Check whether an O_CREAT open in a sticky directory * should be allowed, or not, on files that already * exist. - * @dir: the sticky parent directory + * @dir_mode: mode bits of directory + * @dir_uid: owner of directory * @inode: the inode of the file to open * * Block an O_CREAT open of a FIFO (or a regular file) when: @@ -1039,18 +1040,18 @@ static int may_linkat(struct path *link) * * Returns 0 if the open is allowed, -ve on error. */ -static int may_create_in_sticky(struct dentry * const dir, +static int may_create_in_sticky(umode_t dir_mode, kuid_t dir_uid, struct inode * const inode) { if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) || (!sysctl_protected_regular && S_ISREG(inode->i_mode)) || - likely(!(dir->d_inode->i_mode & S_ISVTX)) || - uid_eq(inode->i_uid, dir->d_inode->i_uid) || + likely(!(dir_mode & S_ISVTX)) || + uid_eq(inode->i_uid, dir_uid) || uid_eq(current_fsuid(), inode->i_uid)) return 0; - if (likely(dir->d_inode->i_mode & 0002) || - (dir->d_inode->i_mode & 0020 && + if (likely(dir_mode & 0002) || + (dir_mode & 0020 && ((sysctl_protected_fifos >= 2 && S_ISFIFO(inode->i_mode)) || (sysctl_protected_regular >= 2 && S_ISREG(inode->i_mode))))) { return -EACCES; @@ -3265,6 +3266,8 @@ static int do_last(struct nameidata *nd, int *opened) { struct dentry *dir = nd->path.dentry; + kuid_t dir_uid = dir->d_inode->i_uid; + umode_t dir_mode = dir->d_inode->i_mode; int open_flag = op->open_flag; bool will_truncate = (open_flag & O_TRUNC) != 0; bool got_write = false; @@ -3400,7 +3403,7 @@ static int do_last(struct nameidata *nd, error = -EISDIR; if (d_is_dir(nd->path.dentry)) goto out; - error = may_create_in_sticky(dir, + error = may_create_in_sticky(dir_mode, dir_uid, d_backing_inode(nd->path.dentry)); if (unlikely(error)) goto out; -- GitLab From 3e0151deb2872230e2a05c11d56f3a80cd5698f7 Mon Sep 17 00:00:00 2001 From: Masato Suzuki Date: Mon, 27 Jan 2020 14:07:46 +0900 Subject: [PATCH 0681/1055] sd: Fix REQ_OP_ZONE_REPORT completion handling ZBC/ZAC report zones command may return less bytes than requested if the number of matching zones for the report request is small. However, unlike read or write commands, the remainder of incomplete report zones commands cannot be automatically requested by the block layer: the start sector of the next report cannot be known, and the report reply may not be 512B aligned for SAS drives (a report zone reply size is always a multiple of 64B). The regular request completion code executing bio_advance() and restart of the command remainder part currently causes invalid zone descriptor data to be reported to the caller if the report zone size is smaller than 512B (a case that can happen easily for a report of the last zones of a SAS drive for example). Since blkdev_report_zones() handles report zone command processing in a loop until completion (no more zones are being reported), we can safely avoid that the block layer performs an incorrect bio_advance() call and restart of the remainder of incomplete report zone BIOs. To do so, always indicate a full completion of REQ_OP_ZONE_REPORT by setting good_bytes to the request buffer size and by setting the command resid to 0. This does not affect the post processing of the report zone reply done by sd_zbc_complete() since the reply header indicates the number of zones reported. Fixes: 89d947561077 ("sd: Implement support for ZBC devices") Cc: # 4.19 Cc: # 4.14 Signed-off-by: Masato Suzuki Reviewed-by: Damien Le Moal Acked-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 2955b856e9ec..e8c2afbb82e9 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1981,9 +1981,13 @@ static int sd_done(struct scsi_cmnd *SCpnt) } break; case REQ_OP_ZONE_REPORT: + /* To avoid that the block layer performs an incorrect + * bio_advance() call and restart of the remainder of + * incomplete report zone BIOs, always indicate a full + * completion of REQ_OP_ZONE_REPORT. + */ if (!result) { - good_bytes = scsi_bufflen(SCpnt) - - scsi_get_resid(SCpnt); + good_bytes = scsi_bufflen(SCpnt); scsi_set_resid(SCpnt, 0); } else { good_bytes = 0; -- GitLab From a4681849419e18f0592961f7aa88bef19eaa66f3 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Jun 2019 16:12:36 -0600 Subject: [PATCH 0682/1055] coresight: etb10: Do not call smp_processor_id from preemptible commit 730766bae3280a25d40ea76a53dc6342e84e6513 upstream. During a perf session we try to allocate buffers on the "node" associated with the CPU the event is bound to. If it is not bound to a CPU, we use the current CPU node, using smp_processor_id(). However this is unsafe in a pre-emptible context and could generate the splats as below : BUG: using smp_processor_id() in preemptible [00000000] code: perf/2544 Use NUMA_NO_NODE hint instead of using the current node for events not bound to CPUs. Fixes: 2997aa4063d97fdb39 ("coresight: etb10: implementing AUX API") Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Cc: stable # 4.6+ Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20190620221237.3536-5-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etb10.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index d14a9cb7959a..cb675a596302 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -287,9 +287,7 @@ static void *etb_alloc_buffer(struct coresight_device *csdev, int cpu, int node; struct cs_buffers *buf; - if (cpu == -1) - cpu = smp_processor_id(); - node = cpu_to_node(cpu); + node = (cpu == -1) ? NUMA_NO_NODE : cpu_to_node(cpu); buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node); if (!buf) -- GitLab From 308856261df4828afbe00abbb7b226ec80555479 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Thu, 20 Jun 2019 16:12:35 -0600 Subject: [PATCH 0683/1055] coresight: tmc-etf: Do not call smp_processor_id from preemptible commit 024c1fd9dbcc1d8a847f1311f999d35783921b7f upstream. During a perf session we try to allocate buffers on the "node" associated with the CPU the event is bound to. If it is not bound to a CPU, we use the current CPU node, using smp_processor_id(). However this is unsafe in a pre-emptible context and could generate the splats as below : BUG: using smp_processor_id() in preemptible [00000000] code: perf/2544 caller is tmc_alloc_etf_buffer+0x5c/0x60 CPU: 2 PID: 2544 Comm: perf Not tainted 5.1.0-rc6-147786-g116841e #344 Hardware name: ARM LTD ARM Juno Development Platform/ARM Juno Development Platform, BIOS EDK II Feb 1 2019 Call trace: dump_backtrace+0x0/0x150 show_stack+0x14/0x20 dump_stack+0x9c/0xc4 debug_smp_processor_id+0x10c/0x110 tmc_alloc_etf_buffer+0x5c/0x60 etm_setup_aux+0x1c4/0x230 rb_alloc_aux+0x1b8/0x2b8 perf_mmap+0x35c/0x478 mmap_region+0x34c/0x4f0 do_mmap+0x2d8/0x418 vm_mmap_pgoff+0xd0/0xf8 ksys_mmap_pgoff+0x88/0xf8 __arm64_sys_mmap+0x28/0x38 el0_svc_handler+0xd8/0x138 el0_svc+0x8/0xc Use NUMA_NO_NODE hint instead of using the current node for events not bound to CPUs. Fixes: 2e499bbc1a929ac ("coresight: tmc: implementing TMC-ETF AUX space API") Cc: Mathieu Poirier Signed-off-by: Suzuki K Poulose Cc: stable # 4.7+ Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20190620221237.3536-4-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-tmc-etf.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etf.c b/drivers/hwtracing/coresight/coresight-tmc-etf.c index 336194d059fe..0a00f4e941fb 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etf.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etf.c @@ -308,9 +308,7 @@ static void *tmc_alloc_etf_buffer(struct coresight_device *csdev, int cpu, int node; struct cs_buffers *buf; - if (cpu == -1) - cpu = smp_processor_id(); - node = cpu_to_node(cpu); + node = (cpu == -1) ? NUMA_NO_NODE : cpu_to_node(cpu); /* Allocate memory structure for interaction with Perf */ buf = kzalloc_node(sizeof(struct cs_buffers), GFP_KERNEL, node); -- GitLab From 5cdd9e0e7ee99caf59ad54fa833eeb6033386875 Mon Sep 17 00:00:00 2001 From: Wen Huang Date: Thu, 28 Nov 2019 18:51:04 +0800 Subject: [PATCH 0684/1055] libertas: Fix two buffer overflows at parsing bss descriptor commit e5e884b42639c74b5b57dc277909915c0aefc8bb upstream. add_ie_rates() copys rates without checking the length in bss descriptor from remote AP.when victim connects to remote attacker, this may trigger buffer overflow. lbs_ibss_join_existing() copys rates without checking the length in bss descriptor from remote IBSS node.when victim connects to remote attacker, this may trigger buffer overflow. Fix them by putting the length check before performing copy. This fix addresses CVE-2019-14896 and CVE-2019-14897. This also fix build warning of mixed declarations and code. Reported-by: kbuild test robot Signed-off-by: Wen Huang Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/marvell/libertas/cfg.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index 9f3a7b512673..4ffc188d2ffd 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -273,6 +273,10 @@ add_ie_rates(u8 *tlv, const u8 *ie, int *nrates) int hw, ap, ap_max = ie[1]; u8 hw_rate; + if (ap_max > MAX_RATES) { + lbs_deb_assoc("invalid rates\n"); + return tlv; + } /* Advance past IE header */ ie += 2; @@ -1720,6 +1724,9 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, struct cmd_ds_802_11_ad_hoc_join cmd; u8 preamble = RADIO_PREAMBLE_SHORT; int ret = 0; + int hw, i; + u8 rates_max; + u8 *rates; /* TODO: set preamble based on scan result */ ret = lbs_set_radio(priv, preamble, 1); @@ -1778,9 +1785,12 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, if (!rates_eid) { lbs_add_rates(cmd.bss.rates); } else { - int hw, i; - u8 rates_max = rates_eid[1]; - u8 *rates = cmd.bss.rates; + rates_max = rates_eid[1]; + if (rates_max > MAX_RATES) { + lbs_deb_join("invalid rates"); + goto out; + } + rates = cmd.bss.rates; for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) { u8 hw_rate = lbs_rates[hw].bitrate / 5; for (i = 0; i < rates_max; i++) { -- GitLab From bef0dc84c65d057f3bbdb577028b73692ca1556f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 10 Nov 2019 07:27:04 +0100 Subject: [PATCH 0685/1055] media: v4l2-ioctl.c: zero reserved fields for S/TRY_FMT commit ee8951e56c0f960b9621636603a822811cef3158 upstream. v4l2_vbi_format, v4l2_sliced_vbi_format and v4l2_sdr_format have a reserved array at the end that should be zeroed by drivers as per the V4L2 spec. Older drivers often do not do this, so just handle this in the core. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-ioctl.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 7cafc8a57950..8eb52139684a 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1496,12 +1496,12 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VBI_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_vbi_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.vbi); + CLEAR_AFTER_FIELD(p, fmt.vbi.flags); return ops->vidioc_s_fmt_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.sliced); + CLEAR_AFTER_FIELD(p, fmt.sliced.io_size); return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_vid_out)) @@ -1524,22 +1524,22 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VBI_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_vbi_out)) break; - CLEAR_AFTER_FIELD(p, fmt.vbi); + CLEAR_AFTER_FIELD(p, fmt.vbi.flags); return ops->vidioc_s_fmt_vbi_out(file, fh, arg); case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_out)) break; - CLEAR_AFTER_FIELD(p, fmt.sliced); + CLEAR_AFTER_FIELD(p, fmt.sliced.io_size); return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg); case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_sdr_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.sdr); + CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize); return ops->vidioc_s_fmt_sdr_cap(file, fh, arg); case V4L2_BUF_TYPE_SDR_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_sdr_out)) break; - CLEAR_AFTER_FIELD(p, fmt.sdr); + CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize); return ops->vidioc_s_fmt_sdr_out(file, fh, arg); case V4L2_BUF_TYPE_META_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_meta_cap)) @@ -1583,12 +1583,12 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VBI_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_vbi_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.vbi); + CLEAR_AFTER_FIELD(p, fmt.vbi.flags); return ops->vidioc_try_fmt_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.sliced); + CLEAR_AFTER_FIELD(p, fmt.sliced.io_size); return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_vid_out)) @@ -1611,22 +1611,22 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VBI_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_vbi_out)) break; - CLEAR_AFTER_FIELD(p, fmt.vbi); + CLEAR_AFTER_FIELD(p, fmt.vbi.flags); return ops->vidioc_try_fmt_vbi_out(file, fh, arg); case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_out)) break; - CLEAR_AFTER_FIELD(p, fmt.sliced); + CLEAR_AFTER_FIELD(p, fmt.sliced.io_size); return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg); case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_sdr_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.sdr); + CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize); return ops->vidioc_try_fmt_sdr_cap(file, fh, arg); case V4L2_BUF_TYPE_SDR_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_sdr_out)) break; - CLEAR_AFTER_FIELD(p, fmt.sdr); + CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize); return ops->vidioc_try_fmt_sdr_out(file, fh, arg); case V4L2_BUF_TYPE_META_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_meta_cap)) -- GitLab From 20c0aa965935903656ec476ca3ffcfbee10d07e8 Mon Sep 17 00:00:00 2001 From: Bo Wu Date: Wed, 20 Nov 2019 13:26:17 +0000 Subject: [PATCH 0686/1055] scsi: iscsi: Avoid potential deadlock in iscsi_if_rx func commit bba340c79bfe3644829db5c852fdfa9e33837d6d upstream. In iscsi_if_rx func, after receiving one request through iscsi_if_recv_msg func, iscsi_if_send_reply will be called to try to reply to the request in a do-while loop. If the iscsi_if_send_reply function keeps returning -EAGAIN, a deadlock will occur. For example, a client only send msg without calling recvmsg func, then it will result in the watchdog soft lockup. The details are given as follows: sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ISCSI); retval = bind(sock_fd, (struct sock addr*) & src_addr, sizeof(src_addr); while (1) { state_msg = sendmsg(sock_fd, &msg, 0); //Note: recvmsg(sock_fd, &msg, 0) is not processed here. } close(sock_fd); watchdog: BUG: soft lockup - CPU#7 stuck for 22s! [netlink_test:253305] Sample time: 4000897528 ns(HZ: 250) Sample stat: curr: user: 675503481560, nice: 321724050, sys: 448689506750, idle: 4654054240530, iowait: 40885550700, irq: 14161174020, softirq: 8104324140, st: 0 deta: user: 0, nice: 0, sys: 3998210100, idle: 0, iowait: 0, irq: 1547170, softirq: 242870, st: 0 Sample softirq: TIMER: 992 SCHED: 8 Sample irqstat: irq 2: delta 1003, curr: 3103802, arch_timer CPU: 7 PID: 253305 Comm: netlink_test Kdump: loaded Tainted: G OE Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015 pstate: 40400005 (nZcv daif +PAN -UAO) pc : __alloc_skb+0x104/0x1b0 lr : __alloc_skb+0x9c/0x1b0 sp : ffff000033603a30 x29: ffff000033603a30 x28: 00000000000002dd x27: ffff800b34ced810 x26: ffff800ba7569f00 x25: 00000000ffffffff x24: 0000000000000000 x23: ffff800f7c43f600 x22: 0000000000480020 x21: ffff0000091d9000 x20: ffff800b34eff200 x19: ffff800ba7569f00 x18: 0000000000000000 x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 x14: 0001000101000100 x13: 0000000101010000 x12: 0101000001010100 x11: 0001010101010001 x10: 00000000000002dd x9 : ffff000033603d58 x8 : ffff800b34eff400 x7 : ffff800ba7569200 x6 : ffff800b34eff400 x5 : 0000000000000000 x4 : 00000000ffffffff x3 : 0000000000000000 x2 : 0000000000000001 x1 : ffff800b34eff2c0 x0 : 0000000000000300 Call trace: __alloc_skb+0x104/0x1b0 iscsi_if_rx+0x144/0x12bc [scsi_transport_iscsi] netlink_unicast+0x1e0/0x258 netlink_sendmsg+0x310/0x378 sock_sendmsg+0x4c/0x70 sock_write_iter+0x90/0xf0 __vfs_write+0x11c/0x190 vfs_write+0xac/0x1c0 ksys_write+0x6c/0xd8 __arm64_sys_write+0x24/0x30 el0_svc_common+0x78/0x130 el0_svc_handler+0x38/0x78 el0_svc+0x8/0xc Link: https://lore.kernel.org/r/EDBAAA0BBBA2AC4E9C8B6B81DEEE1D6915E3D4D2@dggeml505-mbx.china.huawei.com Signed-off-by: Bo Wu Reviewed-by: Zhiqiang Liu Reviewed-by: Lee Duncan Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_transport_iscsi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index b4d06bd9ed51..95d71e301a53 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -37,6 +37,8 @@ #define ISCSI_TRANSPORT_VERSION "2.0-870" +#define ISCSI_SEND_MAX_ALLOWED 10 + static int dbg_session; module_param_named(debug_session, dbg_session, int, S_IRUGO | S_IWUSR); @@ -3680,6 +3682,7 @@ iscsi_if_rx(struct sk_buff *skb) struct nlmsghdr *nlh; struct iscsi_uevent *ev; uint32_t group; + int retries = ISCSI_SEND_MAX_ALLOWED; nlh = nlmsg_hdr(skb); if (nlh->nlmsg_len < sizeof(*nlh) + sizeof(*ev) || @@ -3710,6 +3713,10 @@ iscsi_if_rx(struct sk_buff *skb) break; err = iscsi_if_send_reply(portid, nlh->nlmsg_type, ev, sizeof(*ev)); + if (err == -EAGAIN && --retries < 0) { + printk(KERN_WARNING "Send reply failed, error %d\n", err); + break; + } } while (err < 0 && err != -ECONNREFUSED && err != -ESRCH); skb_pull(skb, rlen); } -- GitLab From e9a80d43d9b50198256eb75c92a1341c6169ec1f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 28 Jan 2020 12:49:12 +0100 Subject: [PATCH 0687/1055] md: Avoid namespace collision with bitmap API commit e64e4018d572710c44f42c923d4ac059f0a23320 upstream. bitmap API (include/linux/bitmap.h) has 'bitmap' prefix for its methods. On the other hand MD bitmap API is special case. Adding 'md' prefix to it to avoid name space collision. No functional changes intended. Signed-off-by: Andy Shevchenko Acked-by: Shaohua Li Signed-off-by: Dmitry Torokhov [only take the bitmap_free change for stable - gregkh] Signed-off-by: Greg Kroah-Hartman --- drivers/md/bitmap.c | 10 +++++----- drivers/md/bitmap.h | 2 +- drivers/md/md-cluster.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 0cabf31fb163..7eb76a1a2505 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1729,7 +1729,7 @@ void bitmap_flush(struct mddev *mddev) /* * free memory that was allocated */ -void bitmap_free(struct bitmap *bitmap) +void md_bitmap_free(struct bitmap *bitmap) { unsigned long k, pages; struct bitmap_page *bp; @@ -1763,7 +1763,7 @@ void bitmap_free(struct bitmap *bitmap) kfree(bp); kfree(bitmap); } -EXPORT_SYMBOL(bitmap_free); +EXPORT_SYMBOL(md_bitmap_free); void bitmap_wait_behind_writes(struct mddev *mddev) { @@ -1796,7 +1796,7 @@ void bitmap_destroy(struct mddev *mddev) if (mddev->thread) mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT; - bitmap_free(bitmap); + md_bitmap_free(bitmap); } /* @@ -1887,7 +1887,7 @@ struct bitmap *bitmap_create(struct mddev *mddev, int slot) return bitmap; error: - bitmap_free(bitmap); + md_bitmap_free(bitmap); return ERR_PTR(err); } @@ -1958,7 +1958,7 @@ struct bitmap *get_bitmap_from_slot(struct mddev *mddev, int slot) rv = bitmap_init_from_disk(bitmap, 0); if (rv) { - bitmap_free(bitmap); + md_bitmap_free(bitmap); return ERR_PTR(rv); } diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index 5df35ca90f58..dd53a978c5f2 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h @@ -271,7 +271,7 @@ int bitmap_resize(struct bitmap *bitmap, sector_t blocks, struct bitmap *get_bitmap_from_slot(struct mddev *mddev, int slot); int bitmap_copy_from_slot(struct mddev *mddev, int slot, sector_t *lo, sector_t *hi, bool clear_bits); -void bitmap_free(struct bitmap *bitmap); +void md_bitmap_free(struct bitmap *bitmap); void bitmap_wait_behind_writes(struct mddev *mddev); #endif diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 717aaffc227d..10057ac85476 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -1128,7 +1128,7 @@ int cluster_check_sync_size(struct mddev *mddev) bm_lockres = lockres_init(mddev, str, NULL, 1); if (!bm_lockres) { pr_err("md-cluster: Cannot initialize %s\n", str); - bitmap_free(bitmap); + md_bitmap_free(bitmap); return -1; } bm_lockres->flags |= DLM_LKF_NOQUEUE; @@ -1142,11 +1142,11 @@ int cluster_check_sync_size(struct mddev *mddev) sync_size = sb->sync_size; else if (sync_size != sb->sync_size) { kunmap_atomic(sb); - bitmap_free(bitmap); + md_bitmap_free(bitmap); return -1; } kunmap_atomic(sb); - bitmap_free(bitmap); + md_bitmap_free(bitmap); } return (my_sync_size == sync_size) ? 0 : -1; -- GitLab From 8f715caa52eae8a31704cb398a2d9fe5250a37bf Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 1 Aug 2018 15:42:56 -0700 Subject: [PATCH 0688/1055] bitmap: Add bitmap_alloc(), bitmap_zalloc() and bitmap_free() commit c42b65e363ce97a828f81b59033c3558f8fa7f70 upstream. A lot of code become ugly because of open coding allocations for bitmaps. Introduce three helpers to allow users be more clear of intention and keep their code neat. Note, due to multiple circular dependencies we may not provide the helpers as inliners. For now we keep them exported and, perhaps, at some point in the future we will sort out header inclusion and inheritance. Signed-off-by: Andy Shevchenko Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- include/linux/bitmap.h | 8 ++++++++ lib/bitmap.c | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h index aec255fb62aa..10a4dd02221d 100644 --- a/include/linux/bitmap.h +++ b/include/linux/bitmap.h @@ -86,6 +86,14 @@ * contain all bit positions from 0 to 'bits' - 1. */ +/* + * Allocation and deallocation of bitmap. + * Provided in lib/bitmap.c to avoid circular dependency. + */ +extern unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags); +extern unsigned long *bitmap_zalloc(unsigned int nbits, gfp_t flags); +extern void bitmap_free(const unsigned long *bitmap); + /* * lib/bitmap.c provides these functions: */ diff --git a/lib/bitmap.c b/lib/bitmap.c index 2a9373ef4054..fbe38a83acb3 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -1212,3 +1213,22 @@ void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int n } EXPORT_SYMBOL(bitmap_copy_le); #endif + +unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags) +{ + return kmalloc_array(BITS_TO_LONGS(nbits), sizeof(unsigned long), + flags); +} +EXPORT_SYMBOL(bitmap_alloc); + +unsigned long *bitmap_zalloc(unsigned int nbits, gfp_t flags) +{ + return bitmap_alloc(nbits, flags | __GFP_ZERO); +} +EXPORT_SYMBOL(bitmap_zalloc); + +void bitmap_free(const unsigned long *bitmap) +{ + kfree(bitmap); +} +EXPORT_SYMBOL(bitmap_free); -- GitLab From f3439dd7ee8662c4f8558b5f41676e15c31776c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kadlecsik=20J=C3=B3zsef?= Date: Sun, 19 Jan 2020 22:06:49 +0100 Subject: [PATCH 0689/1055] netfilter: ipset: use bitmap infrastructure completely commit 32c72165dbd0e246e69d16a3ad348a4851afd415 upstream. The bitmap allocation did not use full unsigned long sizes when calculating the required size and that was triggered by KASAN as slab-out-of-bounds read in several places. The patch fixes all of them. Reported-by: syzbot+fabca5cbf5e54f3fe2de@syzkaller.appspotmail.com Reported-by: syzbot+827ced406c9a1d9570ed@syzkaller.appspotmail.com Reported-by: syzbot+190d63957b22ef673ea5@syzkaller.appspotmail.com Reported-by: syzbot+dfccdb2bdb4a12ad425e@syzkaller.appspotmail.com Reported-by: syzbot+df0d0f5895ef1f41a65b@syzkaller.appspotmail.com Reported-by: syzbot+b08bd19bb37513357fd4@syzkaller.appspotmail.com Reported-by: syzbot+53cdd0ec0bbabd53370a@syzkaller.appspotmail.com Signed-off-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- include/linux/netfilter/ipset/ip_set.h | 7 ------- net/netfilter/ipset/ip_set_bitmap_gen.h | 2 +- net/netfilter/ipset/ip_set_bitmap_ip.c | 6 +++--- net/netfilter/ipset/ip_set_bitmap_ipmac.c | 6 +++--- net/netfilter/ipset/ip_set_bitmap_port.c | 6 +++--- 5 files changed, 10 insertions(+), 17 deletions(-) diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index 91a533bd3eb1..b7246b7e0bf4 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h @@ -445,13 +445,6 @@ ip6addrptr(const struct sk_buff *skb, bool src, struct in6_addr *addr) sizeof(*addr)); } -/* Calculate the bytes required to store the inclusive range of a-b */ -static inline int -bitmap_bytes(u32 a, u32 b) -{ - return 4 * ((((b - a + 8) / 8) + 3) / 4); -} - #include #include #include diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h index b0701f6259cc..3c0e345367a5 100644 --- a/net/netfilter/ipset/ip_set_bitmap_gen.h +++ b/net/netfilter/ipset/ip_set_bitmap_gen.h @@ -79,7 +79,7 @@ mtype_flush(struct ip_set *set) if (set->extensions & IPSET_EXT_DESTROY) mtype_ext_cleanup(set); - memset(map->members, 0, map->memsize); + bitmap_zero(map->members, map->elements); set->elements = 0; set->ext_size = 0; } diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c index 4783efff0bde..a4c104a4977f 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ip.c +++ b/net/netfilter/ipset/ip_set_bitmap_ip.c @@ -40,7 +40,7 @@ MODULE_ALIAS("ip_set_bitmap:ip"); /* Type structure */ struct bitmap_ip { - void *members; /* the set members */ + unsigned long *members; /* the set members */ u32 first_ip; /* host byte order, included in range */ u32 last_ip; /* host byte order, included in range */ u32 elements; /* number of max elements in the set */ @@ -222,7 +222,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, u32 first_ip, u32 last_ip, u32 elements, u32 hosts, u8 netmask) { - map->members = ip_set_alloc(map->memsize); + map->members = bitmap_zalloc(elements, GFP_KERNEL | __GFP_NOWARN); if (!map->members) return false; map->first_ip = first_ip; @@ -315,7 +315,7 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[], if (!map) return -ENOMEM; - map->memsize = bitmap_bytes(0, elements - 1); + map->memsize = BITS_TO_LONGS(elements) * sizeof(unsigned long); set->variant = &bitmap_ip; if (!init_map_ip(set, map, first_ip, last_ip, elements, hosts, netmask)) { diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c index 9a065f672d3a..8e58e7e34981 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c @@ -46,7 +46,7 @@ enum { /* Type structure */ struct bitmap_ipmac { - void *members; /* the set members */ + unsigned long *members; /* the set members */ u32 first_ip; /* host byte order, included in range */ u32 last_ip; /* host byte order, included in range */ u32 elements; /* number of max elements in the set */ @@ -299,7 +299,7 @@ static bool init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, u32 first_ip, u32 last_ip, u32 elements) { - map->members = ip_set_alloc(map->memsize); + map->members = bitmap_zalloc(elements, GFP_KERNEL | __GFP_NOWARN); if (!map->members) return false; map->first_ip = first_ip; @@ -363,7 +363,7 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[], if (!map) return -ENOMEM; - map->memsize = bitmap_bytes(0, elements - 1); + map->memsize = BITS_TO_LONGS(elements) * sizeof(unsigned long); set->variant = &bitmap_ipmac; if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) { kfree(map); diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c index 7f0c733358a4..6771b362a123 100644 --- a/net/netfilter/ipset/ip_set_bitmap_port.c +++ b/net/netfilter/ipset/ip_set_bitmap_port.c @@ -34,7 +34,7 @@ MODULE_ALIAS("ip_set_bitmap:port"); /* Type structure */ struct bitmap_port { - void *members; /* the set members */ + unsigned long *members; /* the set members */ u16 first_port; /* host byte order, included in range */ u16 last_port; /* host byte order, included in range */ u32 elements; /* number of max elements in the set */ @@ -207,7 +207,7 @@ static bool init_map_port(struct ip_set *set, struct bitmap_port *map, u16 first_port, u16 last_port) { - map->members = ip_set_alloc(map->memsize); + map->members = bitmap_zalloc(map->elements, GFP_KERNEL | __GFP_NOWARN); if (!map->members) return false; map->first_port = first_port; @@ -250,7 +250,7 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[], return -ENOMEM; map->elements = elements; - map->memsize = bitmap_bytes(0, map->elements); + map->memsize = BITS_TO_LONGS(elements) * sizeof(unsigned long); set->variant = &bitmap_port; if (!init_map_port(set, map, first_port, last_port)) { kfree(map); -- GitLab From 94868d28db84f25e316e1d9d914263df4496e70b Mon Sep 17 00:00:00 2001 From: Martin Schiller Date: Thu, 9 Jan 2020 07:31:14 +0100 Subject: [PATCH 0690/1055] net/x25: fix nonblocking connect commit e21dba7a4df4d93da237da65a096084b4f2e87b4 upstream. This patch fixes 2 issues in x25_connect(): 1. It makes absolutely no sense to reset the neighbour and the connection state after a (successful) nonblocking call of x25_connect. This prevents any connection from being established, since the response (call accept) cannot be processed. 2. Any further calls to x25_connect() while a call is pending should simply return, instead of creating new Call Request (on different logical channels). This patch should also fix the "KASAN: null-ptr-deref Write in x25_connect" and "BUG: unable to handle kernel NULL pointer dereference in x25_connect" bugs reported by syzbot. Signed-off-by: Martin Schiller Reported-by: syzbot+429c200ffc8772bfe070@syzkaller.appspotmail.com Reported-by: syzbot+eec0c87f31a7c3b66f7b@syzkaller.appspotmail.com Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/x25/af_x25.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index a156b6dc3a72..f4fa33b84cde 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -764,6 +764,10 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, if (sk->sk_state == TCP_ESTABLISHED) goto out; + rc = -EALREADY; /* Do nothing if call is already in progress */ + if (sk->sk_state == TCP_SYN_SENT) + goto out; + sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; @@ -810,7 +814,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, /* Now the loop */ rc = -EINPROGRESS; if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) - goto out_put_neigh; + goto out; rc = x25_wait_for_connection_establishment(sk); if (rc) -- GitLab From 9fa690a2a016e1b55356835f047b952e67d3d73a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 29 Jan 2020 15:02:39 +0100 Subject: [PATCH 0691/1055] Linux 4.14.169 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1e74ba09cdda..795d93bfe156 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 168 +SUBLEVEL = 169 EXTRAVERSION = NAME = Petit Gorille -- GitLab From 8f92c773d6e715fe7b8ad23bf7ba148b74401ca9 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Wed, 29 Jan 2020 09:15:17 -0800 Subject: [PATCH 0692/1055] ANDROID: Incremental fs: Fix sparse errors Fix all sparse errors in fs/incfs except fs/incfs/integrity.c:192:9: warning: Variable length array is used Test: incfs_test passes Bug: 133435829 Change-Id: I9c2e26e4e1a06a894977f11a3c8559b968dd115e Signed-off-by: Paul Lawrence --- fs/incfs/format.c | 4 ++-- fs/incfs/main.c | 2 +- fs/incfs/vfs.c | 11 ++++++----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/fs/incfs/format.c b/fs/incfs/format.c index 247e1b4ec563..db71f527cf36 100644 --- a/fs/incfs/format.c +++ b/fs/incfs/format.c @@ -178,7 +178,7 @@ static int append_md_to_backing_file(struct backing_file_context *bfc, record_size = le16_to_cpu(record->h_record_size); file_pos = incfs_get_end_offset(bfc->bc_file); - record->h_prev_md_offset = bfc->bc_last_md_record_offset; + record->h_prev_md_offset = cpu_to_le64(bfc->bc_last_md_record_offset); record->h_next_md_offset = 0; record->h_record_crc = cpu_to_le32(calc_md_crc(record)); @@ -281,7 +281,7 @@ int incfs_write_file_attr_to_backing_file(struct backing_file_context *bfc, file_attr.fa_header.h_next_md_offset = cpu_to_le64(0); file_attr.fa_size = cpu_to_le16((u16)value.len); file_attr.fa_offset = cpu_to_le64(value_offset); - file_attr.fa_crc = cpu_to_le64(crc); + file_attr.fa_crc = cpu_to_le32(crc); result = write_to_bf(bfc, value.data, value.len, value_offset, true); if (result) diff --git a/fs/incfs/main.c b/fs/incfs/main.c index d9eec7496846..e65d0d895128 100644 --- a/fs/incfs/main.c +++ b/fs/incfs/main.c @@ -12,7 +12,7 @@ #define INCFS_NODE_FEATURES "features" -struct file_system_type incfs_fs_type = { +static struct file_system_type incfs_fs_type = { .owner = THIS_MODULE, .name = INCFS_NAME, .mount = incfs_mount_fs, diff --git a/fs/incfs/vfs.c b/fs/incfs/vfs.c index 0c2f23e5ca55..e4790189abd3 100644 --- a/fs/incfs/vfs.c +++ b/fs/incfs/vfs.c @@ -18,6 +18,7 @@ #include +#include "vfs.h" #include "data_mgmt.h" #include "format.h" #include "integrity.h" @@ -173,7 +174,7 @@ static const struct xattr_handler incfs_xattr_handler = { .get = incfs_handler_getxattr, }; -const struct xattr_handler *incfs_xattr_ops[] = { +static const struct xattr_handler *incfs_xattr_ops[] = { &incfs_xattr_handler, NULL, }; @@ -933,11 +934,11 @@ static int init_new_file(struct mount_info *mi, struct dentry *dentry, struct path path = {}; struct file *new_file; int error = 0; - struct backing_file_context *bfc = 0; + struct backing_file_context *bfc = NULL; u32 block_count; - struct mem_range mem_range = {0}; - struct signature_info *si = 0; - struct mtree *hash_tree = 0; + struct mem_range mem_range = {NULL}; + struct signature_info *si = NULL; + struct mtree *hash_tree = NULL; if (!mi || !dentry || !uuid) return -EFAULT; -- GitLab From 3a88df7f17ab1671ff2e68a5305451d251d870cd Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 1 Feb 2018 21:27:22 -0800 Subject: [PATCH 0693/1055] UPSTREAM: libnvdimm, namespace: make min namespace size 4K The arbitrary 4MB minimum namespace size turns out to be too large for some environments. Quoting Cheng-mean Liu: In the case of emulated NVDIMM devices in the VM environment, there are scenarios that NVDIMM device with much smaller sizes are desired, for example, we might use a single enumerated NVDIMM DAX device for representing each container layer, which in some cases could be just a few KBs size. PAGE_SIZE is the minimum where we can still support DAX of at least a single page. Cc: Matthew Wilcox Reported-by: Cheng-mean Liu Signed-off-by: Dan Williams (cherry picked from commit f2ba5a5baecf795c2150826bd0c95fc3f7f3d226) Bug: 146400078 Bug: 148297388 Change-Id: I362c3d1bf27921f69e78a9c34674176e85e391f7 Signed-off-by: Alistair Delva --- include/uapi/linux/ndctl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/ndctl.h b/include/uapi/linux/ndctl.h index 145f242c7c90..c58bf7b7d906 100644 --- a/include/uapi/linux/ndctl.h +++ b/include/uapi/linux/ndctl.h @@ -257,7 +257,7 @@ enum nd_driver_flags { }; enum { - ND_MIN_NAMESPACE_SIZE = 0x00400000, + ND_MIN_NAMESPACE_SIZE = PAGE_SIZE, }; enum ars_masks { -- GitLab From 153e6e252a37429cafb850d285a36a60bc76fd89 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 6 Sep 2018 10:19:30 +0100 Subject: [PATCH 0694/1055] UPSTREAM: UAPI: ndctl: Remove use of PAGE_SIZE The macro PAGE_SIZE isn't valid outside of the kernel, so it should not appear in UAPI headers. Furthermore, the actual machine page size could theoretically change from an application's point of view if it's running in a container that gets migrated to another machine (say 4K/ppc64 to 64K/ppc64). Fixes: f2ba5a5baecf ("libnvdimm, namespace: make min namespace size 4K") Signed-off-by: David Howells Signed-off-by: Dan Williams (cherry picked from commit f366d322aea782cf786aa821d5accdc1609f9e10) Bug: 146400078 Bug: 148297388 Change-Id: I9eda3e848190b5bd26e5fc7f4d3cfdcb648fd815 Signed-off-by: Alistair Delva --- include/linux/ndctl.h | 22 ++++++++++++++++++++++ include/uapi/linux/ndctl.h | 4 ---- 2 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 include/linux/ndctl.h diff --git a/include/linux/ndctl.h b/include/linux/ndctl.h new file mode 100644 index 000000000000..cd5a293ce3ae --- /dev/null +++ b/include/linux/ndctl.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014-2016, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU Lesser General Public License, + * version 2.1, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for + * more details. + */ +#ifndef _LINUX_NDCTL_H +#define _LINUX_NDCTL_H + +#include + +enum { + ND_MIN_NAMESPACE_SIZE = PAGE_SIZE, +}; + +#endif /* _LINUX_NDCTL_H */ diff --git a/include/uapi/linux/ndctl.h b/include/uapi/linux/ndctl.h index c58bf7b7d906..0303ad623ab4 100644 --- a/include/uapi/linux/ndctl.h +++ b/include/uapi/linux/ndctl.h @@ -256,10 +256,6 @@ enum nd_driver_flags { ND_DRIVER_DAX_PMEM = 1 << ND_DEVICE_DAX_PMEM, }; -enum { - ND_MIN_NAMESPACE_SIZE = PAGE_SIZE, -}; - enum ars_masks { ARS_STATUS_MASK = 0x0000FFFF, ARS_EXT_STATUS_SHIFT = 16, -- GitLab From 8497411066cc5f74872cd81d4b1cb0ea4bb4f839 Mon Sep 17 00:00:00 2001 From: Ram Muthiah Date: Tue, 28 Jan 2020 14:15:46 -0800 Subject: [PATCH 0695/1055] ANDROID: cuttlefish_defconfig: set CONFIG_IKHEADERS to y Change-Id: I0ed529c1e2fee8890c7e97d35097197f7d9f0e6a Signed-off-by: Ram Muthiah Bug: 143710295 Test: Treehugger --- arch/arm64/configs/cuttlefish_defconfig | 2 +- arch/x86/configs/x86_64_cuttlefish_defconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index 7fd46d9c1629..6765af189582 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -9,7 +9,7 @@ CONFIG_TASK_IO_ACCOUNTING=y CONFIG_PSI=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y -CONFIG_IKHEADERS=m +CONFIG_IKHEADERS=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y CONFIG_RT_GROUP_SCHED=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index ca27bedba3bf..cbb844f4b3d6 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -12,7 +12,7 @@ CONFIG_TASK_IO_ACCOUNTING=y CONFIG_PSI=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y -CONFIG_IKHEADERS=m +CONFIG_IKHEADERS=y CONFIG_CGROUPS=y CONFIG_MEMCG=y CONFIG_MEMCG_SWAP=y -- GitLab From 141c248217d7556cc1a2d7c31ad1a9aecaef754c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 29 Jan 2020 06:45:56 -0800 Subject: [PATCH 0696/1055] ANDROID: fix bpf jit + cfi interactions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit change from: https://android-review.googlesource.com/c/kernel/common/+/1126406 ANDROID: bpf: validate bpf_func when BPF_JIT is enabled with CFI was incorrectly reverted in: https://android-review.googlesource.com/c/kernel/common/+/1184358 UPSTREAM: bpf: multi program support for cgroup+bpf Test: builds Bug: 121213201 Bug: 138317270 Signed-off-by: Maciej Żenczykowski Change-Id: I2b238de61340e58eb71aaa6cf6b59945a8740a08 --- include/linux/filter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/filter.h b/include/linux/filter.h index 5a5786240006..f33f80ee9dc6 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -536,7 +536,7 @@ static inline void bpf_jit_set_header_magic(struct bpf_binary_header *hdr) } #endif -#define BPF_PROG_RUN(filter, ctx) (*(filter)->bpf_func)(ctx, (filter)->insnsi) +#define BPF_PROG_RUN(filter, ctx) bpf_call_func(filter, ctx) #define BPF_SKB_CB_LEN QDISC_CB_PRIV_LEN -- GitLab From 98c326e94fad8628bae2bd62e6ae0c179972bbd1 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Thu, 9 Jan 2020 11:48:58 -0800 Subject: [PATCH 0697/1055] ANDROID: Incremental fs: Enable incremental-fs in cuttlefish_defconfig Bug: 133435829 Signed-off-by: Paul Lawrence Change-Id: Iaf3926ae0bdf2363d61f83254f4150288173911f --- 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 6765af189582..d0d8ee4a9c24 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -437,6 +437,7 @@ CONFIG_QUOTA=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index cbb844f4b3d6..ba51925cfe19 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -453,6 +453,7 @@ CONFIG_QFMT_V2=y CONFIG_AUTOFS4_FS=y CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y -- GitLab From 75f80b3632ccbc11b48cb164b5ef0a49b5663a57 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 29 Jan 2020 16:04:42 -0800 Subject: [PATCH 0698/1055] ANDROID: kallsyms: strip hashes from function names with ThinLTO With CONFIG_THINLTO and CFI both enabled, LLVM appends a hash to the names of all static functions. This breaks userspace tools, so strip out the hash from output. Bug: 147422318 Change-Id: Ibea6be089d530e92dcd191481cb02549041203f6 Signed-off-by: Sami Tolvanen --- kernel/kallsyms.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 06432e1a792a..4ad367a05274 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -314,6 +314,12 @@ static inline void cleanup_symbol_name(char *s) { char *res; +#ifdef CONFIG_THINLTO + /* Filter out hashes from static functions */ + res = strrchr(s, '$'); + if (res) + *res = '\0'; +#endif res = strrchr(s, '.'); if (res && !strcmp(res, ".cfi")) *res = '\0'; -- GitLab From 5fc0809078fd047fdd840cfa4d1f7f81612b1f7c Mon Sep 17 00:00:00 2001 From: Ram Muthiah Date: Thu, 30 Jan 2020 21:39:15 -0800 Subject: [PATCH 0699/1055] ANDROID: cf_defconfig: removed old VIRTIO configs SCSI_VIRTIO and VIRTIO_BALLOON are not needed to run cuttlefish. Test: Treehugger Bug: 135937364 Change-Id: Ie65598c1adc834d2a88799d73eee55bc86d329ae Signed-off-by: Ram Muthiah --- arch/arm64/configs/cuttlefish_defconfig | 2 -- arch/x86/configs/x86_64_cuttlefish_defconfig | 2 -- 2 files changed, 4 deletions(-) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index d0d8ee4a9c24..cebf887fabcc 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -220,7 +220,6 @@ 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 @@ -405,7 +404,6 @@ CONFIG_RTC_DRV_PL031=y CONFIG_VIRTIO_PCI=y # CONFIG_VIRTIO_PCI_LEGACY is not set CONFIG_VIRTIO_PMEM=y -CONFIG_VIRTIO_BALLOON=y CONFIG_VIRTIO_INPUT=y CONFIG_VIRTIO_MMIO=y CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index ba51925cfe19..1f8f9ebca55e 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -234,7 +234,6 @@ CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=y CONFIG_SCSI_CONSTANTS=y CONFIG_SCSI_SPI_ATTRS=y -CONFIG_SCSI_VIRTIO=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y @@ -421,7 +420,6 @@ CONFIG_RTC_DRV_TEST=y CONFIG_SW_SYNC=y CONFIG_VIRTIO_PCI=y CONFIG_VIRTIO_PMEM=y -CONFIG_VIRTIO_BALLOON=y CONFIG_VIRTIO_INPUT=y CONFIG_VIRTIO_MMIO=y CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y -- GitLab From 19a55f5defbc82dee173cc91f480cb8d5dcc3bc6 Mon Sep 17 00:00:00 2001 From: Ram Muthiah Date: Fri, 31 Jan 2020 18:03:10 -0800 Subject: [PATCH 0700/1055] ANDROID: cf_defconfig: removed CONFIG_CAN Test: Treehugger Change-Id: Ib973c53d0c58906fcbf551f6cda5a2c915119742 Signed-off-by: Ram Muthiah --- arch/arm64/configs/cuttlefish_defconfig | 4 ---- arch/x86/configs/x86_64_cuttlefish_defconfig | 4 ---- 2 files changed, 8 deletions(-) diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index cebf887fabcc..7b49457d4b61 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -196,10 +196,6 @@ CONFIG_NET_CLS_ACT=y CONFIG_VSOCKETS=y CONFIG_VIRTIO_VSOCKETS=y CONFIG_BPF_JIT=y -CONFIG_CAN=y -# CONFIG_CAN_BCM is not set -# CONFIG_CAN_GW is not set -CONFIG_CAN_VCAN=y CONFIG_CFG80211=y # CONFIG_CFG80211_DEFAULT_PS is not set CONFIG_MAC80211=y diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 1f8f9ebca55e..35ae5541007f 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -207,10 +207,6 @@ CONFIG_NET_CLS_ACT=y CONFIG_VSOCKETS=y CONFIG_VIRTIO_VSOCKETS=y CONFIG_BPF_JIT=y -CONFIG_CAN=y -# CONFIG_CAN_BCM is not set -# CONFIG_CAN_GW is not set -CONFIG_CAN_VCAN=y CONFIG_CFG80211=y CONFIG_MAC80211=y CONFIG_RFKILL=y -- GitLab From 24ac4314b915c8c6687717b5db4ff004ad034456 Mon Sep 17 00:00:00 2001 From: Ram Muthiah Date: Fri, 31 Jan 2020 18:26:35 -0800 Subject: [PATCH 0701/1055] ANDROID: cf_defconfig: Remove VIRTIO_CONSOLE Test: Treehugger Change-Id: Icd7ab67ef6da790bec5895bb2a6a137e2a14845f Signed-off-by: Ram Muthiah --- 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 7b49457d4b61..930d43759d06 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -297,7 +297,6 @@ CONFIG_SERIAL_OF_PLATFORM=y CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_SERIAL_DEV_BUS=y -CONFIG_VIRTIO_CONSOLE=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_VIRTIO=y # CONFIG_HW_RANDOM_CAVIUM is not set diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 35ae5541007f..81950eb19c4f 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -311,7 +311,6 @@ CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_DEV_BUS=y -CONFIG_VIRTIO_CONSOLE=y CONFIG_HW_RANDOM=y # CONFIG_HW_RANDOM_INTEL is not set # CONFIG_HW_RANDOM_AMD is not set -- GitLab From a79def80c7a478ac5b07d16998cf2fa52affa13b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 10 Dec 2019 12:44:23 +0100 Subject: [PATCH 0702/1055] orinoco_usb: fix interface sanity check commit b73e05aa543cf8db4f4927e36952360d71291d41 upstream. Make sure to use the current alternate setting when verifying the interface descriptors to avoid binding to an invalid interface. Failing to do so could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on. Fixes: 9afac70a7305 ("orinoco: add orinoco_usb driver") Cc: stable # 2.6.35 Signed-off-by: Johan Hovold Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intersil/orinoco/orinoco_usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c index 56f6e3b71f48..95015d74b1c0 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c @@ -1613,9 +1613,9 @@ static int ezusb_probe(struct usb_interface *interface, /* set up the endpoint information */ /* check out the endpoints */ - iface_desc = &interface->altsetting[0].desc; + iface_desc = &interface->cur_altsetting->desc; for (i = 0; i < iface_desc->bNumEndpoints; ++i) { - ep = &interface->altsetting[0].endpoint[i].desc; + ep = &interface->cur_altsetting->endpoint[i].desc; if (usb_endpoint_is_bulk_in(ep)) { /* we found a bulk in endpoint */ -- GitLab From 98a23baf0794352313aeda5d7ebcfb867db05929 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 10 Dec 2019 12:44:25 +0100 Subject: [PATCH 0703/1055] rsi_91x_usb: fix interface sanity check commit 3139b180906af43bc09bd3373fc2338a8271d9d9 upstream. Make sure to use the current alternate setting when verifying the interface descriptors to avoid binding to an invalid interface. Failing to do so could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on. Fixes: dad0d04fa7ba ("rsi: Add RS9113 wireless driver") Cc: stable # 3.15 Cc: Fariya Fatima Signed-off-by: Johan Hovold Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rsi/rsi_91x_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index f90c10b3c921..786a330bc470 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -105,7 +105,7 @@ static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface, __le16 buffer_size; int ii, bep_found = 0; - iface_desc = &(interface->altsetting[0]); + iface_desc = interface->cur_altsetting; for (ii = 0; ii < iface_desc->desc.bNumEndpoints; ++ii) { endpoint = &(iface_desc->endpoint[ii].desc); -- GitLab From 172b7f71488cfcb1426790bdefe334b1487fb65c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 22 Jan 2020 11:15:26 +0100 Subject: [PATCH 0704/1055] USB: serial: ir-usb: add missing endpoint sanity check commit 2988a8ae7476fe9535ab620320790d1714bdad1d upstream. Add missing endpoint sanity check to avoid dereferencing a NULL-pointer on open() in case a device lacks a bulk-out endpoint. Note that prior to commit f4a4cbb2047e ("USB: ir-usb: reimplement using generic framework") the oops would instead happen on open() if the device lacked a bulk-in endpoint and on write() if it lacked a bulk-out endpoint. Fixes: f4a4cbb2047e ("USB: ir-usb: reimplement using generic framework") Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ir-usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index f9734a96d516..069e34a1f8e3 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -199,6 +199,9 @@ static int ir_startup(struct usb_serial *serial) struct usb_irda_cs_descriptor *irda_desc; int rates; + if (serial->num_bulk_in < 1 || serial->num_bulk_out < 1) + return -ENODEV; + irda_desc = irda_usb_find_class_desc(serial, 0); if (!irda_desc) { dev_err(&serial->dev->dev, -- GitLab From dc7692a8975be3e97a5e0df02ab619430eb3ead8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 22 Jan 2020 11:15:27 +0100 Subject: [PATCH 0705/1055] USB: serial: ir-usb: fix link-speed handling commit 17a0184ca17e288decdca8b2841531e34d49285f upstream. Commit e0d795e4f36c ("usb: irda: cleanup on ir-usb module") added a USB IrDA header with common defines, but mistakingly switched to using the class-descriptor baud-rate bitmask values for the outbound header. This broke link-speed handling for rates above 9600 baud, but a device would also be able to operate at the default 9600 baud until a link-speed request was issued (e.g. using the TCGETS ioctl). Fixes: e0d795e4f36c ("usb: irda: cleanup on ir-usb module") Cc: stable # 2.6.27 Cc: Felipe Balbi Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ir-usb.c | 20 ++++++++++---------- include/linux/usb/irda.h | 13 ++++++++++++- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 069e34a1f8e3..e1c4a81a556c 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -339,34 +339,34 @@ static void ir_set_termios(struct tty_struct *tty, switch (baud) { case 2400: - ir_baud = USB_IRDA_BR_2400; + ir_baud = USB_IRDA_LS_2400; break; case 9600: - ir_baud = USB_IRDA_BR_9600; + ir_baud = USB_IRDA_LS_9600; break; case 19200: - ir_baud = USB_IRDA_BR_19200; + ir_baud = USB_IRDA_LS_19200; break; case 38400: - ir_baud = USB_IRDA_BR_38400; + ir_baud = USB_IRDA_LS_38400; break; case 57600: - ir_baud = USB_IRDA_BR_57600; + ir_baud = USB_IRDA_LS_57600; break; case 115200: - ir_baud = USB_IRDA_BR_115200; + ir_baud = USB_IRDA_LS_115200; break; case 576000: - ir_baud = USB_IRDA_BR_576000; + ir_baud = USB_IRDA_LS_576000; break; case 1152000: - ir_baud = USB_IRDA_BR_1152000; + ir_baud = USB_IRDA_LS_1152000; break; case 4000000: - ir_baud = USB_IRDA_BR_4000000; + ir_baud = USB_IRDA_LS_4000000; break; default: - ir_baud = USB_IRDA_BR_9600; + ir_baud = USB_IRDA_LS_9600; baud = 9600; } diff --git a/include/linux/usb/irda.h b/include/linux/usb/irda.h index 396d2b043e64..556a801efce3 100644 --- a/include/linux/usb/irda.h +++ b/include/linux/usb/irda.h @@ -119,11 +119,22 @@ struct usb_irda_cs_descriptor { * 6 - 115200 bps * 7 - 576000 bps * 8 - 1.152 Mbps - * 9 - 5 mbps + * 9 - 4 Mbps * 10..15 - Reserved */ #define USB_IRDA_STATUS_LINK_SPEED 0x0f +#define USB_IRDA_LS_NO_CHANGE 0 +#define USB_IRDA_LS_2400 1 +#define USB_IRDA_LS_9600 2 +#define USB_IRDA_LS_19200 3 +#define USB_IRDA_LS_38400 4 +#define USB_IRDA_LS_57600 5 +#define USB_IRDA_LS_115200 6 +#define USB_IRDA_LS_576000 7 +#define USB_IRDA_LS_1152000 8 +#define USB_IRDA_LS_4000000 9 + /* The following is a 4-bit value used only for * outbound header: * -- GitLab From 2cb7f8d0e7512189b3b7ea287ffce36d7831897f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 22 Jan 2020 11:15:28 +0100 Subject: [PATCH 0706/1055] USB: serial: ir-usb: fix IrLAP framing commit 38c0d5bdf4973f9f5a888166e9d3e9ed0d32057a upstream. Commit f4a4cbb2047e ("USB: ir-usb: reimplement using generic framework") switched to using the generic write implementation which may combine multiple write requests into larger transfers. This can break the IrLAP protocol where end-of-frame is determined using the USB short packet mechanism, for example, if multiple frames are sent in rapid succession. Fixes: f4a4cbb2047e ("USB: ir-usb: reimplement using generic framework") Cc: stable # 2.6.35 Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ir-usb.c | 113 +++++++++++++++++++++++++++++------- 1 file changed, 91 insertions(+), 22 deletions(-) diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index e1c4a81a556c..a3e3b4703f38 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -49,9 +49,10 @@ static int buffer_size; static int xbof = -1; static int ir_startup (struct usb_serial *serial); -static int ir_open(struct tty_struct *tty, struct usb_serial_port *port); -static int ir_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size); +static int ir_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count); +static int ir_write_room(struct tty_struct *tty); +static void ir_write_bulk_callback(struct urb *urb); static void ir_process_read_urb(struct urb *urb); static void ir_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios); @@ -81,8 +82,9 @@ static struct usb_serial_driver ir_device = { .num_ports = 1, .set_termios = ir_set_termios, .attach = ir_startup, - .open = ir_open, - .prepare_write_buffer = ir_prepare_write_buffer, + .write = ir_write, + .write_room = ir_write_room, + .write_bulk_callback = ir_write_bulk_callback, .process_read_urb = ir_process_read_urb, }; @@ -258,35 +260,102 @@ static int ir_startup(struct usb_serial *serial) return 0; } -static int ir_open(struct tty_struct *tty, struct usb_serial_port *port) +static int ir_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count) { - int i; + struct urb *urb = NULL; + unsigned long flags; + int ret; - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) - port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET; + if (port->bulk_out_size == 0) + return -EINVAL; - /* Start reading from the device */ - return usb_serial_generic_open(tty, port); -} + if (count == 0) + return 0; -static int ir_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size) -{ - unsigned char *buf = dest; - int count; + count = min(count, port->bulk_out_size - 1); + + spin_lock_irqsave(&port->lock, flags); + if (__test_and_clear_bit(0, &port->write_urbs_free)) { + urb = port->write_urbs[0]; + port->tx_bytes += count; + } + spin_unlock_irqrestore(&port->lock, flags); + + if (!urb) + return 0; /* * The first byte of the packet we send to the device contains an - * inbound header which indicates an additional number of BOFs and + * outbound header which indicates an additional number of BOFs and * a baud rate change. * * See section 5.4.2.2 of the USB IrDA spec. */ - *buf = ir_xbof | ir_baud; + *(u8 *)urb->transfer_buffer = ir_xbof | ir_baud; + + memcpy(urb->transfer_buffer + 1, buf, count); + + urb->transfer_buffer_length = count + 1; + urb->transfer_flags = URB_ZERO_PACKET; + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) { + dev_err(&port->dev, "failed to submit write urb: %d\n", ret); + + spin_lock_irqsave(&port->lock, flags); + __set_bit(0, &port->write_urbs_free); + port->tx_bytes -= count; + spin_unlock_irqrestore(&port->lock, flags); + + return ret; + } + + return count; +} + +static void ir_write_bulk_callback(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + int status = urb->status; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + __set_bit(0, &port->write_urbs_free); + port->tx_bytes -= urb->transfer_buffer_length - 1; + spin_unlock_irqrestore(&port->lock, flags); + + switch (status) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: + dev_dbg(&port->dev, "write urb stopped: %d\n", status); + return; + case -EPIPE: + dev_err(&port->dev, "write urb stopped: %d\n", status); + return; + default: + dev_err(&port->dev, "nonzero write-urb status: %d\n", status); + break; + } + + usb_serial_port_softint(port); +} + +static int ir_write_room(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + int count = 0; + + if (port->bulk_out_size == 0) + return 0; + + if (test_bit(0, &port->write_urbs_free)) + count = port->bulk_out_size - 1; - count = kfifo_out_locked(&port->write_fifo, buf + 1, size - 1, - &port->lock); - return count + 1; + return count; } static void ir_process_read_urb(struct urb *urb) -- GitLab From e1b4f5461f8b7f11d3882e2725f0fed2632ef02e Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Wed, 11 Dec 2019 10:10:03 -0600 Subject: [PATCH 0707/1055] usb: dwc3: turn off VBUS when leaving host mode commit 09ed259fac621634d51cd986aa8d65f035662658 upstream. VBUS should be turned off when leaving the host mode. Set GCTL_PRTCAP to device mode in teardown to de-assert DRVVBUS pin to turn off VBUS power. Fixes: 5f94adfeed97 ("usb: dwc3: core: refactor mode initialization to its own function") Cc: stable@vger.kernel.org Signed-off-by: Bin Liu Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a497b878c3e2..021899c58028 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1031,6 +1031,9 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc) /* do nothing */ break; } + + /* de-assert DRVVBUS for HOST and OTG mode */ + dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); } static void dwc3_get_properties(struct dwc3 *dwc) -- GitLab From 6560fd66278fec045902010ff7b07878a13e501f Mon Sep 17 00:00:00 2001 From: Andrey Shvetsov Date: Thu, 16 Jan 2020 18:22:39 +0100 Subject: [PATCH 0708/1055] staging: most: net: fix buffer overflow commit 4d1356ac12f4d5180d0df345d85ff0ee42b89c72 upstream. If the length of the socket buffer is 0xFFFFFFFF (max size for an unsigned int), then payload_len becomes 0xFFFFFFF1 after subtracting 14 (ETH_HLEN). Then, mdp_len is set to payload_len + 16 (MDP_HDR_LEN) which overflows and results in a value of 2. These values for payload_len and mdp_len will pass current buffer size checks. This patch checks if derived from skb->len sum may overflow. The check is based on the following idea: For any `unsigned V1, V2` and derived `unsigned SUM = V1 + V2`, `V1 + V2` overflows iif `SUM < V1`. Reported-by: Greg Kroah-Hartman Signed-off-by: Andrey Shvetsov Cc: stable Link: https://lore.kernel.org/r/20200116172238.6046-1-andrey.shvetsov@microchip.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/aim-network/networking.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/staging/most/aim-network/networking.c b/drivers/staging/most/aim-network/networking.c index 936f013c350e..6398c27563c9 100644 --- a/drivers/staging/most/aim-network/networking.c +++ b/drivers/staging/most/aim-network/networking.c @@ -85,6 +85,11 @@ static int skb_to_mamac(const struct sk_buff *skb, struct mbo *mbo) unsigned int payload_len = skb->len - ETH_HLEN; unsigned int mdp_len = payload_len + MDP_HDR_LEN; + if (mdp_len < skb->len) { + pr_err("drop: too large packet! (%u)\n", skb->len); + return -EINVAL; + } + if (mbo->buffer_length < mdp_len) { pr_err("drop: too small buffer! (%d for %d)\n", mbo->buffer_length, mdp_len); @@ -132,6 +137,11 @@ static int skb_to_mep(const struct sk_buff *skb, struct mbo *mbo) u8 *buff = mbo->virt_address; unsigned int mep_len = skb->len + MEP_HDR_LEN; + if (mep_len < skb->len) { + pr_err("drop: too large packet! (%u)\n", skb->len); + return -EINVAL; + } + if (mbo->buffer_length < mep_len) { pr_err("drop: too small buffer! (%d for %d)\n", mbo->buffer_length, mep_len); -- GitLab From 07219a4cf2fca988405fb835ef950191ec972dd8 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 14 Jan 2020 18:16:04 +0000 Subject: [PATCH 0709/1055] staging: wlan-ng: ensure error return is actually returned commit 4cc41cbce536876678b35e03c4a8a7bb72c78fa9 upstream. Currently when the call to prism2sta_ifst fails a netdev_err error is reported, error return variable result is set to -1 but the function always returns 0 for success. Fix this by returning the error value in variable result rather than 0. Addresses-Coverity: ("Unused value") Fixes: 00b3ed168508 ("Staging: add wlan-ng prism2 usb driver") Signed-off-by: Colin Ian King Cc: stable Link: https://lore.kernel.org/r/20200114181604.390235-1-colin.king@canonical.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/prism2mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c index c4aa9e7e7003..be89a0ee44bf 100644 --- a/drivers/staging/wlan-ng/prism2mgmt.c +++ b/drivers/staging/wlan-ng/prism2mgmt.c @@ -945,7 +945,7 @@ int prism2mgmt_flashdl_state(struct wlandevice *wlandev, void *msgp) } } - return 0; + return result; } /*---------------------------------------------------------------- -- GitLab From abb33ca718674b7bc027dd16377b3553b44f4ee2 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 8 Jan 2020 21:40:58 +0000 Subject: [PATCH 0710/1055] staging: vt6656: correct packet types for CTS protect, mode. commit d971fdd3412f8342747778fb59b8803720ed82b1 upstream. It appears that the driver still transmits in CTS protect mode even though it is not enabled in mac80211. That is both packet types PK_TYPE_11GA and PK_TYPE_11GB both use CTS protect. The only difference between them GA does not use B rates. Find if only B rate in GB or GA in protect mode otherwise transmit packets as PK_TYPE_11A. Cc: stable Signed-off-by: Malcolm Priestley Link: https://lore.kernel.org/r/9c1323ff-dbb3-0eaa-43e1-9453f7390dc0@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/device.h | 2 ++ drivers/staging/vt6656/rxtx.c | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h index 705fffa59da9..41a4f9555d07 100644 --- a/drivers/staging/vt6656/device.h +++ b/drivers/staging/vt6656/device.h @@ -62,6 +62,8 @@ #define RATE_AUTO 12 #define MAX_RATE 12 +#define VNT_B_RATES (BIT(RATE_1M) | BIT(RATE_2M) |\ + BIT(RATE_5M) | BIT(RATE_11M)) /* * device specific diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index a44abcce6fb4..f15990491ce4 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -825,10 +825,14 @@ int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb) if (info->band == NL80211_BAND_5GHZ) { pkt_type = PK_TYPE_11A; } else { - if (tx_rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) - pkt_type = PK_TYPE_11GB; - else - pkt_type = PK_TYPE_11GA; + if (tx_rate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { + if (priv->basic_rates & VNT_B_RATES) + pkt_type = PK_TYPE_11GB; + else + pkt_type = PK_TYPE_11GA; + } else { + pkt_type = PK_TYPE_11A; + } } } else { pkt_type = PK_TYPE_11B; -- GitLab From bba758d3f3b9d3295f191e42edc7bd9820f183a1 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 8 Jan 2020 21:41:20 +0000 Subject: [PATCH 0711/1055] staging: vt6656: use NULLFUCTION stack on mac80211 commit d579c43c82f093e63639151625b2139166c730fd upstream. It appears that the drivers does not go into power save correctly the NULL data packets are not being transmitted because it not enabled in mac80211. The driver needs to capture ieee80211_is_nullfunc headers and copy the duration_id to it's own duration data header. Cc: stable Signed-off-by: Malcolm Priestley Link: https://lore.kernel.org/r/610971ae-555b-a6c3-61b3-444a0c1e35b4@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/main_usb.c | 1 + drivers/staging/vt6656/rxtx.c | 14 +++++--------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index 645ea16b53d5..e8ccd800c94f 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -977,6 +977,7 @@ vt6656_probe(struct usb_interface *intf, const struct usb_device_id *id) ieee80211_hw_set(priv->hw, RX_INCLUDES_FCS); ieee80211_hw_set(priv->hw, REPORTS_TX_ACK_STATUS); ieee80211_hw_set(priv->hw, SUPPORTS_PS); + ieee80211_hw_set(priv->hw, PS_NULLFUNC_STACK); priv->hw->max_signal = 100; diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index f15990491ce4..f78f31ce6443 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -288,11 +288,9 @@ static u16 vnt_rxtx_datahead_g(struct vnt_usb_send_context *tx_context, PK_TYPE_11B, &buf->b); /* Get Duration and TimeStamp */ - if (ieee80211_is_pspoll(hdr->frame_control)) { - __le16 dur = cpu_to_le16(priv->current_aid | BIT(14) | BIT(15)); - - buf->duration_a = dur; - buf->duration_b = dur; + if (ieee80211_is_nullfunc(hdr->frame_control)) { + buf->duration_a = hdr->duration_id; + buf->duration_b = hdr->duration_id; } else { buf->duration_a = vnt_get_duration_le(priv, tx_context->pkt_type, need_ack); @@ -381,10 +379,8 @@ static u16 vnt_rxtx_datahead_ab(struct vnt_usb_send_context *tx_context, tx_context->pkt_type, &buf->ab); /* Get Duration and TimeStampOff */ - if (ieee80211_is_pspoll(hdr->frame_control)) { - __le16 dur = cpu_to_le16(priv->current_aid | BIT(14) | BIT(15)); - - buf->duration = dur; + if (ieee80211_is_nullfunc(hdr->frame_control)) { + buf->duration = hdr->duration_id; } else { buf->duration = vnt_get_duration_le(priv, tx_context->pkt_type, need_ack); -- GitLab From c6c4999a16f2af38ca4fb8cb57a86062d15961d1 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Wed, 8 Jan 2020 21:41:36 +0000 Subject: [PATCH 0712/1055] staging: vt6656: Fix false Tx excessive retries reporting. commit 9dd631fa99dc0a0dfbd191173bf355ba30ea786a upstream. The driver reporting IEEE80211_TX_STAT_ACK is not being handled correctly. The driver should only report on TSR_TMO flag is not set indicating no transmission errors and when not IEEE80211_TX_CTL_NO_ACK is being requested. Cc: stable Signed-off-by: Malcolm Priestley Link: https://lore.kernel.org/r/340f1f7f-c310-dca5-476f-abc059b9cd97@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6656/int.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/staging/vt6656/int.c b/drivers/staging/vt6656/int.c index c6ffbe0e2728..c521729c4192 100644 --- a/drivers/staging/vt6656/int.c +++ b/drivers/staging/vt6656/int.c @@ -107,9 +107,11 @@ static int vnt_int_report_rate(struct vnt_private *priv, u8 pkt_no, u8 tsr) info->status.rates[0].count = tx_retry; - if (!(tsr & (TSR_TMO | TSR_RETRYTMO))) { + if (!(tsr & TSR_TMO)) { info->status.rates[0].idx = idx; - info->flags |= IEEE80211_TX_STAT_ACK; + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) + info->flags |= IEEE80211_TX_STAT_ACK; } ieee80211_tx_status_irqsafe(priv->hw, context->skb); -- GitLab From a2e73efbb3125dfe1e19cccd883f1721b342a760 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Thu, 16 Jan 2020 13:14:01 +0100 Subject: [PATCH 0713/1055] serial: 8250_bcm2835aux: Fix line mismatch on driver unbind commit dc76697d7e933d5e299116f219c890568785ea15 upstream. Unbinding the bcm2835aux UART driver raises the following error if the maximum number of 8250 UARTs is set to 1 (via the 8250.nr_uarts module parameter or CONFIG_SERIAL_8250_RUNTIME_UARTS): (NULL device *): Removing wrong port: a6f80333 != fa20408b That's because bcm2835aux_serial_probe() retrieves UART line number 1 from the devicetree and stores it in data->uart.port.line, while serial8250_register_8250_port() instead uses UART line number 0, which is stored in data->line. On driver unbind, bcm2835aux_serial_remove() uses data->uart.port.line, which contains the wrong number. Fix it. The issue does not occur if the maximum number of 8250 UARTs is >= 2. Fixes: bdc5f3009580 ("serial: bcm2835: add driver for bcm2835-aux-uart") Signed-off-by: Lukas Wunner Cc: stable@vger.kernel.org # v4.6+ Cc: Martin Sperl Reviewed-by: Nicolas Saenz Julienne Tested-by: Nicolas Saenz Julienne Link: https://lore.kernel.org/r/912ccf553c5258135c6d7e8f404a101ef320f0f4.1579175223.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_bcm2835aux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c index a23c7da42ea8..7bbcae75e651 100644 --- a/drivers/tty/serial/8250/8250_bcm2835aux.c +++ b/drivers/tty/serial/8250/8250_bcm2835aux.c @@ -119,7 +119,7 @@ static int bcm2835aux_serial_remove(struct platform_device *pdev) { struct bcm2835aux_data *data = platform_get_drvdata(pdev); - serial8250_unregister_port(data->uart.port.line); + serial8250_unregister_port(data->line); clk_disable_unprepare(data->clk); return 0; -- GitLab From 6a35190cc2ed47344e719694f1a99255ef0dc20a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 30 Dec 2019 21:19:31 -0600 Subject: [PATCH 0714/1055] crypto: chelsio - fix writing tfm flags to wrong place commit bd56cea012fc2d6381e8cd3209510ce09f9de8c9 upstream. The chelsio crypto driver is casting 'struct crypto_aead' directly to 'struct crypto_tfm', which is incorrect because the crypto_tfm isn't the first field of 'struct crypto_aead'. Consequently, the calls to crypto_tfm_set_flags() are modifying some other field in the struct. Also, the driver is setting CRYPTO_TFM_RES_BAD_KEY_LEN in ->setauthsize(), not just in ->setkey(). This is incorrect since this flag is for bad key lengths, not for bad authentication tag lengths. Fix these bugs by removing the broken crypto_tfm_set_flags() calls from ->setauthsize() and by fixing them in ->setkey(). Fixes: 324429d74127 ("chcr: Support for Chelsio's Crypto Hardware") Cc: # v4.9+ Cc: Atul Gupta Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/chelsio/chcr_algo.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index bb7b59fc5c08..8d39f3a07bf8 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -2693,9 +2693,6 @@ static int chcr_gcm_setauthsize(struct crypto_aead *tfm, unsigned int authsize) aeadctx->mayverify = VERIFY_SW; break; default: - - crypto_tfm_set_flags((struct crypto_tfm *) tfm, - CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } return crypto_aead_setauthsize(aeadctx->sw_cipher, authsize); @@ -2720,8 +2717,6 @@ static int chcr_4106_4309_setauthsize(struct crypto_aead *tfm, aeadctx->mayverify = VERIFY_HW; break; default: - crypto_tfm_set_flags((struct crypto_tfm *)tfm, - CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } return crypto_aead_setauthsize(aeadctx->sw_cipher, authsize); @@ -2762,8 +2757,6 @@ static int chcr_ccm_setauthsize(struct crypto_aead *tfm, aeadctx->mayverify = VERIFY_HW; break; default: - crypto_tfm_set_flags((struct crypto_tfm *)tfm, - CRYPTO_TFM_RES_BAD_KEY_LEN); return -EINVAL; } return crypto_aead_setauthsize(aeadctx->sw_cipher, authsize); @@ -2790,8 +2783,7 @@ static int chcr_ccm_common_setkey(struct crypto_aead *aead, ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_256; mk_size = CHCR_KEYCTX_MAC_KEY_SIZE_256; } else { - crypto_tfm_set_flags((struct crypto_tfm *)aead, - CRYPTO_TFM_RES_BAD_KEY_LEN); + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); aeadctx->enckey_len = 0; return -EINVAL; } @@ -2831,8 +2823,7 @@ static int chcr_aead_rfc4309_setkey(struct crypto_aead *aead, const u8 *key, int error; if (keylen < 3) { - crypto_tfm_set_flags((struct crypto_tfm *)aead, - CRYPTO_TFM_RES_BAD_KEY_LEN); + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); aeadctx->enckey_len = 0; return -EINVAL; } @@ -2883,8 +2874,7 @@ static int chcr_gcm_setkey(struct crypto_aead *aead, const u8 *key, } else if (keylen == AES_KEYSIZE_256) { ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_256; } else { - crypto_tfm_set_flags((struct crypto_tfm *)aead, - CRYPTO_TFM_RES_BAD_KEY_LEN); + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); pr_err("GCM: Invalid key length %d\n", keylen); ret = -EINVAL; goto out; -- GitLab From 2f4c65c23fcd208138836e1bd0aa3198a43d4c08 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 10 Dec 2019 12:44:20 +0100 Subject: [PATCH 0715/1055] ath9k: fix storage endpoint lookup commit 0ef332951e856efa89507cdd13ba8f4fb8d4db12 upstream. Make sure to use the current alternate setting when verifying the storage interface descriptors to avoid submitting an URB to an invalid endpoint. Failing to do so could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on. Fixes: 36bcce430657 ("ath9k_htc: Handle storage devices") Cc: stable # 2.6.39 Signed-off-by: Johan Hovold Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/hif_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index c5f4dd808745..6f669166c263 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -1214,7 +1214,7 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context) static int send_eject_command(struct usb_interface *interface) { struct usb_device *udev = interface_to_usbdev(interface); - struct usb_host_interface *iface_desc = &interface->altsetting[0]; + struct usb_host_interface *iface_desc = interface->cur_altsetting; struct usb_endpoint_descriptor *endpoint; unsigned char *cmd; u8 bulk_out_ep; -- GitLab From 684cf943bb4782b49a28de5f5d0d3bf97c152c4b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 10 Dec 2019 12:44:22 +0100 Subject: [PATCH 0716/1055] brcmfmac: fix interface sanity check commit 3428fbcd6e6c0850b1a8b2a12082b7b2aabb3da3 upstream. Make sure to use the current alternate setting when verifying the interface descriptors to avoid binding to an invalid interface. Failing to do so could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on. Fixes: 71bb244ba2fd ("brcm80211: fmac: add USB support for bcm43235/6/8 chipsets") Cc: stable # 3.4 Cc: Arend van Spriel Signed-off-by: Johan Hovold Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index be855aa32154..2eb5fe7367c6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -1333,7 +1333,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) goto fail; } - desc = &intf->altsetting[0].desc; + desc = &intf->cur_altsetting->desc; if ((desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || (desc->bInterfaceSubClass != 2) || (desc->bInterfaceProtocol != 0xff)) { @@ -1346,7 +1346,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) num_of_eps = desc->bNumEndpoints; for (ep = 0; ep < num_of_eps; ep++) { - endpoint = &intf->altsetting[0].endpoint[ep].desc; + endpoint = &intf->cur_altsetting->endpoint[ep].desc; endpoint_num = usb_endpoint_num(endpoint); if (!usb_endpoint_xfer_bulk(endpoint)) continue; -- GitLab From 419d0f93ac3c043c73b6387090cb3bee416e53fe Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 10 Dec 2019 12:44:24 +0100 Subject: [PATCH 0717/1055] rtl8xxxu: fix interface sanity check commit 39a4281c312f2d226c710bc656ce380c621a2b16 upstream. Make sure to use the current alternate setting when verifying the interface descriptors to avoid binding to an invalid interface. Failing to do so could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on. Fixes: 26f1fad29ad9 ("New driver: rtl8xxxu (mac80211)") Cc: stable # 4.4 Cc: Jes Sorensen Signed-off-by: Johan Hovold Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 73fc5952fd37..63f37fa72e4b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5921,7 +5921,7 @@ static int rtl8xxxu_parse_usb(struct rtl8xxxu_priv *priv, u8 dir, xtype, num; int ret = 0; - host_interface = &interface->altsetting[0]; + host_interface = interface->cur_altsetting; interface_desc = &host_interface->desc; endpoints = interface_desc->bNumEndpoints; -- GitLab From 108b4537f1a450a4b979857f3ad5113e485917ba Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 10 Dec 2019 12:44:26 +0100 Subject: [PATCH 0718/1055] zd1211rw: fix storage endpoint lookup commit 2d68bb2687abb747558b933e80845ff31570a49c upstream. Make sure to use the current alternate setting when verifying the storage interface descriptors to avoid submitting an URB to an invalid endpoint. Failing to do so could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on. Fixes: a1030e92c150 ("[PATCH] zd1211rw: Convert installer CDROM device into WLAN device") Cc: stable # 2.6.19 Signed-off-by: Johan Hovold Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/zydas/zd1211rw/zd_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c index c30bf118c67d..1e396eb26ccf 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c @@ -1272,7 +1272,7 @@ static void print_id(struct usb_device *udev) static int eject_installer(struct usb_interface *intf) { struct usb_device *udev = interface_to_usbdev(intf); - struct usb_host_interface *iface_desc = &intf->altsetting[0]; + struct usb_host_interface *iface_desc = intf->cur_altsetting; struct usb_endpoint_descriptor *endpoint; unsigned char *cmd; u8 bulk_out_ep; -- GitLab From 0f6f0693493719ff84c7ff5ae161605d86aed619 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 26 Nov 2019 17:54:09 -0800 Subject: [PATCH 0719/1055] arc: eznps: fix allmodconfig kconfig warning [ Upstream commit 1928b36cfa4df1aeedf5f2644d0c33f3a1fcfd7b ] Fix kconfig warning for arch/arc/plat-eznps/Kconfig allmodconfig: WARNING: unmet direct dependencies detected for CLKSRC_NPS Depends on [n]: GENERIC_CLOCKEVENTS [=y] && !PHYS_ADDR_T_64BIT [=y] Selected by [y]: - ARC_PLAT_EZNPS [=y] Signed-off-by: Randy Dunlap Cc: Vineet Gupta Cc: Ofer Levi Cc: linux-snps-arc@lists.infradead.org Signed-off-by: Vineet Gupta Signed-off-by: Sasha Levin --- arch/arc/plat-eznps/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arc/plat-eznps/Kconfig b/arch/arc/plat-eznps/Kconfig index 8eff057efcae..ce908e2c5282 100644 --- a/arch/arc/plat-eznps/Kconfig +++ b/arch/arc/plat-eznps/Kconfig @@ -7,7 +7,7 @@ menuconfig ARC_PLAT_EZNPS bool "\"EZchip\" ARC dev platform" select CPU_BIG_ENDIAN - select CLKSRC_NPS + select CLKSRC_NPS if !PHYS_ADDR_T_64BIT select EZNPS_GIC select EZCHIP_NPS_MANAGEMENT_ENET if ETHERNET help -- GitLab From a30b232c18fa4736efa685f70cd00454a6e998d4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 19 Nov 2019 15:57:11 +0100 Subject: [PATCH 0720/1055] HID: ite: Add USB id match for Acer SW5-012 keyboard dock [ Upstream commit 8f18eca9ebc57d6b150237033f6439242907e0ba ] The Acer SW5-012 2-in-1 keyboard dock uses a Synaptics S91028 touchpad which is connected to an ITE 8595 USB keyboard controller chip. This keyboard has the same quirk for its rfkill / airplane mode hotkey as other keyboards with the ITE 8595 chip, it only sends a single release event when pressed and released, it never sends a press event. This commit adds this keyboards USB id to the hid-ite id-table, fixing the rfkill key not working on this keyboard. Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-ite.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 1e2e6e58256a..9d372fa7c298 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1024,6 +1024,7 @@ #define USB_DEVICE_ID_SYNAPTICS_LTS2 0x1d10 #define USB_DEVICE_ID_SYNAPTICS_HD 0x0ac3 #define USB_DEVICE_ID_SYNAPTICS_QUAD_HD 0x1ac3 +#define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012 0x2968 #define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710 #define USB_VENDOR_ID_TEXAS_INSTRUMENTS 0x2047 diff --git a/drivers/hid/hid-ite.c b/drivers/hid/hid-ite.c index 98b059d79bc8..2ce1eb0c9212 100644 --- a/drivers/hid/hid-ite.c +++ b/drivers/hid/hid-ite.c @@ -43,6 +43,9 @@ static int ite_event(struct hid_device *hdev, struct hid_field *field, static const struct hid_device_id ite_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE8595) }, { HID_USB_DEVICE(USB_VENDOR_ID_258A, USB_DEVICE_ID_258A_6A88) }, + /* ITE8595 USB kbd ctlr, with Synaptics touchpad connected to it. */ + { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, + USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012) }, { } }; MODULE_DEVICE_TABLE(hid, ite_devices); -- GitLab From aba29b46dfea2367977a7bd06a2ccdead8bf48f9 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sun, 22 Dec 2019 10:17:02 -0800 Subject: [PATCH 0721/1055] phy: cpcap-usb: Prevent USB line glitches from waking up modem [ Upstream commit 63078b6ba09e842f09df052c5728857389fddcd2 ] The micro-USB connector on Motorola Mapphone devices can be muxed between the SoC and the mdm6600 modem. But even when used for the SoC, configuring the PHY with ID pin grounded will wake up the modem from idle state. Looks like the issue is probably caused by line glitches. We can prevent the glitches by using a previously unknown mode of the GPIO mux to prevent the USB lines from being connected to the moden while configuring the USB PHY, and enable the USB lines after configuring the PHY. Note that this only prevents waking up mdm6600 as regular USB A-host mode, and does not help when connected to a lapdock. The lapdock specific issue still needs to be debugged separately. Cc: Merlijn Wajer Cc: Pavel Machek Cc: Sebastian Reichel Acked-by: Pavel Machek Signed-off-by: Tony Lindgren Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Sasha Levin --- drivers/phy/motorola/phy-cpcap-usb.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c index 4ba3634009af..593c77dbde2e 100644 --- a/drivers/phy/motorola/phy-cpcap-usb.c +++ b/drivers/phy/motorola/phy-cpcap-usb.c @@ -115,7 +115,7 @@ struct cpcap_usb_ints_state { enum cpcap_gpio_mode { CPCAP_DM_DP, CPCAP_MDM_RX_TX, - CPCAP_UNKNOWN, + CPCAP_UNKNOWN_DISABLED, /* Seems to disable USB lines */ CPCAP_OTG_DM_DP, }; @@ -379,7 +379,8 @@ static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata) { int error; - error = cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP); + /* Disable lines to prevent glitches from waking up mdm6600 */ + error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED); if (error) goto out_err; @@ -406,6 +407,11 @@ static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata) if (error) goto out_err; + /* Enable UART mode */ + error = cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP); + if (error) + goto out_err; + return 0; out_err: @@ -418,7 +424,8 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata) { int error; - error = cpcap_usb_gpio_set_mode(ddata, CPCAP_OTG_DM_DP); + /* Disable lines to prevent glitches from waking up mdm6600 */ + error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED); if (error) return error; @@ -458,6 +465,11 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata) if (error) goto out_err; + /* Enable USB mode */ + error = cpcap_usb_gpio_set_mode(ddata, CPCAP_OTG_DM_DP); + if (error) + goto out_err; + return 0; out_err: -- GitLab From d2b24c965f8f91a8d4d284808201e8c1eb2c27dc Mon Sep 17 00:00:00 2001 From: David Engraf Date: Wed, 27 Nov 2019 09:46:17 +0100 Subject: [PATCH 0722/1055] watchdog: max77620_wdt: fix potential build errors [ Upstream commit da9e3f4e30a53cd420cf1e6961c3b4110f0f21f0 ] max77620_wdt uses watchdog core functions. Enable CONFIG_WATCHDOG_CORE to fix potential build errors. Signed-off-by: David Engraf Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20191127084617.16937-1-david.engraf@sysgo.com Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin --- drivers/watchdog/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index f55328a31629..fa15a683ae2d 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -563,6 +563,7 @@ config MAX63XX_WATCHDOG config MAX77620_WATCHDOG tristate "Maxim Max77620 Watchdog Timer" depends on MFD_MAX77620 || COMPILE_TEST + select WATCHDOG_CORE help This is the driver for the Max77620 watchdog timer. Say 'Y' here to enable the watchdog timer support for -- GitLab From 60cf76ecde8c765bc7721a390bb59d08d129efe1 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Fri, 13 Dec 2019 22:48:02 +0100 Subject: [PATCH 0723/1055] watchdog: rn5t618_wdt: fix module aliases [ Upstream commit a76dfb859cd42df6e3d1910659128ffcd2fb6ba2 ] Platform device aliases were missing so module autoloading did not work. Signed-off-by: Andreas Kemnade Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20191213214802.22268-1-andreas@kemnade.info Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin --- drivers/watchdog/rn5t618_wdt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/rn5t618_wdt.c b/drivers/watchdog/rn5t618_wdt.c index e60f55702ab7..d2e79cf70e77 100644 --- a/drivers/watchdog/rn5t618_wdt.c +++ b/drivers/watchdog/rn5t618_wdt.c @@ -193,6 +193,7 @@ static struct platform_driver rn5t618_wdt_driver = { module_platform_driver(rn5t618_wdt_driver); +MODULE_ALIAS("platform:rn5t618-wdt"); MODULE_AUTHOR("Beniamino Galvani "); MODULE_DESCRIPTION("RN5T618 watchdog driver"); MODULE_LICENSE("GPL v2"); -- GitLab From b56f2a4a4327f609e30872e37eda6d73a6433ed2 Mon Sep 17 00:00:00 2001 From: "wuxu.wu" Date: Wed, 1 Jan 2020 11:39:41 +0800 Subject: [PATCH 0724/1055] spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls [ Upstream commit 19b61392c5a852b4e8a0bf35aecb969983c5932d ] dw_spi_irq() and dw_spi_transfer_one concurrent calls. I find a panic in dw_writer(): txw = *(u8 *)(dws->tx), when dw->tx==null, dw->len==4, and dw->tx_end==1. When tpm driver's message overtime dw_spi_irq() and dw_spi_transfer_one may concurrent visit dw_spi, so I think dw_spi structure lack of protection. Otherwise dw_spi_transfer_one set dw rx/tx buffer and then open irq, store dw rx/tx instructions and other cores handle irq load dw rx/tx instructions may out of order. [ 1025.321302] Call trace: ... [ 1025.321319] __crash_kexec+0x98/0x148 [ 1025.321323] panic+0x17c/0x314 [ 1025.321329] die+0x29c/0x2e8 [ 1025.321334] die_kernel_fault+0x68/0x78 [ 1025.321337] __do_kernel_fault+0x90/0xb0 [ 1025.321346] do_page_fault+0x88/0x500 [ 1025.321347] do_translation_fault+0xa8/0xb8 [ 1025.321349] do_mem_abort+0x68/0x118 [ 1025.321351] el1_da+0x20/0x8c [ 1025.321362] dw_writer+0xc8/0xd0 [ 1025.321364] interrupt_transfer+0x60/0x110 [ 1025.321365] dw_spi_irq+0x48/0x70 ... Signed-off-by: wuxu.wu Link: https://lore.kernel.org/r/1577849981-31489-1-git-send-email-wuxu.wu@huawei.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- drivers/spi/spi-dw.c | 15 ++++++++++++--- drivers/spi/spi-dw.h | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index b217c22ff72f..b461200871f8 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -180,9 +180,11 @@ static inline u32 rx_max(struct dw_spi *dws) static void dw_writer(struct dw_spi *dws) { - u32 max = tx_max(dws); + u32 max; u16 txw = 0; + spin_lock(&dws->buf_lock); + max = tx_max(dws); while (max--) { /* Set the tx word if the transfer's original "tx" is not null */ if (dws->tx_end - dws->len) { @@ -194,13 +196,16 @@ static void dw_writer(struct dw_spi *dws) dw_write_io_reg(dws, DW_SPI_DR, txw); dws->tx += dws->n_bytes; } + spin_unlock(&dws->buf_lock); } static void dw_reader(struct dw_spi *dws) { - u32 max = rx_max(dws); + u32 max; u16 rxw; + spin_lock(&dws->buf_lock); + max = rx_max(dws); while (max--) { rxw = dw_read_io_reg(dws, DW_SPI_DR); /* Care rx only if the transfer's original "rx" is not null */ @@ -212,6 +217,7 @@ static void dw_reader(struct dw_spi *dws) } dws->rx += dws->n_bytes; } + spin_unlock(&dws->buf_lock); } static void int_error_stop(struct dw_spi *dws, const char *msg) @@ -284,18 +290,20 @@ static int dw_spi_transfer_one(struct spi_master *master, { struct dw_spi *dws = spi_master_get_devdata(master); struct chip_data *chip = spi_get_ctldata(spi); + unsigned long flags; u8 imask = 0; u16 txlevel = 0; u32 cr0; int ret; dws->dma_mapped = 0; - + spin_lock_irqsave(&dws->buf_lock, flags); dws->tx = (void *)transfer->tx_buf; dws->tx_end = dws->tx + transfer->len; dws->rx = transfer->rx_buf; dws->rx_end = dws->rx + transfer->len; dws->len = transfer->len; + spin_unlock_irqrestore(&dws->buf_lock, flags); spi_enable_chip(dws, 0); @@ -486,6 +494,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) dws->type = SSI_MOTO_SPI; dws->dma_inited = 0; dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); + spin_lock_init(&dws->buf_lock); ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev), master); diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index 5c07cf8f19e0..45fbf3ad591c 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -117,6 +117,7 @@ struct dw_spi { size_t len; void *tx; void *tx_end; + spinlock_t buf_lock; void *rx; void *rx_end; int dma_mapped; -- GitLab From d24cfcdb6285470316c71558722d30aa73c55be7 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Thu, 2 Jan 2020 13:27:06 -0800 Subject: [PATCH 0725/1055] drivers/net/b44: Change to non-atomic bit operations on pwol_mask [ Upstream commit f11421ba4af706cb4f5703de34fa77fba8472776 ] Atomic operations that span cache lines are super-expensive on x86 (not just to the current processor, but also to other processes as all memory operations are blocked until the operation completes). Upcoming x86 processors have a switch to cause such operations to generate a #AC trap. It is expected that some real time systems will enable this mode in BIOS. In preparation for this, it is necessary to fix code that may execute atomic instructions with operands that cross cachelines because the #AC trap will crash the kernel. Since "pwol_mask" is local and never exposed to concurrency, there is no need to set bits in pwol_mask using atomic operations. Directly operate on the byte which contains the bit instead of using __set_bit() to avoid any big endian concern due to type cast to unsigned long in __set_bit(). Suggested-by: Peter Zijlstra Signed-off-by: Fenghua Yu Signed-off-by: Tony Luck Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/broadcom/b44.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index a1125d10c825..8b9a0ce1d29f 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -1521,8 +1521,10 @@ static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset) int ethaddr_bytes = ETH_ALEN; memset(ppattern + offset, 0xff, magicsync); - for (j = 0; j < magicsync; j++) - set_bit(len++, (unsigned long *) pmask); + for (j = 0; j < magicsync; j++) { + pmask[len >> 3] |= BIT(len & 7); + len++; + } for (j = 0; j < B44_MAX_PATTERNS; j++) { if ((B44_PATTERN_SIZE - len) >= ETH_ALEN) @@ -1534,7 +1536,8 @@ static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset) for (k = 0; k< ethaddr_bytes; k++) { ppattern[offset + magicsync + (j * ETH_ALEN) + k] = macaddr[k]; - set_bit(len++, (unsigned long *) pmask); + pmask[len >> 3] |= BIT(len & 7); + len++; } } return len - 1; -- GitLab From e52f8ff34eaa49047c225a42c0a4d2976c4ab20c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 4 Jan 2020 15:31:43 +0100 Subject: [PATCH 0726/1055] net: wan: sdla: Fix cast from pointer to integer of different size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 00c0688cecadbf7ac2f5b4cdb36d912a2d3f0cca ] Since net_device.mem_start is unsigned long, it should not be cast to int right before casting to pointer. This fixes warning (compile testing on alpha architecture): drivers/net/wan/sdla.c: In function ‘sdla_transmit’: drivers/net/wan/sdla.c:711:13: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] Signed-off-by: Krzysztof Kozlowski Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/wan/sdla.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 236c62538036..1eb329fc7241 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -711,7 +711,7 @@ static netdev_tx_t sdla_transmit(struct sk_buff *skb, spin_lock_irqsave(&sdla_lock, flags); SDLA_WINDOW(dev, addr); - pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK)); + pbuf = (void *)(dev->mem_start + (addr & SDLA_ADDR_MASK)); __sdla_write(dev, pbuf->buf_addr, skb->data, skb->len); SDLA_WINDOW(dev, addr); pbuf->opp_flag = 1; -- GitLab From c698d678854c08590c3d1964ecca1bfabc138950 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 6 Jan 2020 04:51:54 +0300 Subject: [PATCH 0727/1055] gpio: max77620: Add missing dependency on GPIOLIB_IRQCHIP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit c5706c7defc79de68a115b5536376298a8fef111 ] Driver fails to compile in a minimized kernel's configuration because of the missing dependency on GPIOLIB_IRQCHIP. error: ‘struct gpio_chip’ has no member named ‘irq’ 44 | virq = irq_find_mapping(gpio->gpio_chip.irq.domain, offset); Signed-off-by: Dmitry Osipenko Link: https://lore.kernel.org/r/20200106015154.12040-1-digetx@gmail.com Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin --- drivers/gpio/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2357d2f73c1a..8d2ab77c6581 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -990,6 +990,7 @@ config GPIO_LP87565 config GPIO_MAX77620 tristate "GPIO support for PMIC MAX77620 and MAX20024" depends on MFD_MAX77620 + select GPIOLIB_IRQCHIP help GPIO driver for MAX77620 and MAX20024 PMIC from Maxim Semiconductor. MAX77620 PMIC has 8 pins that can be configured as GPIOs. The -- GitLab From 5be2654a3fd996d423ca26fc6a48b9f1aa7199d2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 7 Jan 2020 21:43:59 +0100 Subject: [PATCH 0728/1055] atm: eni: fix uninitialized variable warning [ Upstream commit 30780d086a83332adcd9362281201cee7c3d9d19 ] With -O3, gcc has found an actual unintialized variable stored into an mmio register in two instances: drivers/atm/eni.c: In function 'discard': drivers/atm/eni.c:465:13: error: 'dma[1]' is used uninitialized in this function [-Werror=uninitialized] writel(dma[i*2+1],eni_dev->rx_dma+dma_wr*8+4); ^ drivers/atm/eni.c:465:13: error: 'dma[3]' is used uninitialized in this function [-Werror=uninitialized] Change the code to always write zeroes instead. Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/atm/eni.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index ce47eb17901d..a106d15f6def 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -372,7 +372,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, here = (eni_vcc->descr+skip) & (eni_vcc->words-1); dma[j++] = (here << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT) | MID_DT_JK; - j++; + dma[j++] = 0; } here = (eni_vcc->descr+size+skip) & (eni_vcc->words-1); if (!eff) size += skip; @@ -445,7 +445,7 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb, if (size != eff) { dma[j++] = (here << MID_DMA_COUNT_SHIFT) | (vcc->vci << MID_DMA_VCI_SHIFT) | MID_DT_JK; - j++; + dma[j++] = 0; } if (!j || j > 2*RX_DMA_BUF) { printk(KERN_CRIT DEV_LABEL "!j or j too big!!!\n"); -- GitLab From 5ed8ea1798f5585f81252fbbf49ddf50029de2a4 Mon Sep 17 00:00:00 2001 From: Slawomir Pawlowski Date: Tue, 17 Sep 2019 09:20:48 +0000 Subject: [PATCH 0729/1055] PCI: Add DMA alias quirk for Intel VCA NTB [ Upstream commit 56b4cd4b7da9ee95778eb5c8abea49f641ebfd91 ] Intel Visual Compute Accelerator (VCA) is a family of PCIe add-in devices exposing computational units via Non Transparent Bridges (NTB, PEX 87xx). Similarly to MIC x200, we need to add DMA aliases to allow buffer access when IOMMU is enabled. Add aliases to allow computational unit access to host memory. These aliases mark the whole VCA device as one IOMMU group. All possible slot numbers (0x20) are used, since we are unable to tell what slot is used on other side. This quirk is intended for both host and computational unit sides. The VCA devices have up to five functions: four for DMA channels and one additional. Link: https://lore.kernel.org/r/5683A335CC8BE1438C3C30C49DCC38DF637CED8E@IRSMSX102.ger.corp.intel.com Signed-off-by: Slawomir Pawlowski Signed-off-by: Przemek Kitszel Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin --- drivers/pci/quirks.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 90df085e9f92..e7ed051ec125 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4019,6 +4019,40 @@ static void quirk_mic_x200_dma_alias(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2260, quirk_mic_x200_dma_alias); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2264, quirk_mic_x200_dma_alias); +/* + * Intel Visual Compute Accelerator (VCA) is a family of PCIe add-in devices + * exposing computational units via Non Transparent Bridges (NTB, PEX 87xx). + * + * Similarly to MIC x200, we need to add DMA aliases to allow buffer access + * when IOMMU is enabled. These aliases allow computational unit access to + * host memory. These aliases mark the whole VCA device as one IOMMU + * group. + * + * All possible slot numbers (0x20) are used, since we are unable to tell + * what slot is used on other side. This quirk is intended for both host + * and computational unit sides. The VCA devices have up to five functions + * (four for DMA channels and one additional). + */ +static void quirk_pex_vca_alias(struct pci_dev *pdev) +{ + const unsigned int num_pci_slots = 0x20; + unsigned int slot; + + for (slot = 0; slot < num_pci_slots; slot++) { + pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x0)); + pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x1)); + pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x2)); + pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x3)); + pci_add_dma_alias(pdev, PCI_DEVFN(slot, 0x4)); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2954, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2955, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2956, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2958, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2959, quirk_pex_vca_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x295A, quirk_pex_vca_alias); + /* * The IOMMU and interrupt controller on Broadcom Vulcan/Cavium ThunderX2 are * associated not at the root bus, but at a bridge below. This quirk avoids -- GitLab From ebb7fb7dfd657b65fd7d315b0c8709af94db535f Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Tue, 8 Sep 2015 09:53:38 -0700 Subject: [PATCH 0730/1055] usb-storage: Disable UAS on JMicron SATA enclosure [ Upstream commit bc3bdb12bbb3492067c8719011576370e959a2e6 ] Steve Ellis reported incorrect block sizes and alignement offsets with a SATA enclosure. Adding a quirk to disable UAS fixes the problems. Reported-by: Steven Ellis Cc: Pacho Ramos Signed-off-by: Laura Abbott Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/usb/storage/unusual_uas.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index f15aa47c54a9..0eb8c67ee138 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -163,12 +163,15 @@ UNUSUAL_DEV(0x2537, 0x1068, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_UAS), -/* Reported-by: Takeo Nakayama */ +/* + * Initially Reported-by: Takeo Nakayama + * UAS Ignore Reported by Steven Ellis + */ UNUSUAL_DEV(0x357d, 0x7788, 0x0000, 0x9999, "JMicron", "JMS566", USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_REPORT_OPCODES), + US_FL_NO_REPORT_OPCODES | US_FL_IGNORE_UAS), /* Reported-by: Hans de Goede */ UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999, -- GitLab From b4cdf5066ce23d1cc23c1dd4c71438e762c82581 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 24 Jan 2020 14:57:20 -0800 Subject: [PATCH 0731/1055] net_sched: ematch: reject invalid TCF_EM_SIMPLE [ Upstream commit 55cd9f67f1e45de8517cdaab985fb8e56c0bc1d8 ] It is possible for malicious userspace to set TCF_EM_SIMPLE bit even for matches that should not have this bit set. This can fool two places using tcf_em_is_simple() 1) tcf_em_tree_destroy() -> memory leak of em->data if ops->destroy() is NULL 2) tcf_em_tree_dump() wrongly report/leak 4 low-order bytes of a kernel pointer. BUG: memory leak unreferenced object 0xffff888121850a40 (size 32): comm "syz-executor927", pid 7193, jiffies 4294941655 (age 19.840s) hex dump (first 32 bytes): 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<00000000f67036ea>] kmemleak_alloc_recursive include/linux/kmemleak.h:43 [inline] [<00000000f67036ea>] slab_post_alloc_hook mm/slab.h:586 [inline] [<00000000f67036ea>] slab_alloc mm/slab.c:3320 [inline] [<00000000f67036ea>] __do_kmalloc mm/slab.c:3654 [inline] [<00000000f67036ea>] __kmalloc_track_caller+0x165/0x300 mm/slab.c:3671 [<00000000fab0cc8e>] kmemdup+0x27/0x60 mm/util.c:127 [<00000000d9992e0a>] kmemdup include/linux/string.h:453 [inline] [<00000000d9992e0a>] em_nbyte_change+0x5b/0x90 net/sched/em_nbyte.c:32 [<000000007e04f711>] tcf_em_validate net/sched/ematch.c:241 [inline] [<000000007e04f711>] tcf_em_tree_validate net/sched/ematch.c:359 [inline] [<000000007e04f711>] tcf_em_tree_validate+0x332/0x46f net/sched/ematch.c:300 [<000000007a769204>] basic_set_parms net/sched/cls_basic.c:157 [inline] [<000000007a769204>] basic_change+0x1d7/0x5f0 net/sched/cls_basic.c:219 [<00000000e57a5997>] tc_new_tfilter+0x566/0xf70 net/sched/cls_api.c:2104 [<0000000074b68559>] rtnetlink_rcv_msg+0x3b2/0x4b0 net/core/rtnetlink.c:5415 [<00000000b7fe53fb>] netlink_rcv_skb+0x61/0x170 net/netlink/af_netlink.c:2477 [<00000000e83a40d0>] rtnetlink_rcv+0x1d/0x30 net/core/rtnetlink.c:5442 [<00000000d62ba933>] netlink_unicast_kernel net/netlink/af_netlink.c:1302 [inline] [<00000000d62ba933>] netlink_unicast+0x223/0x310 net/netlink/af_netlink.c:1328 [<0000000088070f72>] netlink_sendmsg+0x2c0/0x570 net/netlink/af_netlink.c:1917 [<00000000f70b15ea>] sock_sendmsg_nosec net/socket.c:639 [inline] [<00000000f70b15ea>] sock_sendmsg+0x54/0x70 net/socket.c:659 [<00000000ef95a9be>] ____sys_sendmsg+0x2d0/0x300 net/socket.c:2330 [<00000000b650f1ab>] ___sys_sendmsg+0x8a/0xd0 net/socket.c:2384 [<0000000055bfa74a>] __sys_sendmsg+0x80/0xf0 net/socket.c:2417 [<000000002abac183>] __do_sys_sendmsg net/socket.c:2426 [inline] [<000000002abac183>] __se_sys_sendmsg net/socket.c:2424 [inline] [<000000002abac183>] __x64_sys_sendmsg+0x23/0x30 net/socket.c:2424 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Reported-by: syzbot+03c4738ed29d5d366ddf@syzkaller.appspotmail.com Cc: Cong Wang Acked-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/ematch.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/sched/ematch.c b/net/sched/ematch.c index 60f2354c1789..a48dca26f178 100644 --- a/net/sched/ematch.c +++ b/net/sched/ematch.c @@ -242,6 +242,9 @@ static int tcf_em_validate(struct tcf_proto *tp, goto errout; if (em->ops->change) { + err = -EINVAL; + if (em_hdr->flags & TCF_EM_SIMPLE) + goto errout; err = em->ops->change(net, data, data_len, em); if (err < 0) goto errout; -- GitLab From c662ea4fab81c530590c2be3e86e26313d047e3b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 28 Nov 2019 18:22:01 +0100 Subject: [PATCH 0732/1055] rsi: fix use-after-free on probe errors commit 92aafe77123ab478e5f5095878856ab0424910da upstream. The driver would fail to stop the command timer in most error paths, something which specifically could lead to the timer being freed while still active on I/O errors during probe. Fix this by making sure that each function starting the timer also stops it in all relevant error paths. Reported-by: syzbot+1d1597a5aa3679c65b9f@syzkaller.appspotmail.com Fixes: b78e91bcfb33 ("rsi: Add new firmware loading method") Cc: stable # 4.12 Cc: Prameela Rani Garnepudi Cc: Amitkumar Karwar Signed-off-by: Johan Hovold Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rsi/rsi_91x_hal.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_hal.c b/drivers/net/wireless/rsi/rsi_91x_hal.c index 120b0ff545c1..d205947c4c55 100644 --- a/drivers/net/wireless/rsi/rsi_91x_hal.c +++ b/drivers/net/wireless/rsi/rsi_91x_hal.c @@ -541,6 +541,7 @@ static int bl_cmd(struct rsi_hw *adapter, u8 cmd, u8 exp_resp, char *str) bl_start_cmd_timer(adapter, timeout); status = bl_write_cmd(adapter, cmd, exp_resp, ®out_val); if (status < 0) { + bl_stop_cmd_timer(adapter); rsi_dbg(ERR_ZONE, "%s: Command %s (%0x) writing failed..\n", __func__, str, cmd); @@ -656,10 +657,9 @@ static int ping_pong_write(struct rsi_hw *adapter, u8 cmd, u8 *addr, u32 size) } status = bl_cmd(adapter, cmd_req, cmd_resp, str); - if (status) { - bl_stop_cmd_timer(adapter); + if (status) return status; - } + return 0; } @@ -749,10 +749,9 @@ static int auto_fw_upgrade(struct rsi_hw *adapter, u8 *flash_content, status = bl_cmd(adapter, EOF_REACHED, FW_LOADING_SUCCESSFUL, "EOF_REACHED"); - if (status) { - bl_stop_cmd_timer(adapter); + if (status) return status; - } + rsi_dbg(INFO_ZONE, "FW loading is done and FW is running..\n"); return 0; } @@ -773,6 +772,7 @@ static int rsi_load_firmware(struct rsi_hw *adapter) status = hif_ops->master_reg_read(adapter, SWBL_REGOUT, ®out_val, 2); if (status < 0) { + bl_stop_cmd_timer(adapter); rsi_dbg(ERR_ZONE, "%s: REGOUT read failed\n", __func__); return status; -- GitLab From 713ff7e4d605c4dd1efd838e3f0092cd93733f0c Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 5 Dec 2019 13:45:05 +0800 Subject: [PATCH 0733/1055] crypto: af_alg - Use bh_lock_sock in sk_destruct commit 37f96694cf73ba116993a9d2d99ad6a75fa7fdb0 upstream. As af_alg_release_parent may be called from BH context (most notably due to an async request that only completes after socket closure, or as reported here because of an RCU-delayed sk_destruct call), we must use bh_lock_sock instead of lock_sock. Reported-by: syzbot+c2f1558d49e25cc36e5e@syzkaller.appspotmail.com Reported-by: Eric Dumazet Fixes: c840ac6af3f8 ("crypto: af_alg - Disallow bind/setkey/...") Cc: Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/af_alg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crypto/af_alg.c b/crypto/af_alg.c index 422bba808f73..0679c35adf55 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -139,11 +139,13 @@ void af_alg_release_parent(struct sock *sk) sk = ask->parent; ask = alg_sk(sk); - lock_sock(sk); + local_bh_disable(); + bh_lock_sock(sk); ask->nokey_refcnt -= nokey; if (!last) last = !--ask->refcnt; - release_sock(sk); + bh_unlock_sock(sk); + local_bh_enable(); if (last) sock_put(sk); -- GitLab From 40642747dd9feab4912157882166c05722cec7b0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Feb 2020 16:26:45 +0000 Subject: [PATCH 0734/1055] vfs: fix do_last() regression commit 6404674acd596de41fd3ad5f267b4525494a891a upstream. Brown paperbag time: fetching ->i_uid/->i_mode really should've been done from nd->inode. I even suggested that, but the reason for that has slipped through the cracks and I went for dir->d_inode instead - made for more "obvious" patch. Analysis: - at the entry into do_last() and all the way to step_into(): dir (aka nd->path.dentry) is known not to have been freed; so's nd->inode and it's equal to dir->d_inode unless we are already doomed to -ECHILD. inode of the file to get opened is not known. - after step_into(): inode of the file to get opened is known; dir might be pointing to freed memory/be negative/etc. - at the call of may_create_in_sticky(): guaranteed to be out of RCU mode; inode of the file to get opened is known and pinned; dir might be garbage. The last was the reason for the original patch. Except that at the do_last() entry we can be in RCU mode and it is possible that nd->path.dentry->d_inode has already changed under us. In that case we are going to fail with -ECHILD, but we need to be careful; nd->inode is pointing to valid struct inode and it's the same as nd->path.dentry->d_inode in "won't fail with -ECHILD" case, so we should use that. Reported-by: "Rantala, Tommi T. (Nokia - FI/Espoo)" Reported-by: syzbot+190005201ced78a74ad6@syzkaller.appspotmail.com Wearing-brown-paperbag: Al Viro Cc: stable@kernel.org Fixes: d0cb50185ae9 ("do_last(): fetch directory ->i_mode and ->i_uid before it's too late") Signed-off-by: Al Viro Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/namei.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index d648d6d2b635..f421f8d80f4d 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3266,8 +3266,8 @@ static int do_last(struct nameidata *nd, int *opened) { struct dentry *dir = nd->path.dentry; - kuid_t dir_uid = dir->d_inode->i_uid; - umode_t dir_mode = dir->d_inode->i_mode; + kuid_t dir_uid = nd->inode->i_uid; + umode_t dir_mode = nd->inode->i_mode; int open_flag = op->open_flag; bool will_truncate = (open_flag & O_TRUNC) != 0; bool got_write = false; -- GitLab From d20edc0bca5577bab38acb5b190619c922ddebf8 Mon Sep 17 00:00:00 2001 From: Xiaochen Shen Date: Sun, 2 Feb 2020 05:59:30 +0800 Subject: [PATCH 0735/1055] x86/resctrl: Fix use-after-free when deleting resource groups commit b8511ccc75c033f6d54188ea4df7bf1e85778740 upstream. A resource group (rdtgrp) contains a reference count (rdtgrp->waitcount) that indicates how many waiters expect this rdtgrp to exist. Waiters could be waiting on rdtgroup_mutex or some work sitting on a task's workqueue for when the task returns from kernel mode or exits. The deletion of a rdtgrp is intended to have two phases: (1) while holding rdtgroup_mutex the necessary cleanup is done and rdtgrp->flags is set to RDT_DELETED, (2) after releasing the rdtgroup_mutex, the rdtgrp structure is freed only if there are no waiters and its flag is set to RDT_DELETED. Upon gaining access to rdtgroup_mutex or rdtgrp, a waiter is required to check for the RDT_DELETED flag. When unmounting the resctrl file system or deleting ctrl_mon groups, all of the subdirectories are removed and the data structure of rdtgrp is forcibly freed without checking rdtgrp->waitcount. If at this point there was a waiter on rdtgrp then a use-after-free issue occurs when the waiter starts running and accesses the rdtgrp structure it was waiting on. See kfree() calls in [1], [2] and [3] in these two call paths in following scenarios: (1) rdt_kill_sb() -> rmdir_all_sub() -> free_all_child_rdtgrp() (2) rdtgroup_rmdir() -> rdtgroup_rmdir_ctrl() -> free_all_child_rdtgrp() There are several scenarios that result in use-after-free issue in following: Scenario 1: ----------- In Thread 1, rdtgroup_tasks_write() adds a task_work callback move_myself(). If move_myself() is scheduled to execute after Thread 2 rdt_kill_sb() is finished, referring to earlier rdtgrp memory (rdtgrp->waitcount) which was already freed in Thread 2 results in use-after-free issue. Thread 1 (rdtgroup_tasks_write) Thread 2 (rdt_kill_sb) ------------------------------- ---------------------- rdtgroup_kn_lock_live atomic_inc(&rdtgrp->waitcount) mutex_lock rdtgroup_move_task __rdtgroup_move_task /* * Take an extra refcount, so rdtgrp cannot be freed * before the call back move_myself has been invoked */ atomic_inc(&rdtgrp->waitcount) /* Callback move_myself will be scheduled for later */ task_work_add(move_myself) rdtgroup_kn_unlock mutex_unlock atomic_dec_and_test(&rdtgrp->waitcount) && (flags & RDT_DELETED) mutex_lock rmdir_all_sub /* * sentry and rdtgrp are freed * without checking refcount */ free_all_child_rdtgrp kfree(sentry)*[1] kfree(rdtgrp)*[2] mutex_unlock /* * Callback is scheduled to execute * after rdt_kill_sb is finished */ move_myself /* * Use-after-free: refer to earlier rdtgrp * memory which was freed in [1] or [2]. */ atomic_dec_and_test(&rdtgrp->waitcount) && (flags & RDT_DELETED) kfree(rdtgrp) Scenario 2: ----------- In Thread 1, rdtgroup_tasks_write() adds a task_work callback move_myself(). If move_myself() is scheduled to execute after Thread 2 rdtgroup_rmdir() is finished, referring to earlier rdtgrp memory (rdtgrp->waitcount) which was already freed in Thread 2 results in use-after-free issue. Thread 1 (rdtgroup_tasks_write) Thread 2 (rdtgroup_rmdir) ------------------------------- ------------------------- rdtgroup_kn_lock_live atomic_inc(&rdtgrp->waitcount) mutex_lock rdtgroup_move_task __rdtgroup_move_task /* * Take an extra refcount, so rdtgrp cannot be freed * before the call back move_myself has been invoked */ atomic_inc(&rdtgrp->waitcount) /* Callback move_myself will be scheduled for later */ task_work_add(move_myself) rdtgroup_kn_unlock mutex_unlock atomic_dec_and_test(&rdtgrp->waitcount) && (flags & RDT_DELETED) rdtgroup_kn_lock_live atomic_inc(&rdtgrp->waitcount) mutex_lock rdtgroup_rmdir_ctrl free_all_child_rdtgrp /* * sentry is freed without * checking refcount */ kfree(sentry)*[3] rdtgroup_ctrl_remove rdtgrp->flags = RDT_DELETED rdtgroup_kn_unlock mutex_unlock atomic_dec_and_test( &rdtgrp->waitcount) && (flags & RDT_DELETED) kfree(rdtgrp) /* * Callback is scheduled to execute * after rdt_kill_sb is finished */ move_myself /* * Use-after-free: refer to earlier rdtgrp * memory which was freed in [3]. */ atomic_dec_and_test(&rdtgrp->waitcount) && (flags & RDT_DELETED) kfree(rdtgrp) If CONFIG_DEBUG_SLAB=y, Slab corruption on kmalloc-2k can be observed like following. Note that "0x6b" is POISON_FREE after kfree(). The corrupted bits "0x6a", "0x64" at offset 0x424 correspond to waitcount member of struct rdtgroup which was freed: Slab corruption (Not tainted): kmalloc-2k start=ffff9504c5b0d000, len=2048 420: 6b 6b 6b 6b 6a 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkjkkkkkkkkkkk Single bit error detected. Probably bad RAM. Run memtest86+ or a similar memory test tool. Next obj: start=ffff9504c5b0d800, len=2048 000: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk 010: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Slab corruption (Not tainted): kmalloc-2k start=ffff9504c58ab800, len=2048 420: 6b 6b 6b 6b 64 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkdkkkkkkkkkkk Prev obj: start=ffff9504c58ab000, len=2048 000: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk 010: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Fix this by taking reference count (waitcount) of rdtgrp into account in the two call paths that currently do not do so. Instead of always freeing the resource group it will only be freed if there are no waiters on it. If there are waiters, the resource group will have its flags set to RDT_DELETED. It will be left to the waiter to free the resource group when it starts running and finding that it was the last waiter and the resource group has been removed (rdtgrp->flags & RDT_DELETED) since. (1) rdt_kill_sb() -> rmdir_all_sub() -> free_all_child_rdtgrp() (2) rdtgroup_rmdir() -> rdtgroup_rmdir_ctrl() -> free_all_child_rdtgrp() Backporting notes: Since upstream commit fa7d949337cc ("x86/resctrl: Rename and move rdt files to a separate directory"), the file arch/x86/kernel/cpu/intel_rdt_rdtgroup.c has been renamed and moved to arch/x86/kernel/cpu/resctrl/rdtgroup.c. Apply the change against file arch/x86/kernel/cpu/intel_rdt_rdtgroup.c in older stable trees. Fixes: f3cbeacaa06e ("x86/intel_rdt/cqm: Add rmdir support") Fixes: 60cf5e101fd4 ("x86/intel_rdt: Add mkdir to resctrl file system") Suggested-by: Reinette Chatre Signed-off-by: Xiaochen Shen Signed-off-by: Borislav Petkov Reviewed-by: Reinette Chatre Reviewed-by: Tony Luck Acked-by: Thomas Gleixner Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/1578500886-21771-2-git-send-email-xiaochen.shen@intel.com Signed-off-by: Sasha Levin --- arch/x86/kernel/cpu/intel_rdt_rdtgroup.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c index 2dae1b3c42fc..734996904dc3 100644 --- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c +++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c @@ -1260,7 +1260,11 @@ static void free_all_child_rdtgrp(struct rdtgroup *rdtgrp) list_for_each_entry_safe(sentry, stmp, head, mon.crdtgrp_list) { free_rmid(sentry->mon.rmid); list_del(&sentry->mon.crdtgrp_list); - kfree(sentry); + + if (atomic_read(&sentry->waitcount) != 0) + sentry->flags = RDT_DELETED; + else + kfree(sentry); } } @@ -1294,7 +1298,11 @@ static void rmdir_all_sub(void) kernfs_remove(rdtgrp->kn); list_del(&rdtgrp->rdtgroup_list); - kfree(rdtgrp); + + if (atomic_read(&rdtgrp->waitcount) != 0) + rdtgrp->flags = RDT_DELETED; + else + kfree(rdtgrp); } /* Notify online CPUs to update per cpu storage and PQR_ASSOC MSR */ update_closid_rmid(cpu_online_mask, &rdtgroup_default); -- GitLab From df57e8ba374ca0e3e6dec6633ce3ed2adfe0d9a8 Mon Sep 17 00:00:00 2001 From: Xiaochen Shen Date: Sun, 2 Feb 2020 06:00:23 +0800 Subject: [PATCH 0736/1055] x86/resctrl: Fix use-after-free due to inaccurate refcount of rdtgroup commit 074fadee59ee7a9d2b216e9854bd4efb5dad679f upstream. There is a race condition in the following scenario which results in an use-after-free issue when reading a monitoring file and deleting the parent ctrl_mon group concurrently: Thread 1 calls atomic_inc() to take refcount of rdtgrp and then calls kernfs_break_active_protection() to drop the active reference of kernfs node in rdtgroup_kn_lock_live(). In Thread 2, kernfs_remove() is a blocking routine. It waits on all sub kernfs nodes to drop the active reference when removing all subtree kernfs nodes recursively. Thread 2 could block on kernfs_remove() until Thread 1 calls kernfs_break_active_protection(). Only after kernfs_remove() completes the refcount of rdtgrp could be trusted. Before Thread 1 calls atomic_inc() and kernfs_break_active_protection(), Thread 2 could call kfree() when the refcount of rdtgrp (sentry) is 0 instead of 1 due to the race. In Thread 1, in rdtgroup_kn_unlock(), referring to earlier rdtgrp memory (rdtgrp->waitcount) which was already freed in Thread 2 results in use-after-free issue. Thread 1 (rdtgroup_mondata_show) Thread 2 (rdtgroup_rmdir) -------------------------------- ------------------------- rdtgroup_kn_lock_live /* * kn active protection until * kernfs_break_active_protection(kn) */ rdtgrp = kernfs_to_rdtgroup(kn) rdtgroup_kn_lock_live atomic_inc(&rdtgrp->waitcount) mutex_lock rdtgroup_rmdir_ctrl free_all_child_rdtgrp /* * sentry->waitcount should be 1 * but is 0 now due to the race. */ kfree(sentry)*[1] /* * Only after kernfs_remove() * completes, the refcount of * rdtgrp could be trusted. */ atomic_inc(&rdtgrp->waitcount) /* kn->active-- */ kernfs_break_active_protection(kn) rdtgroup_ctrl_remove rdtgrp->flags = RDT_DELETED /* * Blocking routine, wait for * all sub kernfs nodes to drop * active reference in * kernfs_break_active_protection. */ kernfs_remove(rdtgrp->kn) rdtgroup_kn_unlock mutex_unlock atomic_dec_and_test( &rdtgrp->waitcount) && (flags & RDT_DELETED) kernfs_unbreak_active_protection(kn) kfree(rdtgrp) mutex_lock mon_event_read rdtgroup_kn_unlock mutex_unlock /* * Use-after-free: refer to earlier rdtgrp * memory which was freed in [1]. */ atomic_dec_and_test(&rdtgrp->waitcount) && (flags & RDT_DELETED) /* kn->active++ */ kernfs_unbreak_active_protection(kn) kfree(rdtgrp) Fix it by moving free_all_child_rdtgrp() to after kernfs_remove() in rdtgroup_rmdir_ctrl() to ensure it has the accurate refcount of rdtgrp. Backporting notes: Since upstream commit fa7d949337cc ("x86/resctrl: Rename and move rdt files to a separate directory"), the file arch/x86/kernel/cpu/intel_rdt_rdtgroup.c has been renamed and moved to arch/x86/kernel/cpu/resctrl/rdtgroup.c. Apply the change against file arch/x86/kernel/cpu/intel_rdt_rdtgroup.c for older stable trees. Upstream commit 17eafd076291 ("x86/intel_rdt: Split resource group removal in two") moved part of resource group removal code from rdtgroup_rmdir_mon() into a separate function rdtgroup_ctrl_remove(). Apply the change against original code base of rdtgroup_rmdir_mon() for older stable trees. Fixes: f3cbeacaa06e ("x86/intel_rdt/cqm: Add rmdir support") Suggested-by: Reinette Chatre Signed-off-by: Xiaochen Shen Signed-off-by: Borislav Petkov Reviewed-by: Reinette Chatre Reviewed-by: Tony Luck Acked-by: Thomas Gleixner Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/1578500886-21771-3-git-send-email-xiaochen.shen@intel.com Signed-off-by: Sasha Levin --- arch/x86/kernel/cpu/intel_rdt_rdtgroup.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c index 734996904dc3..01574966d91f 100644 --- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c +++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c @@ -1800,11 +1800,6 @@ static int rdtgroup_rmdir_ctrl(struct kernfs_node *kn, struct rdtgroup *rdtgrp, closid_free(rdtgrp->closid); free_rmid(rdtgrp->mon.rmid); - /* - * Free all the child monitor group rmids. - */ - free_all_child_rdtgrp(rdtgrp); - list_del(&rdtgrp->rdtgroup_list); /* @@ -1814,6 +1809,11 @@ static int rdtgroup_rmdir_ctrl(struct kernfs_node *kn, struct rdtgroup *rdtgrp, kernfs_get(kn); kernfs_remove(rdtgrp->kn); + /* + * Free all the child monitor group rmids. + */ + free_all_child_rdtgrp(rdtgrp); + return 0; } -- GitLab From e3f5c2e99092f2e57886ac40c6fa62ffcf87ab1e Mon Sep 17 00:00:00 2001 From: Xiaochen Shen Date: Sun, 2 Feb 2020 06:00:53 +0800 Subject: [PATCH 0737/1055] x86/resctrl: Fix a deadlock due to inaccurate reference commit 334b0f4e9b1b4a1d475f803419d202f6c5e4d18e upstream. There is a race condition which results in a deadlock when rmdir and mkdir execute concurrently: $ ls /sys/fs/resctrl/c1/mon_groups/m1/ cpus cpus_list mon_data tasks Thread 1: rmdir /sys/fs/resctrl/c1 Thread 2: mkdir /sys/fs/resctrl/c1/mon_groups/m1 3 locks held by mkdir/48649: #0: (sb_writers#17){.+.+}, at: [] mnt_want_write+0x20/0x50 #1: (&type->i_mutex_dir_key#8/1){+.+.}, at: [] filename_create+0x7b/0x170 #2: (rdtgroup_mutex){+.+.}, at: [] rdtgroup_kn_lock_live+0x3d/0x70 4 locks held by rmdir/48652: #0: (sb_writers#17){.+.+}, at: [] mnt_want_write+0x20/0x50 #1: (&type->i_mutex_dir_key#8/1){+.+.}, at: [] do_rmdir+0x13f/0x1e0 #2: (&type->i_mutex_dir_key#8){++++}, at: [] vfs_rmdir+0x4d/0x120 #3: (rdtgroup_mutex){+.+.}, at: [] rdtgroup_kn_lock_live+0x3d/0x70 Thread 1 is deleting control group "c1". Holding rdtgroup_mutex, kernfs_remove() removes all kernfs nodes under directory "c1" recursively, then waits for sub kernfs node "mon_groups" to drop active reference. Thread 2 is trying to create a subdirectory "m1" in the "mon_groups" directory. The wrapper kernfs_iop_mkdir() takes an active reference to the "mon_groups" directory but the code drops the active reference to the parent directory "c1" instead. As a result, Thread 1 is blocked on waiting for active reference to drop and never release rdtgroup_mutex, while Thread 2 is also blocked on trying to get rdtgroup_mutex. Thread 1 (rdtgroup_rmdir) Thread 2 (rdtgroup_mkdir) (rmdir /sys/fs/resctrl/c1) (mkdir /sys/fs/resctrl/c1/mon_groups/m1) ------------------------- ------------------------- kernfs_iop_mkdir /* * kn: "m1", parent_kn: "mon_groups", * prgrp_kn: parent_kn->parent: "c1", * * "mon_groups", parent_kn->active++: 1 */ kernfs_get_active(parent_kn) kernfs_iop_rmdir /* "c1", kn->active++ */ kernfs_get_active(kn) rdtgroup_kn_lock_live atomic_inc(&rdtgrp->waitcount) /* "c1", kn->active-- */ kernfs_break_active_protection(kn) mutex_lock rdtgroup_rmdir_ctrl free_all_child_rdtgrp sentry->flags = RDT_DELETED rdtgroup_ctrl_remove rdtgrp->flags = RDT_DELETED kernfs_get(kn) kernfs_remove(rdtgrp->kn) __kernfs_remove /* "mon_groups", sub_kn */ atomic_add(KN_DEACTIVATED_BIAS, &sub_kn->active) kernfs_drain(sub_kn) /* * sub_kn->active == KN_DEACTIVATED_BIAS + 1, * waiting on sub_kn->active to drop, but it * never drops in Thread 2 which is blocked * on getting rdtgroup_mutex. */ Thread 1 hangs here ----> wait_event(sub_kn->active == KN_DEACTIVATED_BIAS) ... rdtgroup_mkdir rdtgroup_mkdir_mon(parent_kn, prgrp_kn) mkdir_rdt_prepare(parent_kn, prgrp_kn) rdtgroup_kn_lock_live(prgrp_kn) atomic_inc(&rdtgrp->waitcount) /* * "c1", prgrp_kn->active-- * * The active reference on "c1" is * dropped, but not matching the * actual active reference taken * on "mon_groups", thus causing * Thread 1 to wait forever while * holding rdtgroup_mutex. */ kernfs_break_active_protection( prgrp_kn) /* * Trying to get rdtgroup_mutex * which is held by Thread 1. */ Thread 2 hangs here ----> mutex_lock ... The problem is that the creation of a subdirectory in the "mon_groups" directory incorrectly releases the active protection of its parent directory instead of itself before it starts waiting for rdtgroup_mutex. This is triggered by the rdtgroup_mkdir() flow calling rdtgroup_kn_lock_live()/rdtgroup_kn_unlock() with kernfs node of the parent control group ("c1") as argument. It should be called with kernfs node "mon_groups" instead. What is currently missing is that the kn->priv of "mon_groups" is NULL instead of pointing to the rdtgrp. Fix it by pointing kn->priv to rdtgrp when "mon_groups" is created. Then it could be passed to rdtgroup_kn_lock_live()/rdtgroup_kn_unlock() instead. And then it operates on the same rdtgroup structure but handles the active reference of kernfs node "mon_groups" to prevent deadlock. The same changes are also made to the "mon_data" directories. This results in some unused function parameters that will be cleaned up in follow-up patch as the focus here is on the fix only in support of backporting efforts. Backporting notes: Since upstream commit fa7d949337cc ("x86/resctrl: Rename and move rdt files to a separate directory"), the file arch/x86/kernel/cpu/intel_rdt_rdtgroup.c has been renamed and moved to arch/x86/kernel/cpu/resctrl/rdtgroup.c. Apply the change against file arch/x86/kernel/cpu/intel_rdt_rdtgroup.c for older stable trees. Fixes: c7d9aac61311 ("x86/intel_rdt/cqm: Add mkdir support for RDT monitoring") Suggested-by: Reinette Chatre Signed-off-by: Xiaochen Shen Signed-off-by: Borislav Petkov Reviewed-by: Reinette Chatre Reviewed-by: Tony Luck Acked-by: Thomas Gleixner Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/1578500886-21771-4-git-send-email-xiaochen.shen@intel.com Signed-off-by: Sasha Levin --- arch/x86/kernel/cpu/intel_rdt_rdtgroup.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c index 01574966d91f..0ec30b2384c0 100644 --- a/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c +++ b/arch/x86/kernel/cpu/intel_rdt_rdtgroup.c @@ -1107,7 +1107,7 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type, if (rdt_mon_capable) { ret = mongroup_create_dir(rdtgroup_default.kn, - NULL, "mon_groups", + &rdtgroup_default, "mon_groups", &kn_mongrp); if (ret) { dentry = ERR_PTR(ret); @@ -1499,7 +1499,7 @@ static int mkdir_mondata_all(struct kernfs_node *parent_kn, /* * Create the mon_data directory first. */ - ret = mongroup_create_dir(parent_kn, NULL, "mon_data", &kn); + ret = mongroup_create_dir(parent_kn, prgrp, "mon_data", &kn); if (ret) return ret; @@ -1533,7 +1533,7 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn, uint files = 0; int ret; - prdtgrp = rdtgroup_kn_lock_live(prgrp_kn); + prdtgrp = rdtgroup_kn_lock_live(parent_kn); if (!prdtgrp) { ret = -ENODEV; goto out_unlock; @@ -1589,7 +1589,7 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn, kernfs_activate(kn); /* - * The caller unlocks the prgrp_kn upon success. + * The caller unlocks the parent_kn upon success. */ return 0; @@ -1600,7 +1600,7 @@ static int mkdir_rdt_prepare(struct kernfs_node *parent_kn, out_free_rgrp: kfree(rdtgrp); out_unlock: - rdtgroup_kn_unlock(prgrp_kn); + rdtgroup_kn_unlock(parent_kn); return ret; } @@ -1638,7 +1638,7 @@ static int rdtgroup_mkdir_mon(struct kernfs_node *parent_kn, */ list_add_tail(&rdtgrp->mon.crdtgrp_list, &prgrp->mon.crdtgrp_list); - rdtgroup_kn_unlock(prgrp_kn); + rdtgroup_kn_unlock(parent_kn); return ret; } @@ -1675,7 +1675,7 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn, * Create an empty mon_groups directory to hold the subset * of tasks and cpus to monitor. */ - ret = mongroup_create_dir(kn, NULL, "mon_groups", NULL); + ret = mongroup_create_dir(kn, rdtgrp, "mon_groups", NULL); if (ret) goto out_id_free; } @@ -1688,7 +1688,7 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn, out_common_fail: mkdir_rdt_prepare_clean(rdtgrp); out_unlock: - rdtgroup_kn_unlock(prgrp_kn); + rdtgroup_kn_unlock(parent_kn); return ret; } -- GitLab From db4d8e42eca72d4c29192e793475c1e6a42908cf Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 19 Nov 2019 17:41:31 +0800 Subject: [PATCH 0738/1055] crypto: pcrypt - Fix user-after-free on module unload [ Upstream commit 07bfd9bdf568a38d9440c607b72342036011f727 ] On module unload of pcrypt we must unregister the crypto algorithms first and then tear down the padata structure. As otherwise the crypto algorithms are still alive and can be used while the padata structure is being freed. Fixes: 5068c7a883d1 ("crypto: pcrypt - Add pcrypt crypto...") Cc: Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin --- crypto/pcrypt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c index a5718c0a3dc4..1348541da463 100644 --- a/crypto/pcrypt.c +++ b/crypto/pcrypt.c @@ -505,11 +505,12 @@ static int __init pcrypt_init(void) static void __exit pcrypt_exit(void) { + crypto_unregister_template(&pcrypt_tmpl); + pcrypt_fini_padata(&pencrypt); pcrypt_fini_padata(&pdecrypt); kset_unregister(pcrypt_kset); - crypto_unregister_template(&pcrypt_tmpl); } module_init(pcrypt_init); -- GitLab From 806dbe2dfa4855c97ec1da876fbd2fdfb61426f5 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Wed, 8 Jan 2020 20:30:30 -0800 Subject: [PATCH 0739/1055] perf c2c: Fix return type for histogram sorting comparision functions commit c1c8013ec34d7163431d18367808ea40b2e305f8 upstream. Commit 722ddfde366f ("perf tools: Fix time sorting") changed - correctly so - hist_entry__sort to return int64. Unfortunately several of the builtin-c2c.c comparison routines only happened to work due the cast caused by the wrong return type. This causes meaningless ordering of both the cacheline list, and the cacheline details page. E.g a simple: perf c2c record -a sleep 3 perf c2c report will result in cacheline table like ================================================= Shared Data Cache Line Table ================================================= # # ------- Cacheline ---------- Total Tot - LLC Load Hitm - - Store Reference - - Load Dram - LLC Total - Core Load Hit - - LLC Load Hit - # Index Address Node PA cnt records Hitm Total Lcl Rmt Total L1Hit L1Miss Lcl Rmt Ld Miss Loads FB L1 L2 Llc Rmt # ..... .............. .... ...... ....... ...... ..... ..... ... .... ..... ...... ...... .... ...... ..... ..... ..... ... .... ....... 0 0x7f0d27ffba00 N/A 0 52 0.12% 13 6 7 12 12 0 0 7 14 40 4 16 0 0 0 1 0x7f0d27ff61c0 N/A 0 6353 14.04% 1475 801 674 779 779 0 0 718 1392 5574 1299 1967 0 115 0 2 0x7f0d26d3ec80 N/A 0 71 0.15% 16 4 12 13 13 0 0 12 24 58 1 20 0 9 0 3 0x7f0d26d3ec00 N/A 0 98 0.22% 23 17 6 19 19 0 0 6 12 79 0 40 0 10 0 i.e. with the list not being ordered by Total Hitm. Fixes: 722ddfde366f ("perf tools: Fix time sorting") Signed-off-by: Andres Freund Tested-by: Michael Petlan Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Namhyung Kim Cc: Peter Zijlstra Cc: stable@vger.kernel.org # v3.16+ Link: http://lore.kernel.org/lkml/20200109043030.233746-1-andres@anarazel.de Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/builtin-c2c.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index bec7a2f1fb4d..264d458bfe2a 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -528,8 +528,8 @@ tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused, { struct c2c_hist_entry *c2c_left; struct c2c_hist_entry *c2c_right; - unsigned int tot_hitm_left; - unsigned int tot_hitm_right; + uint64_t tot_hitm_left; + uint64_t tot_hitm_right; c2c_left = container_of(left, struct c2c_hist_entry, he); c2c_right = container_of(right, struct c2c_hist_entry, he); @@ -562,7 +562,8 @@ __f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused, \ \ c2c_left = container_of(left, struct c2c_hist_entry, he); \ c2c_right = container_of(right, struct c2c_hist_entry, he); \ - return c2c_left->stats.__f - c2c_right->stats.__f; \ + return (uint64_t) c2c_left->stats.__f - \ + (uint64_t) c2c_right->stats.__f; \ } #define STAT_FN(__f) \ @@ -615,7 +616,8 @@ ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused, c2c_left = container_of(left, struct c2c_hist_entry, he); c2c_right = container_of(right, struct c2c_hist_entry, he); - return llc_miss(&c2c_left->stats) - llc_miss(&c2c_right->stats); + return (uint64_t) llc_miss(&c2c_left->stats) - + (uint64_t) llc_miss(&c2c_right->stats); } static uint64_t total_records(struct c2c_stats *stats) -- GitLab From 1fa12145cd03de637939c6bc1d4df9fbb6116e33 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 5 Nov 2019 18:18:03 +0900 Subject: [PATCH 0740/1055] PM / devfreq: Add new name attribute for sysfs commit 2fee1a7cc6b1ce6634bb0f025be2c94a58dfa34d upstream. The commit 4585fbcb5331 ("PM / devfreq: Modify the device name as devfreq(X) for sysfs") changed the node name to devfreq(x). After this commit, it is not possible to get the device name through /sys/class/devfreq/devfreq(X)/*. Add new name attribute in order to get device name. Cc: stable@vger.kernel.org Fixes: 4585fbcb5331 ("PM / devfreq: Modify the device name as devfreq(X) for sysfs") Signed-off-by: Chanwoo Choi Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-class-devfreq | 7 +++++++ drivers/devfreq/devfreq.c | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq index ee39acacf6f8..335595a79866 100644 --- a/Documentation/ABI/testing/sysfs-class-devfreq +++ b/Documentation/ABI/testing/sysfs-class-devfreq @@ -7,6 +7,13 @@ Description: The name of devfreq object denoted as ... is same as the name of device using devfreq. +What: /sys/class/devfreq/.../name +Date: November 2019 +Contact: Chanwoo Choi +Description: + The /sys/class/devfreq/.../name shows the name of device + of the corresponding devfreq object. + What: /sys/class/devfreq/.../governor Date: September 2011 Contact: MyungJoo Ham diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index ad18de955b6c..58ec3abfd321 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -902,6 +902,14 @@ int devfreq_remove_governor(struct devfreq_governor *governor) } EXPORT_SYMBOL(devfreq_remove_governor); +static ssize_t name_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct devfreq *devfreq = to_devfreq(dev); + return sprintf(buf, "%s\n", dev_name(devfreq->dev.parent)); +} +static DEVICE_ATTR_RO(name); + static ssize_t governor_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1200,6 +1208,7 @@ static ssize_t trans_stat_show(struct device *dev, static DEVICE_ATTR_RO(trans_stat); static struct attribute *devfreq_attrs[] = { + &dev_attr_name.attr, &dev_attr_governor.attr, &dev_attr_available_governors.attr, &dev_attr_cur_freq.attr, -- GitLab From 44d8703769f363593b41d51aeaac6ddeee8bc7da Mon Sep 17 00:00:00 2001 From: Vitaly Chikunov Date: Tue, 24 Dec 2019 20:20:29 +0300 Subject: [PATCH 0741/1055] tools lib: Fix builds when glibc contains strlcpy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6c4798d3f08b81c2c52936b10e0fa872590c96ae upstream. Disable a couple of compilation warnings (which are treated as errors) on strlcpy() definition and declaration, allowing users to compile perf and kernel (objtool) when: 1. glibc have strlcpy() (such as in ALT Linux since 2004) objtool and perf build fails with this (in gcc): In file included from exec-cmd.c:3: tools/include/linux/string.h:20:15: error: redundant redeclaration of ‘strlcpy’ [-Werror=redundant-decls] 20 | extern size_t strlcpy(char *dest, const char *src, size_t size); 2. clang ignores `-Wredundant-decls', but produces another warning when building perf: CC util/string.o ../lib/string.c:99:8: error: attribute declaration must precede definition [-Werror,-Wignored-attributes] size_t __weak strlcpy(char *dest, const char *src, size_t size) ../../tools/include/linux/compiler.h:66:34: note: expanded from macro '__weak' # define __weak __attribute__((weak)) /usr/include/bits/string_fortified.h:151:8: note: previous definition is here __NTH (strlcpy (char *__restrict __dest, const char *__restrict __src, Committer notes: The #pragma GCC diagnostic directive was introduced in gcc 4.6, so check for that as well. Fixes: ce99091 ("perf tools: Move strlcpy() from perf to tools/lib/string.c") Fixes: 0215d59 ("tools lib: Reinstate strlcpy() header guard with __UCLIBC__") Resolves: https://bugzilla.kernel.org/show_bug.cgi?id=118481 Signed-off-by: Vitaly Chikunov Reviewed-by: Dmitry Levin Cc: Dmitry Levin Cc: Josh Poimboeuf Cc: kbuild test robot Cc: Peter Zijlstra Cc: stable@vger.kernel.org Cc: Vineet Gupta Link: http://lore.kernel.org/lkml/20191224172029.19690-1-vt@altlinux.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/include/linux/string.h | 8 ++++++++ tools/lib/string.c | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/tools/include/linux/string.h b/tools/include/linux/string.h index 6c3e2cc274c5..0ec646f127dc 100644 --- a/tools/include/linux/string.h +++ b/tools/include/linux/string.h @@ -14,7 +14,15 @@ int strtobool(const char *s, bool *res); * However uClibc headers also define __GLIBC__ hence the hack below */ #if defined(__GLIBC__) && !defined(__UCLIBC__) +// pragma diagnostic was introduced in gcc 4.6 +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +#endif extern size_t strlcpy(char *dest, const char *src, size_t size); +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#pragma GCC diagnostic pop +#endif #endif char *str_error_r(int errnum, char *buf, size_t buflen); diff --git a/tools/lib/string.c b/tools/lib/string.c index 93b3d4b6feac..ee0afcbdd696 100644 --- a/tools/lib/string.c +++ b/tools/lib/string.c @@ -95,6 +95,10 @@ int strtobool(const char *s, bool *res) * If libc has strlcpy() then that version will override this * implementation: */ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wignored-attributes" +#endif size_t __weak strlcpy(char *dest, const char *src, size_t size) { size_t ret = strlen(src); @@ -106,3 +110,6 @@ size_t __weak strlcpy(char *dest, const char *src, size_t size) } return ret; } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif -- GitLab From 64700ad97eab8b533afd5dbfff22266b68900e35 Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Tue, 21 Jan 2020 16:54:39 +0100 Subject: [PATCH 0742/1055] arm64: kbuild: remove compressed images on 'make ARCH=arm64 (dist)clean' commit d7bbd6c1b01cb5dd13c245d4586a83145c1d5f52 upstream. Since v4.3-rc1 commit 0723c05fb75e44 ("arm64: enable more compressed Image formats"), it is possible to build Image.{bz2,lz4,lzma,lzo} AArch64 images. However, the commit missed adding support for removing those images on 'make ARCH=arm64 (dist)clean'. Fix this by adding them to the target list. Make sure to match the order of the recipes in the makefile. Cc: stable@vger.kernel.org # v4.3+ Fixes: 0723c05fb75e44 ("arm64: enable more compressed Image formats") Signed-off-by: Dirk Behme Signed-off-by: Eugeniu Rosca Reviewed-by: Masahiro Yamada Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile index 1f012c506434..cd3414898d10 100644 --- a/arch/arm64/boot/Makefile +++ b/arch/arm64/boot/Makefile @@ -16,7 +16,7 @@ OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S -targets := Image Image.gz +targets := Image Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo $(obj)/Image: vmlinux FORCE $(call if_changed,objcopy) -- GitLab From 08e4a312439c294b9753166537baf3cc0bd6bb07 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 15 Dec 2019 01:09:03 -0500 Subject: [PATCH 0743/1055] ext4: validate the debug_want_extra_isize mount option at parse time commit 9803387c55f7d2ce69aa64340c5fdc6b3027dbc8 upstream. Instead of setting s_want_extra_size and then making sure that it is a valid value afterwards, validate the field before we set it. This avoids races and other problems when remounting the file system. Link: https://lore.kernel.org/r/20191215063020.GA11512@mit.edu Cc: stable@kernel.org Signed-off-by: Theodore Ts'o Reported-and-tested-by: syzbot+4a39a025912b265cacef@syzkaller.appspotmail.com Signed-off-by: Zubin Mithra Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 127 +++++++++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 61 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 1a0a56647974..93d8aa6ef661 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1782,6 +1782,13 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token, arg = JBD2_DEFAULT_MAX_COMMIT_AGE; sbi->s_commit_interval = HZ * arg; } else if (token == Opt_debug_want_extra_isize) { + if ((arg & 1) || + (arg < 4) || + (arg > (sbi->s_inode_size - EXT4_GOOD_OLD_INODE_SIZE))) { + ext4_msg(sb, KERN_ERR, + "Invalid want_extra_isize %d", arg); + return -1; + } sbi->s_want_extra_isize = arg; } else if (token == Opt_max_batch_time) { sbi->s_max_batch_time = arg; @@ -3454,40 +3461,6 @@ int ext4_calculate_overhead(struct super_block *sb) return 0; } -static void ext4_clamp_want_extra_isize(struct super_block *sb) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - unsigned def_extra_isize = sizeof(struct ext4_inode) - - EXT4_GOOD_OLD_INODE_SIZE; - - if (sbi->s_inode_size == EXT4_GOOD_OLD_INODE_SIZE) { - sbi->s_want_extra_isize = 0; - return; - } - if (sbi->s_want_extra_isize < 4) { - sbi->s_want_extra_isize = def_extra_isize; - if (ext4_has_feature_extra_isize(sb)) { - if (sbi->s_want_extra_isize < - le16_to_cpu(es->s_want_extra_isize)) - sbi->s_want_extra_isize = - le16_to_cpu(es->s_want_extra_isize); - if (sbi->s_want_extra_isize < - le16_to_cpu(es->s_min_extra_isize)) - sbi->s_want_extra_isize = - le16_to_cpu(es->s_min_extra_isize); - } - } - /* Check if enough inode space is available */ - if ((sbi->s_want_extra_isize > sbi->s_inode_size) || - (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize > - sbi->s_inode_size)) { - sbi->s_want_extra_isize = def_extra_isize; - ext4_msg(sb, KERN_INFO, - "required extra inode space not available"); - } -} - static void ext4_set_resv_clusters(struct super_block *sb) { ext4_fsblk_t resv_clusters; @@ -3695,6 +3668,65 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) */ sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT; + if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) { + sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE; + sbi->s_first_ino = EXT4_GOOD_OLD_FIRST_INO; + } else { + sbi->s_inode_size = le16_to_cpu(es->s_inode_size); + sbi->s_first_ino = le32_to_cpu(es->s_first_ino); + if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) { + ext4_msg(sb, KERN_ERR, "invalid first ino: %u", + sbi->s_first_ino); + goto failed_mount; + } + if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || + (!is_power_of_2(sbi->s_inode_size)) || + (sbi->s_inode_size > blocksize)) { + ext4_msg(sb, KERN_ERR, + "unsupported inode size: %d", + sbi->s_inode_size); + goto failed_mount; + } + /* + * i_atime_extra is the last extra field available for + * [acm]times in struct ext4_inode. Checking for that + * field should suffice to ensure we have extra space + * for all three. + */ + if (sbi->s_inode_size >= offsetof(struct ext4_inode, i_atime_extra) + + sizeof(((struct ext4_inode *)0)->i_atime_extra)) { + sb->s_time_gran = 1; + } else { + sb->s_time_gran = NSEC_PER_SEC; + } + } + if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) { + sbi->s_want_extra_isize = sizeof(struct ext4_inode) - + EXT4_GOOD_OLD_INODE_SIZE; + if (ext4_has_feature_extra_isize(sb)) { + unsigned v, max = (sbi->s_inode_size - + EXT4_GOOD_OLD_INODE_SIZE); + + v = le16_to_cpu(es->s_want_extra_isize); + if (v > max) { + ext4_msg(sb, KERN_ERR, + "bad s_want_extra_isize: %d", v); + goto failed_mount; + } + if (sbi->s_want_extra_isize < v) + sbi->s_want_extra_isize = v; + + v = le16_to_cpu(es->s_min_extra_isize); + if (v > max) { + ext4_msg(sb, KERN_ERR, + "bad s_min_extra_isize: %d", v); + goto failed_mount; + } + if (sbi->s_want_extra_isize < v) + sbi->s_want_extra_isize = v; + } + } + if (sbi->s_es->s_mount_opts[0]) { char *s_mount_opts = kstrndup(sbi->s_es->s_mount_opts, sizeof(sbi->s_es->s_mount_opts), @@ -3893,29 +3925,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) has_huge_files); sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files); - if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) { - sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE; - sbi->s_first_ino = EXT4_GOOD_OLD_FIRST_INO; - } else { - sbi->s_inode_size = le16_to_cpu(es->s_inode_size); - sbi->s_first_ino = le32_to_cpu(es->s_first_ino); - if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) { - ext4_msg(sb, KERN_ERR, "invalid first ino: %u", - sbi->s_first_ino); - goto failed_mount; - } - if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || - (!is_power_of_2(sbi->s_inode_size)) || - (sbi->s_inode_size > blocksize)) { - ext4_msg(sb, KERN_ERR, - "unsupported inode size: %d", - sbi->s_inode_size); - goto failed_mount; - } - if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) - sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2); - } - sbi->s_desc_size = le16_to_cpu(es->s_desc_size); if (ext4_has_feature_64bit(sb)) { if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT || @@ -4354,8 +4363,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) if (ext4_setup_super(sb, es, sb_rdonly(sb))) sb->s_flags |= MS_RDONLY; - ext4_clamp_want_extra_isize(sb); - ext4_set_resv_clusters(sb); err = ext4_setup_system_zone(sb); @@ -5139,8 +5146,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) goto restore_opts; } - ext4_clamp_want_extra_isize(sb); - if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^ test_opt(sb, JOURNAL_CHECKSUM)) { ext4_msg(sb, KERN_ERR, "changing journal_checksum " -- GitLab From 569ae81e2ed8eab6c3b99d7364ef129f8c21f193 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 30 Jan 2020 22:11:07 -0800 Subject: [PATCH 0744/1055] mm/mempolicy.c: fix out of bounds write in mpol_parse_str() commit c7a91bc7c2e17e0a9c8b9745a2cb118891218fd1 upstream. What we are trying to do is change the '=' character to a NUL terminator and then at the end of the function we restore it back to an '='. The problem is there are two error paths where we jump to the end of the function before we have replaced the '=' with NUL. We end up putting the '=' in the wrong place (possibly one element before the start of the buffer). Link: http://lkml.kernel.org/r/20200115055426.vdjwvry44nfug7yy@kili.mountain Reported-by: syzbot+e64a13c5369a194d67df@syzkaller.appspotmail.com Fixes: 095f1fc4ebf3 ("mempolicy: rework shmem mpol parsing and display") Signed-off-by: Dan Carpenter Acked-by: Vlastimil Babka Dmitry Vyukov Cc: Michal Hocko Cc: Dan Carpenter Cc: Lee Schermerhorn Cc: Andrea Arcangeli Cc: Hugh Dickins Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/mempolicy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index a37cfa88669e..1b34f2e35951 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2724,6 +2724,9 @@ int mpol_parse_str(char *str, struct mempolicy **mpol) char *flags = strchr(str, '='); int err = 1; + if (flags) + *flags++ = '\0'; /* terminate mode string */ + if (nodelist) { /* NUL-terminate mode or flags string */ *nodelist++ = '\0'; @@ -2734,9 +2737,6 @@ int mpol_parse_str(char *str, struct mempolicy **mpol) } else nodes_clear(nodes); - if (flags) - *flags++ = '\0'; /* terminate mode string */ - for (mode = 0; mode < MPOL_MAX; mode++) { if (!strcmp(str, policy_modes[mode])) { break; -- GitLab From 4397069f236d9d9888f23c0ed814c403f80bfd1c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 12 Dec 2019 11:30:03 +0100 Subject: [PATCH 0745/1055] reiserfs: Fix memory leak of journal device string commit 5474ca7da6f34fa95e82edc747d5faa19cbdfb5c upstream. When a filesystem is mounted with jdev mount option, we store the journal device name in an allocated string in superblock. However we fail to ever free that string. Fix it. Reported-by: syzbot+1c6756baf4b16b94d2a6@syzkaller.appspotmail.com Fixes: c3aa077648e1 ("reiserfs: Properly display mount options in /proc/mounts") CC: stable@vger.kernel.org Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/reiserfs/super.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index cc0b22c72e83..5208d85dd30c 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -629,6 +629,7 @@ static void reiserfs_put_super(struct super_block *s) reiserfs_write_unlock(s); mutex_destroy(&REISERFS_SB(s)->lock); destroy_workqueue(REISERFS_SB(s)->commit_wq); + kfree(REISERFS_SB(s)->s_jdev); kfree(s->s_fs_info); s->s_fs_info = NULL; } @@ -2243,6 +2244,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) kfree(qf_names[j]); } #endif + kfree(sbi->s_jdev); kfree(sbi); s->s_fs_info = NULL; -- GitLab From 2e0ebd897abc719448d9d10e3a7bbeac6294c30e Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 10 Nov 2019 11:04:40 +0100 Subject: [PATCH 0746/1055] media: digitv: don't continue if remote control state can't be read commit eecc70d22ae51225de1ef629c1159f7116476b2e upstream. This results in an uninitialized variable read. Reported-by: syzbot+6bf9606ee955b646c0e1@syzkaller.appspotmail.com Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/dvb-usb/digitv.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c index 475a3c0cdee7..20d33f0544ed 100644 --- a/drivers/media/usb/dvb-usb/digitv.c +++ b/drivers/media/usb/dvb-usb/digitv.c @@ -233,18 +233,22 @@ static struct rc_map_table rc_map_digitv_table[] = { static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { - int i; + int ret, i; u8 key[5]; u8 b[4] = { 0 }; *event = 0; *state = REMOTE_NO_KEY_PRESSED; - digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4); + ret = digitv_ctrl_msg(d, USB_READ_REMOTE, 0, NULL, 0, &key[1], 4); + if (ret) + return ret; /* Tell the device we've read the remote. Not sure how necessary this is, but the Nebula SDK does it. */ - digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0); + ret = digitv_ctrl_msg(d, USB_WRITE_REMOTE, 0, b, 4, NULL, 0); + if (ret) + return ret; /* if something is inside the buffer, simulate key press */ if (key[1] != 0) -- GitLab From b7fae41e420f3db83466b9dcd26e06ae706b85ab Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 10 Nov 2019 11:15:37 +0100 Subject: [PATCH 0747/1055] media: af9005: uninitialized variable printked commit 51d0c99b391f0cac61ad7b827c26f549ee55672c upstream. If usb_bulk_msg() fails, actual_length can be uninitialized. Reported-by: syzbot+9d42b7773d2fecd983ab@syzkaller.appspotmail.com Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/dvb-usb/af9005.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c index c047a0bdf91f..66990a193bc5 100644 --- a/drivers/media/usb/dvb-usb/af9005.c +++ b/drivers/media/usb/dvb-usb/af9005.c @@ -563,7 +563,7 @@ static int af9005_boot_packet(struct usb_device *udev, int type, u8 *reply, u8 *buf, int size) { u16 checksum; - int act_len, i, ret; + int act_len = 0, i, ret; memset(buf, 0, size); buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff); -- GitLab From 03a8533d9d06b029dcc8bb818a6ca30db7782ab3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 12 Nov 2019 10:22:24 +0100 Subject: [PATCH 0748/1055] media: gspca: zero usb_buf commit de89d0864f66c2a1b75becfdd6bf3793c07ce870 upstream. Allocate gspca_dev->usb_buf with kzalloc instead of kmalloc to ensure it is property zeroed. This fixes various syzbot errors about uninitialized data. Syzbot links: https://syzkaller.appspot.com/bug?extid=32310fc2aea76898d074 https://syzkaller.appspot.com/bug?extid=99706d6390be1ac542a2 https://syzkaller.appspot.com/bug?extid=64437af5c781a7f0e08e Reported-and-tested-by: syzbot+32310fc2aea76898d074@syzkaller.appspotmail.com Reported-and-tested-by: syzbot+99706d6390be1ac542a2@syzkaller.appspotmail.com Reported-and-tested-by: syzbot+64437af5c781a7f0e08e@syzkaller.appspotmail.com Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/gspca/gspca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 0f141762abf1..87582be4a39d 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -2038,7 +2038,7 @@ int gspca_dev_probe2(struct usb_interface *intf, pr_err("couldn't kzalloc gspca struct\n"); return -ENOMEM; } - gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL); + gspca_dev->usb_buf = kzalloc(USB_BUF_SZ, GFP_KERNEL); if (!gspca_dev->usb_buf) { pr_err("out of memory\n"); ret = -ENOMEM; -- GitLab From fb5e3b56c4c4cc7a83a5f8bd6e9869e53015e41c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 12 Nov 2019 10:22:28 +0100 Subject: [PATCH 0749/1055] media: dvb-usb/dvb-usb-urb.c: initialize actlen to 0 commit 569bc8d6a6a50acb5fcf07fb10b8d2d461fdbf93 upstream. This fixes a syzbot failure since actlen could be uninitialized, but it was still used. Syzbot link: https://syzkaller.appspot.com/bug?extid=6bf9606ee955b646c0e1 Reported-and-tested-by: syzbot+6bf9606ee955b646c0e1@syzkaller.appspotmail.com Signed-off-by: Hans Verkuil Acked-by: Sean Young Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/dvb-usb/dvb-usb-urb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb/dvb-usb-urb.c b/drivers/media/usb/dvb-usb/dvb-usb-urb.c index c1b4e94a37f8..2aabf90d8697 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-urb.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-urb.c @@ -12,7 +12,7 @@ int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen, int delay_ms) { - int actlen,ret = -ENOMEM; + int actlen = 0, ret = -ENOMEM; if (!d || wbuf == NULL || wlen == 0) return -EINVAL; -- GitLab From ab84fd0d3dc83277d6ab7246a6b2cd45ba924367 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Mon, 13 Jan 2020 11:48:42 +0800 Subject: [PATCH 0750/1055] ttyprintk: fix a potential deadlock in interrupt context issue commit 9a655c77ff8fc65699a3f98e237db563b37c439b upstream. tpk_write()/tpk_close() could be interrupted when holding a mutex, then in timer handler tpk_write() may be called again trying to acquire same mutex, lead to deadlock. Google syzbot reported this issue with CONFIG_DEBUG_ATOMIC_SLEEP enabled: BUG: sleeping function called from invalid context at kernel/locking/mutex.c:938 in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 0, name: swapper/1 1 lock held by swapper/1/0: ... Call Trace: dump_stack+0x197/0x210 ___might_sleep.cold+0x1fb/0x23e __might_sleep+0x95/0x190 __mutex_lock+0xc5/0x13c0 mutex_lock_nested+0x16/0x20 tpk_write+0x5d/0x340 resync_tnc+0x1b6/0x320 call_timer_fn+0x1ac/0x780 run_timer_softirq+0x6c3/0x1790 __do_softirq+0x262/0x98c irq_exit+0x19b/0x1e0 smp_apic_timer_interrupt+0x1a3/0x610 apic_timer_interrupt+0xf/0x20 See link https://syzkaller.appspot.com/bug?extid=2eeef62ee31f9460ad65 for more details. Fix it by using spinlock in process context instead of mutex and having interrupt disabled in critical section. Reported-by: syzbot+2eeef62ee31f9460ad65@syzkaller.appspotmail.com Signed-off-by: Zhenzhong Duan Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20200113034842.435-1-zhenzhong.duan@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/char/ttyprintk.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 67549ce88cc9..774748497ace 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -18,10 +18,11 @@ #include #include #include +#include struct ttyprintk_port { struct tty_port port; - struct mutex port_write_mutex; + spinlock_t spinlock; }; static struct ttyprintk_port tpk_port; @@ -100,11 +101,12 @@ static int tpk_open(struct tty_struct *tty, struct file *filp) static void tpk_close(struct tty_struct *tty, struct file *filp) { struct ttyprintk_port *tpkp = tty->driver_data; + unsigned long flags; - mutex_lock(&tpkp->port_write_mutex); + spin_lock_irqsave(&tpkp->spinlock, flags); /* flush tpk_printk buffer */ tpk_printk(NULL, 0); - mutex_unlock(&tpkp->port_write_mutex); + spin_unlock_irqrestore(&tpkp->spinlock, flags); tty_port_close(&tpkp->port, tty, filp); } @@ -116,13 +118,14 @@ static int tpk_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct ttyprintk_port *tpkp = tty->driver_data; + unsigned long flags; int ret; /* exclusive use of tpk_printk within this tty */ - mutex_lock(&tpkp->port_write_mutex); + spin_lock_irqsave(&tpkp->spinlock, flags); ret = tpk_printk(buf, count); - mutex_unlock(&tpkp->port_write_mutex); + spin_unlock_irqrestore(&tpkp->spinlock, flags); return ret; } @@ -172,7 +175,7 @@ static int __init ttyprintk_init(void) { int ret = -ENOMEM; - mutex_init(&tpk_port.port_write_mutex); + spin_lock_init(&tpk_port.spinlock); ttyprintk_driver = tty_alloc_driver(1, TTY_DRIVER_RESET_TERMIOS | -- GitLab From 58e957b9c7c22e89188558c27437b6e9a2ddae3d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 15 Jan 2020 20:49:04 +0300 Subject: [PATCH 0751/1055] Bluetooth: Fix race condition in hci_release_sock() commit 11eb85ec42dc8c7a7ec519b90ccf2eeae9409de8 upstream. Syzbot managed to trigger a use after free "KASAN: use-after-free Write in hci_sock_bind". I have reviewed the code manually and one possibly cause I have found is that we are not holding lock_sock(sk) when we do the hci_dev_put(hdev) in hci_sock_release(). My theory is that the bind and the release are racing against each other which results in this use after free. Reported-by: syzbot+eba992608adf3d796bcc@syzkaller.appspotmail.com Signed-off-by: Dan Carpenter Signed-off-by: Johan Hedberg Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hci_sock.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 4a05235929b9..93093d7c3824 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -826,6 +826,8 @@ static int hci_sock_release(struct socket *sock) if (!sk) return 0; + lock_sock(sk); + switch (hci_pi(sk)->channel) { case HCI_CHANNEL_MONITOR: atomic_dec(&monitor_promisc); @@ -873,6 +875,7 @@ static int hci_sock_release(struct socket *sock) skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sk->sk_write_queue); + release_sock(sk); sock_put(sk); return 0; } -- GitLab From 060af799ef5a17a4a6dc3e95c1bacb51fa6ebec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Koutn=C3=BD?= Date: Thu, 9 Jan 2020 16:05:59 +0100 Subject: [PATCH 0752/1055] cgroup: Prevent double killing of css when enabling threaded cgroup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 3bc0bb36fa30e95ca829e9cf480e1ef7f7638333 upstream. The test_cgcore_no_internal_process_constraint_on_threads selftest when running with subsystem controlling noise triggers two warnings: > [ 597.443115] WARNING: CPU: 1 PID: 28167 at kernel/cgroup/cgroup.c:3131 cgroup_apply_control_enable+0xe0/0x3f0 > [ 597.443413] WARNING: CPU: 1 PID: 28167 at kernel/cgroup/cgroup.c:3177 cgroup_apply_control_disable+0xa6/0x160 Both stem from a call to cgroup_type_write. The first warning was also triggered by syzkaller. When we're switching cgroup to threaded mode shortly after a subsystem was disabled on it, we can see the respective subsystem css dying there. The warning in cgroup_apply_control_enable is harmless in this case since we're not adding new subsys anyway. The warning in cgroup_apply_control_disable indicates an attempt to kill css of recently disabled subsystem repeatedly. The commit prevents these situations by making cgroup_type_write wait for all dying csses to go away before re-applying subtree controls. When at it, the locations of WARN_ON_ONCE calls are moved so that warning is triggered only when we are about to misuse the dying css. Reported-by: syzbot+5493b2a54d31d6aea629@syzkaller.appspotmail.com Reported-by: Christian Brauner Signed-off-by: Michal Koutný Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- kernel/cgroup/cgroup.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 2c57030f54aa..829943aad7be 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -2884,8 +2884,6 @@ static int cgroup_apply_control_enable(struct cgroup *cgrp) for_each_subsys(ss, ssid) { struct cgroup_subsys_state *css = cgroup_css(dsct, ss); - WARN_ON_ONCE(css && percpu_ref_is_dying(&css->refcnt)); - if (!(cgroup_ss_mask(dsct) & (1 << ss->id))) continue; @@ -2895,6 +2893,8 @@ static int cgroup_apply_control_enable(struct cgroup *cgrp) return PTR_ERR(css); } + WARN_ON_ONCE(percpu_ref_is_dying(&css->refcnt)); + if (css_visible(css)) { ret = css_populate_dir(css); if (ret) @@ -2930,11 +2930,11 @@ static void cgroup_apply_control_disable(struct cgroup *cgrp) for_each_subsys(ss, ssid) { struct cgroup_subsys_state *css = cgroup_css(dsct, ss); - WARN_ON_ONCE(css && percpu_ref_is_dying(&css->refcnt)); - if (!css) continue; + WARN_ON_ONCE(percpu_ref_is_dying(&css->refcnt)); + if (css->parent && !(cgroup_ss_mask(dsct) & (1 << ss->id))) { kill_css(css); @@ -3221,7 +3221,8 @@ static ssize_t cgroup_type_write(struct kernfs_open_file *of, char *buf, if (strcmp(strstrip(buf), "threaded")) return -EINVAL; - cgrp = cgroup_kn_lock_live(of->kn, false); + /* drain dying csses before we re-apply (threaded) subtree control */ + cgrp = cgroup_kn_lock_live(of->kn, true); if (!cgrp) return -ENOENT; -- GitLab From c7d812223d2241b331e60df738918f05b93173ac Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 3 Feb 2020 13:21:30 +0000 Subject: [PATCH 0753/1055] media: si470x-i2c: Move free() past last use of 'radio' A pointer to 'struct si470x_device' is currently used after free: drivers/media/radio/si470x/radio-si470x-i2c.c:462:25-30: ERROR: reference preceded by free on line 460 Shift the call to free() down past its final use. NB: Not sending to Mainline, since the problem does not exist there, it was caused by the backport of 2df200ab234a ("media: si470x-i2c: add missed operations in remove") to the stable trees. Cc: # v3.18+ Reported-by: kbuild test robot Reported-by: Julia Lawall Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/media/radio/si470x/radio-si470x-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index b60fb6ed5aeb..527535614342 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -453,10 +453,10 @@ static int si470x_i2c_remove(struct i2c_client *client) free_irq(client->irq, radio); video_unregister_device(&radio->videodev); - kfree(radio); v4l2_ctrl_handler_free(&radio->hdl); v4l2_device_unregister(&radio->v4l2_dev); + kfree(radio); return 0; } -- GitLab From 719e8e93e81e4398af2881388fb88000d3b76a1a Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 11 Dec 2019 15:52:17 +0100 Subject: [PATCH 0754/1055] ARM: dts: sun8i: a83t: Correct USB3503 GPIOs polarity [ Upstream commit 1c226017d3ec93547b58082bdf778d9db7401c95 ] Current USB3503 driver ignores GPIO polarity and always operates as if the GPIO lines were flagged as ACTIVE_HIGH. Fix the polarity for the existing USB3503 chip applications to match the chip specification and common convention for naming the pins. The only pin, which has to be ACTIVE_LOW is the reset pin. The remaining are ACTIVE_HIGH. This change allows later to fix the USB3503 driver to properly use generic GPIO bindings and read polarity from DT. Signed-off-by: Marek Szyprowski Signed-off-by: Maxime Ripard Signed-off-by: Sasha Levin --- arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts index 716a205c6dbb..1fed3231f5c1 100644 --- a/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts +++ b/arch/arm/boot/dts/sun8i-a83t-cubietruck-plus.dts @@ -90,7 +90,7 @@ initial-mode = <1>; /* initialize in HUB mode */ disabled-ports = <1>; intn-gpios = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */ - reset-gpios = <&pio 4 16 GPIO_ACTIVE_HIGH>; /* PE16 */ + reset-gpios = <&pio 4 16 GPIO_ACTIVE_LOW>; /* PE16 */ connect-gpios = <&pio 4 17 GPIO_ACTIVE_HIGH>; /* PE17 */ refclk-frequency = <19200000>; }; -- GitLab From f795e1f7b43490c482c9762287167aa64ce7f6f1 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Tue, 17 Dec 2019 14:21:24 +0530 Subject: [PATCH 0755/1055] ARM: dts: beagle-x15-common: Model 5V0 regulator [ Upstream commit e17e7c498d4f734df93c300441e100818ed58168 ] On am57xx-beagle-x15, 5V0 is connected to P16, P17, P18 and P19 connectors. On am57xx-evm, 5V0 regulator is used to get 3V6 regulator which is connected to the COMQ port. Model 5V0 regulator here in order for it to be used in am57xx-evm to model 3V6 regulator. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Tony Lindgren Signed-off-by: Sasha Levin --- .../boot/dts/am57xx-beagle-x15-common.dtsi | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi index 49aeecd312b4..d578a9f7e1a0 100644 --- a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi +++ b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi @@ -32,6 +32,27 @@ reg = <0x0 0x80000000 0x0 0x80000000>; }; + main_12v0: fixedregulator-main_12v0 { + /* main supply */ + compatible = "regulator-fixed"; + regulator-name = "main_12v0"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-always-on; + regulator-boot-on; + }; + + evm_5v0: fixedregulator-evm_5v0 { + /* Output of TPS54531D */ + compatible = "regulator-fixed"; + regulator-name = "evm_5v0"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&main_12v0>; + regulator-always-on; + regulator-boot-on; + }; + vdd_3v3: fixedregulator-vdd_3v3 { compatible = "regulator-fixed"; regulator-name = "vdd_3v3"; -- GitLab From 852c2bb979257581311ed3baa7911d012532951f Mon Sep 17 00:00:00 2001 From: Dave Gerlach Date: Wed, 11 Dec 2019 22:03:14 -0600 Subject: [PATCH 0756/1055] soc: ti: wkup_m3_ipc: Fix race condition with rproc_boot [ Upstream commit 03729cfa0d543bc996bf959e762ec999afc8f3d2 ] Any user of wkup_m3_ipc calls wkup_m3_ipc_get to get a handle and this checks the value of the static variable m3_ipc_state to see if the wkup_m3 is ready. Currently this is populated during probe before rproc_boot has been called, meaning there is a window of time that wkup_m3_ipc_get can return a valid handle but the wkup_m3 itself is not ready, leading to invalid IPC calls to the wkup_m3 and system instability. To avoid this, move the population of the m3_ipc_state variable until after rproc_boot has succeeded to guarantee a valid and usable handle is always returned. Reported-by: Suman Anna Signed-off-by: Dave Gerlach Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren Signed-off-by: Sasha Levin --- drivers/soc/ti/wkup_m3_ipc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index 369aef5e7228..651827c6ee6f 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -375,6 +375,8 @@ static void wkup_m3_rproc_boot_thread(struct wkup_m3_ipc *m3_ipc) ret = rproc_boot(m3_ipc->rproc); if (ret) dev_err(dev, "rproc_boot failed\n"); + else + m3_ipc_state = m3_ipc; do_exit(0); } @@ -461,8 +463,6 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev) goto err_put_rproc; } - m3_ipc_state = m3_ipc; - return 0; err_put_rproc: -- GitLab From 89f54ffd507359db9aef5e59e32312773fc72747 Mon Sep 17 00:00:00 2001 From: Markus Theil Date: Tue, 3 Dec 2019 19:06:44 +0100 Subject: [PATCH 0757/1055] mac80211: mesh: restrict airtime metric to peered established plinks [ Upstream commit 02a614499600af836137c3fbc4404cd96365fff2 ] The following warning is triggered every time an unestablished mesh peer gets dumped. Checks if a peer link is established before retrieving the airtime link metric. [ 9563.022567] WARNING: CPU: 0 PID: 6287 at net/mac80211/mesh_hwmp.c:345 airtime_link_metric_get+0xa2/0xb0 [mac80211] [ 9563.022697] Hardware name: PC Engines apu2/apu2, BIOS v4.10.0.3 [ 9563.022756] RIP: 0010:airtime_link_metric_get+0xa2/0xb0 [mac80211] [ 9563.022838] Call Trace: [ 9563.022897] sta_set_sinfo+0x936/0xa10 [mac80211] [ 9563.022964] ieee80211_dump_station+0x6d/0x90 [mac80211] [ 9563.023062] nl80211_dump_station+0x154/0x2a0 [cfg80211] [ 9563.023120] netlink_dump+0x17b/0x370 [ 9563.023130] netlink_recvmsg+0x2a4/0x480 [ 9563.023140] ____sys_recvmsg+0xa6/0x160 [ 9563.023154] ___sys_recvmsg+0x93/0xe0 [ 9563.023169] __sys_recvmsg+0x7e/0xd0 [ 9563.023210] do_syscall_64+0x4e/0x140 [ 9563.023217] entry_SYSCALL_64_after_hwframe+0x44/0xa9 Signed-off-by: Markus Theil Link: https://lore.kernel.org/r/20191203180644.70653-1-markus.theil@tu-ilmenau.de [rewrite commit message] Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/mac80211/mesh_hwmp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index fab0764c315f..994dde6e5f9d 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -326,6 +326,9 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, unsigned long fail_avg = ewma_mesh_fail_avg_read(&sta->mesh->fail_avg); + if (sta->mesh->plink_state != NL80211_PLINK_ESTAB) + return MAX_METRIC; + /* Try to get rate based on HW/SW RC algorithm. * Rate is returned in units of Kbps, correct this * to comply with airtime calculation units -- GitLab From aecd1fe0edacfd5d3ff3d4c0752bc89b83d13d72 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 18 Dec 2019 20:04:54 +0100 Subject: [PATCH 0758/1055] clk: mmp2: Fix the order of timer mux parents [ Upstream commit 8bea5ac0fbc5b2103f8779ddff216122e3c2e1ad ] Determined empirically, no documentation is available. The OLPC XO-1.75 laptop used parent 1, that one being VCTCXO/4 (65MHz), but thought it's a VCTCXO/2 (130MHz). The mmp2 timer driver, not knowing what is going on, ended up just dividing the rate as of commit f36797ee4380 ("ARM: mmp/mmp2: dt: enable the clock")' Link: https://lore.kernel.org/r/20191218190454.420358-3-lkundrak@v3.sk Signed-off-by: Lubomir Rintel Acked-by: Stephen Boyd Signed-off-by: Olof Johansson Signed-off-by: Sasha Levin --- drivers/clk/mmp/clk-of-mmp2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index d083b860f083..10689d8cd386 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -134,7 +134,7 @@ static DEFINE_SPINLOCK(ssp3_lock); static const char *ssp_parent_names[] = {"vctcxo_4", "vctcxo_2", "vctcxo", "pll1_16"}; static DEFINE_SPINLOCK(timer_lock); -static const char *timer_parent_names[] = {"clk32", "vctcxo_2", "vctcxo_4", "vctcxo"}; +static const char *timer_parent_names[] = {"clk32", "vctcxo_4", "vctcxo_2", "vctcxo"}; static DEFINE_SPINLOCK(reset_lock); -- GitLab From ca60e5ca55b860dafda4937c5a9631e149cbbb90 Mon Sep 17 00:00:00 2001 From: Radoslaw Tyl Date: Mon, 25 Nov 2019 15:24:52 +0100 Subject: [PATCH 0759/1055] ixgbevf: Remove limit of 10 entries for unicast filter list [ Upstream commit aa604651d523b1493988d0bf6710339f3ee60272 ] Currently, though the FDB entry is added to VF, it does not appear in RAR filters. VF driver only allows to add 10 entries. Attempting to add another causes an error. This patch removes limitation and allows use of all free RAR entries for the FDB if needed. Fixes: 46ec20ff7d ("ixgbevf: Add macvlan support in the set rx mode op") Signed-off-by: Radoslaw Tyl Acked-by: Paul Menzel Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index e238f6e85ab6..a7708e14aa5c 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -1858,11 +1858,6 @@ static int ixgbevf_write_uc_addr_list(struct net_device *netdev) struct ixgbe_hw *hw = &adapter->hw; int count = 0; - if ((netdev_uc_count(netdev)) > 10) { - pr_err("Too many unicast filters - No Space\n"); - return -ENOSPC; - } - if (!netdev_uc_empty(netdev)) { struct netdev_hw_addr *ha; -- GitLab From 0350ed7bccd87c9ce86c55f2c39b69d9f4c9a799 Mon Sep 17 00:00:00 2001 From: Cambda Zhu Date: Wed, 27 Nov 2019 17:03:55 +0800 Subject: [PATCH 0760/1055] ixgbe: Fix calculation of queue with VFs and flow director on interface flap [ Upstream commit 4fad78ad6422d9bca62135bbed8b6abc4cbb85b8 ] This patch fixes the calculation of queue when we restore flow director filters after resetting adapter. In ixgbe_fdir_filter_restore(), filter's vf may be zero which makes the queue outside of the rx_ring array. The calculation is changed to the same as ixgbe_add_ethtool_fdir_entry(). Signed-off-by: Cambda Zhu Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index e4c1e6345edd..ba184287e11f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -5131,7 +5131,7 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; struct hlist_node *node2; struct ixgbe_fdir_filter *filter; - u64 action; + u8 queue; spin_lock(&adapter->fdir_perfect_lock); @@ -5140,17 +5140,34 @@ static void ixgbe_fdir_filter_restore(struct ixgbe_adapter *adapter) hlist_for_each_entry_safe(filter, node2, &adapter->fdir_filter_list, fdir_node) { - action = filter->action; - if (action != IXGBE_FDIR_DROP_QUEUE && action != 0) - action = - (action >> ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF) - 1; + if (filter->action == IXGBE_FDIR_DROP_QUEUE) { + queue = IXGBE_FDIR_DROP_QUEUE; + } else { + u32 ring = ethtool_get_flow_spec_ring(filter->action); + u8 vf = ethtool_get_flow_spec_ring_vf(filter->action); + + if (!vf && (ring >= adapter->num_rx_queues)) { + e_err(drv, "FDIR restore failed without VF, ring: %u\n", + ring); + continue; + } else if (vf && + ((vf > adapter->num_vfs) || + ring >= adapter->num_rx_queues_per_pool)) { + e_err(drv, "FDIR restore failed with VF, vf: %hhu, ring: %u\n", + vf, ring); + continue; + } + + /* Map the ring onto the absolute queue index */ + if (!vf) + queue = adapter->rx_ring[ring]->reg_idx; + else + queue = ((vf - 1) * + adapter->num_rx_queues_per_pool) + ring; + } ixgbe_fdir_write_perfect_filter_82599(hw, - &filter->filter, - filter->sw_idx, - (action == IXGBE_FDIR_DROP_QUEUE) ? - IXGBE_FDIR_DROP_QUEUE : - adapter->rx_ring[action]->reg_idx); + &filter->filter, filter->sw_idx, queue); } spin_unlock(&adapter->fdir_perfect_lock); -- GitLab From 5c273c3a8bb00213dc6bfb3a1e941355bcdaa2d9 Mon Sep 17 00:00:00 2001 From: Manfred Rudigier Date: Wed, 4 Dec 2019 11:40:26 +0100 Subject: [PATCH 0761/1055] igb: Fix SGMII SFP module discovery for 100FX/LX. [ Upstream commit 5365ec1aeff5b9f2962a9c9b31d63f9dad7e0e2d ] Changing the link mode should also be done for 100BaseFX SGMII modules, otherwise they just don't work when the default link mode in CTRL_EXT coming from the EEPROM is SERDES. Additionally 100Base-LX SGMII SFP modules are also supported now, which was not the case before. Tested with an i210 using Flexoptix S.1303.2M.G 100FX and S.1303.10.G 100LX SGMII SFP modules. Signed-off-by: Manfred Rudigier Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin --- drivers/net/ethernet/intel/igb/e1000_82575.c | 8 ++------ drivers/net/ethernet/intel/igb/igb_ethtool.c | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index c37cc8bccf47..158c277ec353 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -562,7 +562,7 @@ static s32 igb_set_sfp_media_type_82575(struct e1000_hw *hw) dev_spec->module_plugged = true; if (eth_flags->e1000_base_lx || eth_flags->e1000_base_sx) { hw->phy.media_type = e1000_media_type_internal_serdes; - } else if (eth_flags->e100_base_fx) { + } else if (eth_flags->e100_base_fx || eth_flags->e100_base_lx) { dev_spec->sgmii_active = true; hw->phy.media_type = e1000_media_type_internal_serdes; } else if (eth_flags->e1000_base_t) { @@ -689,14 +689,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) break; } - /* do not change link mode for 100BaseFX */ - if (dev_spec->eth_flags.e100_base_fx) - break; - /* change current link mode setting */ ctrl_ext &= ~E1000_CTRL_EXT_LINK_MODE_MASK; - if (hw->phy.media_type == e1000_media_type_copper) + if (dev_spec->sgmii_active) ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_SGMII; else ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES; diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index d06a8db514d4..82028ce355fb 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -201,7 +201,7 @@ static int igb_get_link_ksettings(struct net_device *netdev, advertising &= ~ADVERTISED_1000baseKX_Full; } } - if (eth_flags->e100_base_fx) { + if (eth_flags->e100_base_fx || eth_flags->e100_base_lx) { supported |= SUPPORTED_100baseT_Full; advertising |= ADVERTISED_100baseT_Full; } -- GitLab From 3403f8652c453536da61efba3236b531d63701b9 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 13 Jan 2020 11:04:00 +0100 Subject: [PATCH 0762/1055] ASoC: sti: fix possible sleep-in-atomic [ Upstream commit ce780a47c3c01e1e179d0792df6b853a913928f1 ] Change mutex and spinlock management to avoid sleep in atomic issue. Signed-off-by: Arnaud Pouliquen Link: https://lore.kernel.org/r/20200113100400.30472-1-arnaud.pouliquen@st.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- sound/soc/sti/uniperif_player.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index d8b6936e544e..908f13623f8c 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -226,7 +226,6 @@ static void uni_player_set_channel_status(struct uniperif *player, * sampling frequency. If no sample rate is already specified, then * set one. */ - mutex_lock(&player->ctrl_lock); if (runtime) { switch (runtime->rate) { case 22050: @@ -303,7 +302,6 @@ static void uni_player_set_channel_status(struct uniperif *player, player->stream_settings.iec958.status[3 + (n * 4)] << 24; SET_UNIPERIF_CHANNEL_STA_REGN(player, n, status); } - mutex_unlock(&player->ctrl_lock); /* Update the channel status */ if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) @@ -365,8 +363,10 @@ static int uni_player_prepare_iec958(struct uniperif *player, SET_UNIPERIF_CTRL_ZERO_STUFF_HW(player); + mutex_lock(&player->ctrl_lock); /* Update the channel status */ uni_player_set_channel_status(player, runtime); + mutex_unlock(&player->ctrl_lock); /* Clear the user validity user bits */ SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0); @@ -598,7 +598,6 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, iec958->status[1] = ucontrol->value.iec958.status[1]; iec958->status[2] = ucontrol->value.iec958.status[2]; iec958->status[3] = ucontrol->value.iec958.status[3]; - mutex_unlock(&player->ctrl_lock); spin_lock_irqsave(&player->irq_lock, flags); if (player->substream && player->substream->runtime) @@ -608,6 +607,8 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, uni_player_set_channel_status(player, NULL); spin_unlock_irqrestore(&player->irq_lock, flags); + mutex_unlock(&player->ctrl_lock); + return 0; } -- GitLab From f5929c9f3a52a6137b8c5ed2007a4cd725ab7aaf Mon Sep 17 00:00:00 2001 From: Kristian Evensen Date: Mon, 13 Jan 2020 14:57:40 +0100 Subject: [PATCH 0763/1055] qmi_wwan: Add support for Quectel RM500Q MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit a9ff44f0e61d074f29770413fef6a5452be7b83e ] RM500Q is a 5G module from Quectel, supporting both standalone and non-standalone modes. The normal Quectel quirks apply (DTR and dynamic interface numbers). Signed-off-by: Kristian Evensen Acked-by: Bjørn Mork Signed-off-by: Jakub Kicinski Signed-off-by: Sasha Levin --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 4a984b76a60e..db70d4c5778a 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -999,6 +999,7 @@ static const struct usb_device_id products[] = { {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */ {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */ + {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ /* 3. Combined interface devices matching on interface number */ {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ -- GitLab From 8f6b2439a2b939d92b25201e456c7949a1f8ba79 Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Fri, 20 Dec 2019 10:14:32 +0000 Subject: [PATCH 0764/1055] wireless: fix enabling channel 12 for custom regulatory domain [ Upstream commit c4b9d655e445a8be0bff624aedea190606b5ebbc ] Commit e33e2241e272 ("Revert "cfg80211: Use 5MHz bandwidth by default when checking usable channels"") fixed a broken regulatory (leaving channel 12 open for AP where not permitted). Apply a similar fix to custom regulatory domain processing. Signed-off-by: Cathy Luo Signed-off-by: Ganapathi Bhat Link: https://lore.kernel.org/r/1576836859-8945-1-git-send-email-ganapathi.bhat@nxp.com [reword commit message, fix coding style, add a comment] Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/wireless/reg.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 804eac073b6b..e60a7dedfbf1 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1718,14 +1718,15 @@ static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) static void handle_channel_custom(struct wiphy *wiphy, struct ieee80211_channel *chan, - const struct ieee80211_regdomain *regd) + const struct ieee80211_regdomain *regd, + u32 min_bw) { u32 bw_flags = 0; const struct ieee80211_reg_rule *reg_rule = NULL; const struct ieee80211_power_rule *power_rule = NULL; u32 bw; - for (bw = MHZ_TO_KHZ(20); bw >= MHZ_TO_KHZ(5); bw = bw / 2) { + for (bw = MHZ_TO_KHZ(20); bw >= min_bw; bw = bw / 2) { reg_rule = freq_reg_info_regd(MHZ_TO_KHZ(chan->center_freq), regd, bw); if (!IS_ERR(reg_rule)) @@ -1781,8 +1782,14 @@ static void handle_band_custom(struct wiphy *wiphy, if (!sband) return; + /* + * We currently assume that you always want at least 20 MHz, + * otherwise channel 12 might get enabled if this rule is + * compatible to US, which permits 2402 - 2472 MHz. + */ for (i = 0; i < sband->n_channels; i++) - handle_channel_custom(wiphy, &sband->channels[i], regd); + handle_channel_custom(wiphy, &sband->channels[i], regd, + MHZ_TO_KHZ(20)); } /* Used by drivers prior to wiphy registration */ -- GitLab From 2dbb6faebb94d6d5ae87e5ea6be9280c366393e1 Mon Sep 17 00:00:00 2001 From: Orr Mazor Date: Sun, 22 Dec 2019 14:55:31 +0000 Subject: [PATCH 0765/1055] cfg80211: Fix radar event during another phy CAC [ Upstream commit 26ec17a1dc5ecdd8d91aba63ead6f8b5ad5dea0d ] In case a radar event of CAC_FINISHED or RADAR_DETECTED happens during another phy is during CAC we might need to cancel that CAC. If we got a radar in a channel that another phy is now doing CAC on then the CAC should be canceled there. If, for example, 2 phys doing CAC on the same channels, or on comptable channels, once on of them will finish his CAC the other might need to cancel his CAC, since it is no longer relevant. To fix that the commit adds an callback and implement it in mac80211 to end CAC. This commit also adds a call to said callback if after a radar event we see the CAC is no longer relevant Signed-off-by: Orr Mazor Reviewed-by: Sergey Matyukevich Link: https://lore.kernel.org/r/20191222145449.15792-1-Orr.Mazor@tandemg.com [slightly reformat/reword commit message] Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- include/net/cfg80211.h | 5 +++++ net/mac80211/cfg.c | 23 +++++++++++++++++++++++ net/wireless/rdev-ops.h | 10 ++++++++++ net/wireless/reg.c | 23 ++++++++++++++++++++++- net/wireless/trace.h | 5 +++++ 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a4c8e9d7dd06..030eea38f258 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2843,6 +2843,9 @@ struct cfg80211_pmk_conf { * * @start_radar_detection: Start radar detection in the driver. * + * @end_cac: End running CAC, probably because a related CAC + * was finished on another phy. + * * @update_ft_ies: Provide updated Fast BSS Transition information to the * driver. If the SME is in the driver/firmware, this information can be * used in building Authentication and Reassociation Request frames. @@ -3148,6 +3151,8 @@ struct cfg80211_ops { struct net_device *dev, struct cfg80211_chan_def *chandef, u32 cac_time_ms); + void (*end_cac)(struct wiphy *wiphy, + struct net_device *dev); int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_update_ft_ies_params *ftie); int (*crit_proto_start)(struct wiphy *wiphy, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d437007b15bb..b1484b8316e8 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2800,6 +2800,28 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy, return err; } +static void ieee80211_end_cac(struct wiphy *wiphy, + struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + + mutex_lock(&local->mtx); + list_for_each_entry(sdata, &local->interfaces, list) { + /* it might be waiting for the local->mtx, but then + * by the time it gets it, sdata->wdev.cac_started + * will no longer be true + */ + cancel_delayed_work(&sdata->dfs_cac_timer_work); + + if (sdata->wdev.cac_started) { + ieee80211_vif_release_channel(sdata); + sdata->wdev.cac_started = false; + } + } + mutex_unlock(&local->mtx); +} + static struct cfg80211_beacon_data * cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon) { @@ -3730,6 +3752,7 @@ const struct cfg80211_ops mac80211_config_ops = { #endif .get_channel = ieee80211_cfg_get_channel, .start_radar_detection = ieee80211_start_radar_detection, + .end_cac = ieee80211_end_cac, .channel_switch = ieee80211_channel_switch, .set_qos_map = ieee80211_set_qos_map, .set_ap_chanwidth = ieee80211_set_ap_chanwidth, diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 249919bdfc64..4077bb3af440 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1143,6 +1143,16 @@ rdev_start_radar_detection(struct cfg80211_registered_device *rdev, return ret; } +static inline void +rdev_end_cac(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + trace_rdev_end_cac(&rdev->wiphy, dev); + if (rdev->ops->end_cac) + rdev->ops->end_cac(&rdev->wiphy, dev); + trace_rdev_return_void(&rdev->wiphy); +} + static inline int rdev_set_mcast_rate(struct cfg80211_registered_device *rdev, struct net_device *dev, diff --git a/net/wireless/reg.c b/net/wireless/reg.c index e60a7dedfbf1..a520f433d476 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -3303,6 +3303,25 @@ bool regulatory_pre_cac_allowed(struct wiphy *wiphy) return pre_cac_allowed; } +static void cfg80211_check_and_end_cac(struct cfg80211_registered_device *rdev) +{ + struct wireless_dev *wdev; + /* If we finished CAC or received radar, we should end any + * CAC running on the same channels. + * the check !cfg80211_chandef_dfs_usable contain 2 options: + * either all channels are available - those the CAC_FINISHED + * event has effected another wdev state, or there is a channel + * in unavailable state in wdev chandef - those the RADAR_DETECTED + * event has effected another wdev state. + * In both cases we should end the CAC on the wdev. + */ + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { + if (wdev->cac_started && + !cfg80211_chandef_dfs_usable(&rdev->wiphy, &wdev->chandef)) + rdev_end_cac(rdev, wdev->netdev); + } +} + void regulatory_propagate_dfs_state(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, enum nl80211_dfs_state dfs_state, @@ -3329,8 +3348,10 @@ void regulatory_propagate_dfs_state(struct wiphy *wiphy, cfg80211_set_dfs_state(&rdev->wiphy, chandef, dfs_state); if (event == NL80211_RADAR_DETECTED || - event == NL80211_RADAR_CAC_FINISHED) + event == NL80211_RADAR_CAC_FINISHED) { cfg80211_sched_dfs_chan_update(rdev); + cfg80211_check_and_end_cac(rdev); + } nl80211_radar_notify(rdev, chandef, event, NULL, GFP_KERNEL); } diff --git a/net/wireless/trace.h b/net/wireless/trace.h index f3353fe5b35b..cd0a1c7c185d 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -607,6 +607,11 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_flush_pmksa, TP_ARGS(wiphy, netdev) ); +DEFINE_EVENT(wiphy_netdev_evt, rdev_end_cac, + TP_PROTO(struct wiphy *wiphy, struct net_device *netdev), + TP_ARGS(wiphy, netdev) +); + DECLARE_EVENT_CLASS(station_add_change, TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u8 *mac, struct station_parameters *params), -- GitLab From 0a4b3ef53f0a237672b842b639284ac6ca6ef9b7 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 7 Jan 2020 17:35:45 +0200 Subject: [PATCH 0766/1055] mac80211: Fix TKIP replay protection immediately after key setup [ Upstream commit 6f601265215a421f425ba3a4850a35861d024643 ] TKIP replay protection was skipped for the very first frame received after a new key is configured. While this is potentially needed to avoid dropping a frame in some cases, this does leave a window for replay attacks with group-addressed frames at the station side. Any earlier frame sent by the AP using the same key would be accepted as a valid frame and the internal RSC would then be updated to the TSC from that frame. This would allow multiple previously transmitted group-addressed frames to be replayed until the next valid new group-addressed frame from the AP is received by the station. Fix this by limiting the no-replay-protection exception to apply only for the case where TSC=0, i.e., when this is for the very first frame protected using the new key, and the local RSC had not been set to a higher value when configuring the key (which may happen with GTK). Signed-off-by: Jouni Malinen Link: https://lore.kernel.org/r/20200107153545.10934-1-j@w1.fi Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/mac80211/tkip.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index b3622823bad2..ebd66e8f46b3 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -266,9 +266,21 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, if ((keyid >> 6) != key->conf.keyidx) return TKIP_DECRYPT_INVALID_KEYIDX; - if (rx_ctx->ctx.state != TKIP_STATE_NOT_INIT && - (iv32 < rx_ctx->iv32 || - (iv32 == rx_ctx->iv32 && iv16 <= rx_ctx->iv16))) + /* Reject replays if the received TSC is smaller than or equal to the + * last received value in a valid message, but with an exception for + * the case where a new key has been set and no valid frame using that + * key has yet received and the local RSC was initialized to 0. This + * exception allows the very first frame sent by the transmitter to be + * accepted even if that transmitter were to use TSC 0 (IEEE 802.11 + * described TSC to be initialized to 1 whenever a new key is taken into + * use). + */ + if (iv32 < rx_ctx->iv32 || + (iv32 == rx_ctx->iv32 && + (iv16 < rx_ctx->iv16 || + (iv16 == rx_ctx->iv16 && + (rx_ctx->iv32 || rx_ctx->iv16 || + rx_ctx->ctx.state != TKIP_STATE_NOT_INIT))))) return TKIP_DECRYPT_REPLAY; if (only_iv) { -- GitLab From 95f5057bb1a300e840e697463003cb242fa491bd Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 7 Jan 2020 21:07:35 +0100 Subject: [PATCH 0767/1055] wireless: wext: avoid gcc -O3 warning [ Upstream commit e16119655c9e6c4aa5767cd971baa9c491f41b13 ] After the introduction of CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3, the wext code produces a bogus warning: In function 'iw_handler_get_iwstats', inlined from 'ioctl_standard_call' at net/wireless/wext-core.c:1015:9, inlined from 'wireless_process_ioctl' at net/wireless/wext-core.c:935:10, inlined from 'wext_ioctl_dispatch.part.8' at net/wireless/wext-core.c:986:8, inlined from 'wext_handle_ioctl': net/wireless/wext-core.c:671:3: error: argument 1 null where non-null expected [-Werror=nonnull] memcpy(extra, stats, sizeof(struct iw_statistics)); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from arch/x86/include/asm/string.h:5, net/wireless/wext-core.c: In function 'wext_handle_ioctl': arch/x86/include/asm/string_64.h:14:14: note: in a call to function 'memcpy' declared here The problem is that ioctl_standard_call() sometimes calls the handler with a NULL argument that would cause a problem for iw_handler_get_iwstats. However, iw_handler_get_iwstats never actually gets called that way. Marking that function as noinline avoids the warning and leads to slightly smaller object code as well. Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20200107200741.3588770-1-arnd@arndb.de Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin --- net/wireless/wext-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index 6cdb054484d6..5236a3c2c0cc 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -659,7 +659,8 @@ struct iw_statistics *get_wireless_stats(struct net_device *dev) return NULL; } -static int iw_handler_get_iwstats(struct net_device * dev, +/* noinline to avoid a bogus warning with -O3 */ +static noinline int iw_handler_get_iwstats(struct net_device * dev, struct iw_request_info * info, union iwreq_data * wrqu, char * extra) -- GitLab From dc2e1d86500c904f7a4f730ad0481bb42f2f6188 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 16 Jan 2020 12:55:48 -0800 Subject: [PATCH 0768/1055] net: dsa: bcm_sf2: Configure IMP port for 2Gb/sec [ Upstream commit 8f1880cbe8d0d49ebb7e9ae409b3b96676e5aa97 ] With the implementation of the system reset controller we lost a setting that is currently applied by the bootloader and which configures the IMP port for 2Gb/sec, the default is 1Gb/sec. This is needed given the number of ports and applications we expect to run so bring back that setting. Fixes: 01b0ac07589e ("net: dsa: bcm_sf2: Add support for optional reset controller line") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/dsa/bcm_sf2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 94ad2fdd6ef0..05440b727261 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -137,7 +137,7 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port) /* Force link status for IMP port */ reg = core_readl(priv, offset); - reg |= (MII_SW_OR | LINK_STS); + reg |= (MII_SW_OR | LINK_STS | GMII_SPEED_UP_2G); core_writel(priv, reg, offset); /* Enable Broadcast, Multicast, Unicast forwarding to IMP port */ -- GitLab From e99b5648c7a719e5bf4431ed59ab6e98485268e9 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 17 Jan 2020 00:32:46 -0500 Subject: [PATCH 0769/1055] bnxt_en: Fix ipv6 RFS filter matching logic. [ Upstream commit 6fc7caa84e713f7627e171ab1e7c4b5be0dc9b3d ] Fix bnxt_fltr_match() to match ipv6 source and destination addresses. The function currently only checks ipv4 addresses and will not work corrently on ipv6 filters. Fixes: c0c050c58d84 ("bnxt_en: New Broadcom ethernet driver.") Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 38ee7692132c..7461e7b9eaae 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -7402,11 +7402,23 @@ static bool bnxt_fltr_match(struct bnxt_ntuple_filter *f1, struct flow_keys *keys1 = &f1->fkeys; struct flow_keys *keys2 = &f2->fkeys; - if (keys1->addrs.v4addrs.src == keys2->addrs.v4addrs.src && - keys1->addrs.v4addrs.dst == keys2->addrs.v4addrs.dst && - keys1->ports.ports == keys2->ports.ports && - keys1->basic.ip_proto == keys2->basic.ip_proto && - keys1->basic.n_proto == keys2->basic.n_proto && + if (keys1->basic.n_proto != keys2->basic.n_proto || + keys1->basic.ip_proto != keys2->basic.ip_proto) + return false; + + if (keys1->basic.n_proto == htons(ETH_P_IP)) { + if (keys1->addrs.v4addrs.src != keys2->addrs.v4addrs.src || + keys1->addrs.v4addrs.dst != keys2->addrs.v4addrs.dst) + return false; + } else { + if (memcmp(&keys1->addrs.v6addrs.src, &keys2->addrs.v6addrs.src, + sizeof(keys1->addrs.v6addrs.src)) || + memcmp(&keys1->addrs.v6addrs.dst, &keys2->addrs.v6addrs.dst, + sizeof(keys1->addrs.v6addrs.dst))) + return false; + } + + if (keys1->ports.ports == keys2->ports.ports && keys1->control.flags == keys2->control.flags && ether_addr_equal(f1->src_mac_addr, f2->src_mac_addr) && ether_addr_equal(f1->dst_mac_addr, f2->dst_mac_addr)) -- GitLab From adafa3c54b4ad81622a4508ed2c29cb1da46801b Mon Sep 17 00:00:00 2001 From: "Matwey V. Kornilov" Date: Mon, 6 Jan 2020 16:09:08 +0300 Subject: [PATCH 0770/1055] ARM: dts: am335x-boneblack-common: fix memory size [ Upstream commit 5abd45ea0fc3060f7805e131753fdcbafd6c6618 ] BeagleBone Black series is equipped with 512MB RAM whereas only 256MB is included from am335x-bone-common.dtsi This leads to an issue with unusual setups when devicetree is loaded by GRUB2 directly. Signed-off-by: Matwey V. Kornilov Signed-off-by: Tony Lindgren Signed-off-by: Sasha Levin --- arch/arm/boot/dts/am335x-boneblack-common.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/am335x-boneblack-common.dtsi b/arch/arm/boot/dts/am335x-boneblack-common.dtsi index 325daae40278..485c27f039f5 100644 --- a/arch/arm/boot/dts/am335x-boneblack-common.dtsi +++ b/arch/arm/boot/dts/am335x-boneblack-common.dtsi @@ -131,6 +131,11 @@ }; / { + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x20000000>; /* 512 MB */ + }; + clk_mcasp0_fixed: clk_mcasp0_fixed { #clock-cells = <0>; compatible = "fixed-clock"; -- GitLab From 9c8c51176e9d3035f6e89b6664b4dd67a0873cbf Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Mon, 13 Jan 2020 09:32:46 +0100 Subject: [PATCH 0771/1055] vti[6]: fix packet tx through bpf_redirect() [ Upstream commit 95224166a9032ff5d08fca633d37113078ce7d01 ] With an ebpf program that redirects packets through a vti[6] interface, the packets are dropped because no dst is attached. This could also be reproduced with an AF_PACKET socket, with the following python script (vti1 is an ip_vti interface): import socket send_s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, 0) # scapy # p = IP(src='10.100.0.2', dst='10.200.0.1')/ICMP(type='echo-request') # raw(p) req = b'E\x00\x00\x1c\x00\x01\x00\x00@\x01e\xb2\nd\x00\x02\n\xc8\x00\x01\x08\x00\xf7\xff\x00\x00\x00\x00' send_s.sendto(req, ('vti1', 0x800, 0, 0)) Signed-off-by: Nicolas Dichtel Signed-off-by: Steffen Klassert Signed-off-by: Sasha Levin --- net/ipv4/ip_vti.c | 13 +++++++++++-- net/ipv6/ip6_vti.c | 13 +++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 08c15dd42d93..59384ffe89f7 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c @@ -208,8 +208,17 @@ static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev, int mtu; if (!dst) { - dev->stats.tx_carrier_errors++; - goto tx_error_icmp; + struct rtable *rt; + + fl->u.ip4.flowi4_oif = dev->ifindex; + fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC; + rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4); + if (IS_ERR(rt)) { + dev->stats.tx_carrier_errors++; + goto tx_error_icmp; + } + dst = &rt->dst; + skb_dst_set(skb, dst); } dst_hold(dst); diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 557fe3880a3f..396a0f61f5f8 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -453,8 +453,17 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl) int err = -1; int mtu; - if (!dst) - goto tx_err_link_failure; + if (!dst) { + fl->u.ip6.flowi6_oif = dev->ifindex; + fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC; + dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6); + if (dst->error) { + dst_release(dst); + dst = NULL; + goto tx_err_link_failure; + } + skb_dst_set(skb, dst); + } dst_hold(dst); dst = xfrm_lookup(t->net, dst, fl, NULL, 0); -- GitLab From 49e509787b77e4991f89703f81a0f53d7739fc58 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 16 Jan 2020 11:20:53 +0100 Subject: [PATCH 0772/1055] scsi: fnic: do not queue commands during fwreset [ Upstream commit 0e2209629fec427ba75a6351486153a9feddd36b ] When a link is going down the driver will be calling fnic_cleanup_io(), which will traverse all commands and calling 'done' for each found command. While the traversal is handled under the host_lock, calling 'done' happens after the host_lock is being dropped. As fnic_queuecommand_lck() is being called with the host_lock held, it might well be that it will pick the command being selected for abortion from the above routine and enqueue it for sending, but then 'done' is being called on that very command from the above routine. Which of course confuses the hell out of the scsi midlayer. So fix this by not queueing commands when fnic_cleanup_io is active. Link: https://lore.kernel.org/r/20200116102053.62755-1-hare@suse.de Signed-off-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin --- drivers/scsi/fnic/fnic_scsi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 242e2ee494a1..d79ac0b24f5a 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -446,6 +446,9 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED))) return SCSI_MLQUEUE_HOST_BUSY; + if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_FWRESET))) + return SCSI_MLQUEUE_HOST_BUSY; + rport = starget_to_rport(scsi_target(sc->device)); if (!rport) { FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, -- GitLab From 9da4de4d00cc926d98fb13d284104210122ae1fa Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Mon, 20 Jan 2020 15:07:46 +0100 Subject: [PATCH 0773/1055] ARM: 8955/1: virt: Relax arch timer version check during early boot [ Upstream commit 6849b5eba1965ceb0cad3a75877ef4569dd3638e ] Updates to the Generic Timer architecture allow ID_PFR1.GenTimer to have values other than 0 or 1 while still preserving backward compatibility. At the moment, Linux is quite strict in the way it handles this field at early boot and will not configure arch timer if it doesn't find the value 1. Since here use ubfx for arch timer version extraction (hyb-stub build with -march=armv7-a, so it is safe) To help backports (even though the code was correct at the time of writing) Fixes: 8ec58be9f3ff ("ARM: virt: arch_timers: enable access to physical timers") Acked-by: Marc Zyngier Signed-off-by: Vladimir Murzin Signed-off-by: Russell King Signed-off-by: Sasha Levin --- arch/arm/kernel/hyp-stub.S | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/arm/kernel/hyp-stub.S b/arch/arm/kernel/hyp-stub.S index 82a942894fc0..83e463c05dcd 100644 --- a/arch/arm/kernel/hyp-stub.S +++ b/arch/arm/kernel/hyp-stub.S @@ -159,10 +159,9 @@ ARM_BE8(orr r7, r7, #(1 << 25)) @ HSCTLR.EE #if !defined(ZIMAGE) && defined(CONFIG_ARM_ARCH_TIMER) @ make CNTP_* and CNTPCT accessible from PL1 mrc p15, 0, r7, c0, c1, 1 @ ID_PFR1 - lsr r7, #16 - and r7, #0xf - cmp r7, #1 - bne 1f + ubfx r7, r7, #16, #4 + teq r7, #0 + beq 1f mrc p15, 4, r7, c14, c1, 0 @ CNTHCTL orr r7, r7, #3 @ PL1PCEN | PL1PCTEN mcr p15, 4, r7, c14, c1, 0 @ CNTHCTL -- GitLab From ffc1f3076eda033f86e9b0cb873788a01292f737 Mon Sep 17 00:00:00 2001 From: Vincenzo Frascino Date: Fri, 10 Jan 2020 12:28:07 +0000 Subject: [PATCH 0774/1055] tee: optee: Fix compilation issue with nommu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 9e0caab8e0f96f0af7d1dd388e62f44184a75372 ] The optee driver uses specific page table types to verify if a memory region is normal. These types are not defined in nommu systems. Trying to compile the driver in these systems results in a build error: linux/drivers/tee/optee/call.c: In function ‘is_normal_memory’: linux/drivers/tee/optee/call.c:533:26: error: ‘L_PTE_MT_MASK’ undeclared (first use in this function); did you mean ‘PREEMPT_MASK’? return (pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEALLOC; ^~~~~~~~~~~~~ PREEMPT_MASK linux/drivers/tee/optee/call.c:533:26: note: each undeclared identifier is reported only once for each function it appears in linux/drivers/tee/optee/call.c:533:44: error: ‘L_PTE_MT_WRITEALLOC’ undeclared (first use in this function) return (pgprot_val(p) & L_PTE_MT_MASK) == L_PTE_MT_WRITEALLOC; ^~~~~~~~~~~~~~~~~~~ Make the optee driver depend on MMU to fix the compilation issue. Signed-off-by: Vincenzo Frascino [jw: update commit title] Signed-off-by: Jens Wiklander Signed-off-by: Sasha Levin --- drivers/tee/optee/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig index 0126de898036..108600c6eb56 100644 --- a/drivers/tee/optee/Kconfig +++ b/drivers/tee/optee/Kconfig @@ -2,6 +2,7 @@ config OPTEE tristate "OP-TEE" depends on HAVE_ARM_SMCCC + depends on MMU help This implements the OP-TEE Trusted Execution Environment (TEE) driver. -- GitLab From 33fc8d611378dc649f8c342596f7d3be52bdc941 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 22 Jan 2020 15:07:27 +1100 Subject: [PATCH 0775/1055] airo: Fix possible info leak in AIROOLDIOCTL/SIOCDEVPRIVATE [ Upstream commit d6bce2137f5d6bb1093e96d2f801479099b28094 ] The driver for Cisco Aironet 4500 and 4800 series cards (airo.c), implements AIROOLDIOCTL/SIOCDEVPRIVATE in airo_ioctl(). The ioctl handler copies an aironet_ioctl struct from userspace, which includes a command and a length. Some of the commands are handled in readrids(), which kmalloc()'s a buffer of RIDSIZE (2048) bytes. That buffer is then passed to PC4500_readrid(), which has two cases. The else case does some setup and then reads up to RIDSIZE bytes from the hardware into the kmalloc()'ed buffer. Here len == RIDSIZE, pBuf is the kmalloc()'ed buffer: // read the rid length field bap_read(ai, pBuf, 2, BAP1); // length for remaining part of rid len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2; ... // read remainder of the rid rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1); PC4500_readrid() then returns to readrids() which does: len = comp->len; if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) { Where comp->len is the user controlled length field. So if the "rid length field" returned by the hardware is < 2048, and the user requests 2048 bytes in comp->len, we will leak the previous contents of the kmalloc()'ed buffer to userspace. Fix it by kzalloc()'ing the buffer. Found by Ilja by code inspection, not tested as I don't have the required hardware. Reported-by: Ilja Van Sprundel Signed-off-by: Michael Ellerman Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/wireless/cisco/airo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c index fc49255bab00..c9ffbdd42e67 100644 --- a/drivers/net/wireless/cisco/airo.c +++ b/drivers/net/wireless/cisco/airo.c @@ -7811,7 +7811,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { return -EINVAL; } - if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL) + if ((iobuf = kzalloc(RIDSIZE, GFP_KERNEL)) == NULL) return -ENOMEM; PC4500_readrid(ai,ridcode,iobuf,RIDSIZE, 1); -- GitLab From 6f0f284b770a29d0094b4671e37ac0ee521903b6 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 22 Jan 2020 15:07:28 +1100 Subject: [PATCH 0776/1055] airo: Add missing CAP_NET_ADMIN check in AIROOLDIOCTL/SIOCDEVPRIVATE [ Upstream commit 78f7a7566f5eb59321e99b55a6fdb16ea05b37d1 ] The driver for Cisco Aironet 4500 and 4800 series cards (airo.c), implements AIROOLDIOCTL/SIOCDEVPRIVATE in airo_ioctl(). The ioctl handler copies an aironet_ioctl struct from userspace, which includes a command. Some of the commands are handled in readrids(), where the user controlled command is converted into a driver-internal value called "ridcode". There are two command values, AIROGWEPKTMP and AIROGWEPKNV, which correspond to ridcode values of RID_WEP_TEMP and RID_WEP_PERM respectively. These commands both have checks that the user has CAP_NET_ADMIN, with the comment that "Only super-user can read WEP keys", otherwise they return -EPERM. However there is another command value, AIRORRID, that lets the user specify the ridcode value directly, with no other checks. This means the user can bypass the CAP_NET_ADMIN check on AIROGWEPKTMP and AIROGWEPKNV. Fix it by moving the CAP_NET_ADMIN check out of the command handling and instead do it later based on the ridcode. That way regardless of whether the ridcode is set via AIROGWEPKTMP or AIROGWEPKNV, or passed in using AIRORID, we always do the CAP_NET_ADMIN check. Found by Ilja by code inspection, not tested as I don't have the required hardware. Reported-by: Ilja Van Sprundel Signed-off-by: Michael Ellerman Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/wireless/cisco/airo.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c index c9ffbdd42e67..f3f20abbe269 100644 --- a/drivers/net/wireless/cisco/airo.c +++ b/drivers/net/wireless/cisco/airo.c @@ -7788,16 +7788,8 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { case AIROGVLIST: ridcode = RID_APLIST; break; case AIROGDRVNAM: ridcode = RID_DRVNAME; break; case AIROGEHTENC: ridcode = RID_ETHERENCAP; break; - case AIROGWEPKTMP: ridcode = RID_WEP_TEMP; - /* Only super-user can read WEP keys */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - break; - case AIROGWEPKNV: ridcode = RID_WEP_PERM; - /* Only super-user can read WEP keys */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - break; + case AIROGWEPKTMP: ridcode = RID_WEP_TEMP; break; + case AIROGWEPKNV: ridcode = RID_WEP_PERM; break; case AIROGSTAT: ridcode = RID_STATUS; break; case AIROGSTATSD32: ridcode = RID_STATSDELTA; break; case AIROGSTATSC32: ridcode = RID_STATS; break; @@ -7811,6 +7803,12 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { return -EINVAL; } + if (ridcode == RID_WEP_TEMP || ridcode == RID_WEP_PERM) { + /* Only super-user can read WEP keys */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + } + if ((iobuf = kzalloc(RIDSIZE, GFP_KERNEL)) == NULL) return -ENOMEM; -- GitLab From ce9ba09d135bb93652811783bce421be074fa5e4 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Wed, 22 Jan 2020 16:02:07 +0800 Subject: [PATCH 0777/1055] r8152: get default setting of WOL before initializing [ Upstream commit 9583a3638dc07cc1878f41265e85ed497f72efcb ] Initailization would reset runtime suspend by tp->saved_wolopts, so the tp->saved_wolopts should be set before initializing. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/usb/r8152.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 0083c60f5cdf..a7f9c1886bd4 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -5244,6 +5244,11 @@ static int rtl8152_probe(struct usb_interface *intf, intf->needs_remote_wakeup = 1; + if (!rtl_can_wakeup(tp)) + __rtl_set_wol(tp, 0); + else + tp->saved_wolopts = __rtl_get_wol(tp); + tp->rtl_ops.init(tp); queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0); set_ethernet_addr(tp); @@ -5257,10 +5262,6 @@ static int rtl8152_probe(struct usb_interface *intf, goto out1; } - if (!rtl_can_wakeup(tp)) - __rtl_set_wol(tp, 0); - - tp->saved_wolopts = __rtl_get_wol(tp); if (tp->saved_wolopts) device_set_wakeup_enable(&udev->dev, true); else -- GitLab From fcd0c0d36a58b9d99856de8aa6cde011e1134630 Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Wed, 22 Jan 2020 01:43:38 -0800 Subject: [PATCH 0778/1055] qlcnic: Fix CPU soft lockup while collecting firmware dump [ Upstream commit 22e984493a41bf8081f13d9ed84def3ca8cfd427 ] Driver while collecting firmware dump takes longer time to collect/process some of the firmware dump entries/memories. Bigger capture masks makes it worse as it results in larger amount of data being collected and results in CPU soft lockup. Place cond_resched() in some of the driver flows that are expectedly time consuming to relinquish the CPU to avoid CPU soft lockup panic. Signed-off-by: Shahed Shaikh Tested-by: Yonggen Xu Signed-off-by: Manish Chopra Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 1 + drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index a496390b8632..07f9067affc6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -2043,6 +2043,7 @@ static void qlcnic_83xx_exec_template_cmd(struct qlcnic_adapter *p_dev, break; } entry += p_hdr->size; + cond_resched(); } p_dev->ahw->reset.seq_index = index; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index afa10a163da1..f34ae8c75bc5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -703,6 +703,7 @@ static u32 qlcnic_read_memory_test_agent(struct qlcnic_adapter *adapter, addr += 16; reg_read -= 16; ret += 16; + cond_resched(); } out: mutex_unlock(&adapter->ahw->mem_lock); @@ -1383,6 +1384,7 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) buf_offset += entry->hdr.cap_size; entry_offset += entry->hdr.offset; buffer = fw_dump->data + buf_offset; + cond_resched(); } fw_dump->clr = 1; -- GitLab From 5d45e8aa20fbb1097d6d1d6866c91aeb81941663 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Wed, 22 Jan 2020 15:20:28 +0200 Subject: [PATCH 0779/1055] powerpc/fsl/dts: add fsl,erratum-a011043 [ Upstream commit 73d527aef68f7644e59f22ce7f9ac75e7b533aea ] Add fsl,erratum-a011043 to internal MDIO buses. Software may get false read error when reading internal PCS registers through MDIO. As a workaround, all internal MDIO accesses should ignore the MDIO_CFG[MDIO_RD_ER] bit. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0-best-effort.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1-best-effort.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-0.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-1.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-2.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-3.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-4.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-5.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-0.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-1.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-0.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-1.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-2.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-3.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-4.dtsi | 1 + arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-5.dtsi | 1 + 18 files changed, 18 insertions(+) diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0-best-effort.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0-best-effort.dtsi index e1a961f05dcd..baa0c503e741 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0-best-effort.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0-best-effort.dtsi @@ -63,6 +63,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe1000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy0: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi index c288f3c6c637..93095600e808 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi @@ -60,6 +60,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xf1000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy6: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1-best-effort.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1-best-effort.dtsi index 94f3e7175012..ff4bd38f0645 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1-best-effort.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1-best-effort.dtsi @@ -63,6 +63,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe3000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy1: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi index 94a76982d214..1fa38ed6f59e 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi @@ -60,6 +60,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xf3000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy7: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-0.dtsi index b5ff5f71c6b8..a8cc9780c0c4 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-0.dtsi @@ -59,6 +59,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe1000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy0: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-1.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-1.dtsi index ee44182c6348..8b8bd70c9382 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-1.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-1.dtsi @@ -59,6 +59,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe3000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy1: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-2.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-2.dtsi index f05f0d775039..619c880b54d8 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-2.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-2.dtsi @@ -59,6 +59,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe5000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy2: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-3.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-3.dtsi index a9114ec51075..d7ebb73a400d 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-3.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-3.dtsi @@ -59,6 +59,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe7000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy3: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-4.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-4.dtsi index 44dd00ac7367..b151d696a069 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-4.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-4.dtsi @@ -59,6 +59,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe9000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy4: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-5.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-5.dtsi index 5b1b84b58602..adc0ae0013a3 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-5.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-1g-5.dtsi @@ -59,6 +59,7 @@ fman@400000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xeb000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy5: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-0.dtsi index 0e1daaef9e74..435047e0e250 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-0.dtsi @@ -60,6 +60,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xf1000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy14: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-1.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-1.dtsi index 68c5ef779266..c098657cca0a 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-1.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-10g-1.dtsi @@ -60,6 +60,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xf3000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy15: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-0.dtsi index 605363cc1117..9d06824815f3 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-0.dtsi @@ -59,6 +59,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe1000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy8: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-1.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-1.dtsi index 1955dfa13634..70e947730c4b 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-1.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-1.dtsi @@ -59,6 +59,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe3000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy9: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-2.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-2.dtsi index 2c1476454ee0..ad96e6529595 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-2.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-2.dtsi @@ -59,6 +59,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe5000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy10: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-3.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-3.dtsi index b8b541ff5fb0..034bc4b71f7a 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-3.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-3.dtsi @@ -59,6 +59,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe7000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy11: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-4.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-4.dtsi index 4b2cfddd1b15..93ca23d82b39 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-4.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-4.dtsi @@ -59,6 +59,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xe9000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy12: ethernet-phy@0 { reg = <0x0>; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-5.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-5.dtsi index 0a52ddf7cc17..23b3117a2fd2 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-5.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-1-1g-5.dtsi @@ -59,6 +59,7 @@ fman@500000 { #size-cells = <0>; compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; reg = <0xeb000 0x1000>; + fsl,erratum-a011043; /* must ignore read errors */ pcsphy13: ethernet-phy@0 { reg = <0x0>; -- GitLab From 743bc2ab644f8d2c85f4021e1d2d72dd39d1ace8 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Wed, 22 Jan 2020 15:20:29 +0200 Subject: [PATCH 0780/1055] net/fsl: treat fsl,erratum-a011043 [ Upstream commit 1d3ca681b9d9575ccf696ebc2840a1ebb1fd4074 ] When fsl,erratum-a011043 is set, adjust for erratum A011043: MDIO reads to internal PCS registers may result in having the MDIO_CFG[MDIO_RD_ER] bit set, even when there is no error and read data (MDIO_DATA[MDIO_DATA]) is correct. Software may get false read error when reading internal PCS registers through MDIO. As a workaround, all internal MDIO accesses should ignore the MDIO_CFG[MDIO_RD_ER] bit. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/freescale/xgmac_mdio.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c index e03b30c60dcf..c82c85ef5fb3 100644 --- a/drivers/net/ethernet/freescale/xgmac_mdio.c +++ b/drivers/net/ethernet/freescale/xgmac_mdio.c @@ -49,6 +49,7 @@ struct tgec_mdio_controller { struct mdio_fsl_priv { struct tgec_mdio_controller __iomem *mdio_base; bool is_little_endian; + bool has_a011043; }; static u32 xgmac_read32(void __iomem *regs, @@ -226,7 +227,8 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum) return ret; /* Return all Fs if nothing was there */ - if (xgmac_read32(®s->mdio_stat, endian) & MDIO_STAT_RD_ER) { + if ((xgmac_read32(®s->mdio_stat, endian) & MDIO_STAT_RD_ER) && + !priv->has_a011043) { dev_err(&bus->dev, "Error while reading PHY%d reg at %d.%hhu\n", phy_id, dev_addr, regnum); @@ -274,6 +276,9 @@ static int xgmac_mdio_probe(struct platform_device *pdev) priv->is_little_endian = of_property_read_bool(pdev->dev.of_node, "little-endian"); + priv->has_a011043 = of_property_read_bool(pdev->dev.of_node, + "fsl,erratum-a011043"); + ret = of_mdiobus_register(bus, np); if (ret) { dev_err(&pdev->dev, "cannot register MDIO bus\n"); -- GitLab From 5d47f5ed5a1a4d08cd889f5b5fcacc1c0285b5bd Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Wed, 22 Jan 2020 16:15:14 +0200 Subject: [PATCH 0781/1055] net: fsl/fman: rename IF_MODE_XGMII to IF_MODE_10G [ Upstream commit 457bfc0a4bf531487ecc3cf82ec728a5e114fb1e ] As the only 10G PHY interface type defined at the moment the code was developed was XGMII, although the PHY interface mode used was not XGMII, XGMII was used in the code to denote 10G. This patch renames the 10G interface mode to remove the ambiguity. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/freescale/fman/fman_memac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/fman/fman_memac.c b/drivers/net/ethernet/freescale/fman/fman_memac.c index 75ce773c21a6..b33650a897f1 100644 --- a/drivers/net/ethernet/freescale/fman/fman_memac.c +++ b/drivers/net/ethernet/freescale/fman/fman_memac.c @@ -110,7 +110,7 @@ do { \ /* Interface Mode Register (IF_MODE) */ #define IF_MODE_MASK 0x00000003 /* 30-31 Mask on i/f mode bits */ -#define IF_MODE_XGMII 0x00000000 /* 30-31 XGMII (10G) interface */ +#define IF_MODE_10G 0x00000000 /* 30-31 10G interface */ #define IF_MODE_GMII 0x00000002 /* 30-31 GMII (1G) interface */ #define IF_MODE_RGMII 0x00000004 #define IF_MODE_RGMII_AUTO 0x00008000 @@ -439,7 +439,7 @@ static int init(struct memac_regs __iomem *regs, struct memac_cfg *cfg, tmp = 0; switch (phy_if) { case PHY_INTERFACE_MODE_XGMII: - tmp |= IF_MODE_XGMII; + tmp |= IF_MODE_10G; break; default: tmp |= IF_MODE_GMII; -- GitLab From 3c8a4483d801cb8fd8eaf74faacfd6eebece7139 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 23 Jan 2020 09:07:26 +1100 Subject: [PATCH 0782/1055] net/sonic: Add mutual exclusion for accessing shared state [ Upstream commit 865ad2f2201dc18685ba2686f13217f8b3a9c52c ] The netif_stop_queue() call in sonic_send_packet() races with the netif_wake_queue() call in sonic_interrupt(). This causes issues like "NETDEV WATCHDOG: eth0 (macsonic): transmit queue 0 timed out". Fix this by disabling interrupts when accessing tx_skb[] and next_tx. Update a comment to clarify the synchronization properties. Fixes: efcce839360f ("[PATCH] macsonic/jazzsonic network drivers update") Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/natsemi/sonic.c | 49 ++++++++++++++++++++-------- drivers/net/ethernet/natsemi/sonic.h | 1 + 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c index a051dddcbd76..7aa7f8050d44 100644 --- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -50,6 +50,8 @@ static int sonic_open(struct net_device *dev) if (sonic_debug > 2) printk("sonic_open: initializing sonic driver.\n"); + spin_lock_init(&lp->lock); + for (i = 0; i < SONIC_NUM_RRS; i++) { struct sk_buff *skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2); if (skb == NULL) { @@ -194,8 +196,6 @@ static void sonic_tx_timeout(struct net_device *dev) * wake the tx queue * Concurrently with all of this, the SONIC is potentially writing to * the status flags of the TDs. - * Until some mutual exclusion is added, this code will not work with SMP. However, - * MIPS Jazz machines and m68k Macs were all uni-processor machines. */ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) @@ -203,7 +203,8 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) struct sonic_local *lp = netdev_priv(dev); dma_addr_t laddr; int length; - int entry = lp->next_tx; + int entry; + unsigned long flags; if (sonic_debug > 2) printk("sonic_send_packet: skb=%p, dev=%p\n", skb, dev); @@ -226,6 +227,10 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } + spin_lock_irqsave(&lp->lock, flags); + + entry = lp->next_tx; + sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */ sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1); /* single fragment */ sonic_tda_put(dev, entry, SONIC_TD_PKTSIZE, length); /* length of packet */ @@ -235,10 +240,6 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) sonic_tda_put(dev, entry, SONIC_TD_LINK, sonic_tda_get(dev, entry, SONIC_TD_LINK) | SONIC_EOL); - /* - * Must set tx_skb[entry] only after clearing status, and - * before clearing EOL and before stopping queue - */ wmb(); lp->tx_len[entry] = length; lp->tx_laddr[entry] = laddr; @@ -263,6 +264,8 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP); + spin_unlock_irqrestore(&lp->lock, flags); + return NETDEV_TX_OK; } @@ -275,9 +278,21 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id) struct net_device *dev = dev_id; struct sonic_local *lp = netdev_priv(dev); int status; + unsigned long flags; + + /* The lock has two purposes. Firstly, it synchronizes sonic_interrupt() + * with sonic_send_packet() so that the two functions can share state. + * Secondly, it makes sonic_interrupt() re-entrant, as that is required + * by macsonic which must use two IRQs with different priority levels. + */ + spin_lock_irqsave(&lp->lock, flags); + + status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT; + if (!status) { + spin_unlock_irqrestore(&lp->lock, flags); - if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT)) return IRQ_NONE; + } do { if (status & SONIC_INT_PKTRX) { @@ -292,11 +307,12 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id) int td_status; int freed_some = 0; - /* At this point, cur_tx is the index of a TD that is one of: - * unallocated/freed (status set & tx_skb[entry] clear) - * allocated and sent (status set & tx_skb[entry] set ) - * allocated and not yet sent (status clear & tx_skb[entry] set ) - * still being allocated by sonic_send_packet (status clear & tx_skb[entry] clear) + /* The state of a Transmit Descriptor may be inferred + * from { tx_skb[entry], td_status } as follows. + * { clear, clear } => the TD has never been used + * { set, clear } => the TD was handed to SONIC + * { set, set } => the TD was handed back + * { clear, set } => the TD is available for re-use */ if (sonic_debug > 2) @@ -398,7 +414,12 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id) /* load CAM done */ if (status & SONIC_INT_LCD) SONIC_WRITE(SONIC_ISR, SONIC_INT_LCD); /* clear the interrupt */ - } while((status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT)); + + status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT; + } while (status); + + spin_unlock_irqrestore(&lp->lock, flags); + return IRQ_HANDLED; } diff --git a/drivers/net/ethernet/natsemi/sonic.h b/drivers/net/ethernet/natsemi/sonic.h index 421b1a283fed..944f4830c4a1 100644 --- a/drivers/net/ethernet/natsemi/sonic.h +++ b/drivers/net/ethernet/natsemi/sonic.h @@ -321,6 +321,7 @@ struct sonic_local { unsigned int next_tx; /* next free TD */ struct device *device; /* generic device */ struct net_device_stats stats; + spinlock_t lock; }; #define TX_TIMEOUT (3 * HZ) -- GitLab From 3a8debf8b1ee9b3d87df1bdd86883717b793b9be Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 23 Jan 2020 09:07:26 +1100 Subject: [PATCH 0783/1055] net/sonic: Use MMIO accessors [ Upstream commit e3885f576196ddfc670b3d53e745de96ffcb49ab ] The driver accesses descriptor memory which is simultaneously accessed by the chip, so the compiler must not be allowed to re-order CPU accesses. sonic_buf_get() used 'volatile' to prevent that. sonic_buf_put() should have done so too but was overlooked. Fixes: efcce839360f ("[PATCH] macsonic/jazzsonic network drivers update") Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/natsemi/sonic.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/natsemi/sonic.h b/drivers/net/ethernet/natsemi/sonic.h index 944f4830c4a1..7057760cb55c 100644 --- a/drivers/net/ethernet/natsemi/sonic.h +++ b/drivers/net/ethernet/natsemi/sonic.h @@ -343,30 +343,30 @@ static void sonic_tx_timeout(struct net_device *dev); as far as we can tell. */ /* OpenBSD calls this "SWO". I'd like to think that sonic_buf_put() is a much better name. */ -static inline void sonic_buf_put(void* base, int bitmode, +static inline void sonic_buf_put(u16 *base, int bitmode, int offset, __u16 val) { if (bitmode) #ifdef __BIG_ENDIAN - ((__u16 *) base + (offset*2))[1] = val; + __raw_writew(val, base + (offset * 2) + 1); #else - ((__u16 *) base + (offset*2))[0] = val; + __raw_writew(val, base + (offset * 2) + 0); #endif else - ((__u16 *) base)[offset] = val; + __raw_writew(val, base + (offset * 1) + 0); } -static inline __u16 sonic_buf_get(void* base, int bitmode, +static inline __u16 sonic_buf_get(u16 *base, int bitmode, int offset) { if (bitmode) #ifdef __BIG_ENDIAN - return ((volatile __u16 *) base + (offset*2))[1]; + return __raw_readw(base + (offset * 2) + 1); #else - return ((volatile __u16 *) base + (offset*2))[0]; + return __raw_readw(base + (offset * 2) + 0); #endif else - return ((volatile __u16 *) base)[offset]; + return __raw_readw(base + (offset * 1) + 0); } /* Inlines that you should actually use for reading/writing DMA buffers */ -- GitLab From 36db400a662d4651a7987f0ec3598de03eb951a8 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 23 Jan 2020 09:07:26 +1100 Subject: [PATCH 0784/1055] net/sonic: Fix receive buffer handling [ Upstream commit 9e311820f67e740f4fb8dcb82b4c4b5b05bdd1a5 ] The SONIC can sometimes advance its rx buffer pointer (RRP register) without advancing its rx descriptor pointer (CRDA register). As a result the index of the current rx descriptor may not equal that of the current rx buffer. The driver mistakenly assumes that they are always equal. This assumption leads to incorrect packet lengths and possible packet duplication. Avoid this by calling a new function to locate the buffer corresponding to a given descriptor. Fixes: efcce839360f ("[PATCH] macsonic/jazzsonic network drivers update") Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/natsemi/sonic.c | 35 ++++++++++++++++++++++++---- drivers/net/ethernet/natsemi/sonic.h | 5 ++-- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c index 7aa7f8050d44..b6599aa22504 100644 --- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -423,6 +423,21 @@ static irqreturn_t sonic_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +/* Return the array index corresponding to a given Receive Buffer pointer. */ +static int index_from_addr(struct sonic_local *lp, dma_addr_t addr, + unsigned int last) +{ + unsigned int i = last; + + do { + i = (i + 1) & SONIC_RRS_MASK; + if (addr == lp->rx_laddr[i]) + return i; + } while (i != last); + + return -ENOENT; +} + /* * We have a good packet(s), pass it/them up the network stack. */ @@ -442,6 +457,16 @@ static void sonic_rx(struct net_device *dev) status = sonic_rda_get(dev, entry, SONIC_RD_STATUS); if (status & SONIC_RCR_PRX) { + u32 addr = (sonic_rda_get(dev, entry, + SONIC_RD_PKTPTR_H) << 16) | + sonic_rda_get(dev, entry, SONIC_RD_PKTPTR_L); + int i = index_from_addr(lp, addr, entry); + + if (i < 0) { + WARN_ONCE(1, "failed to find buffer!\n"); + break; + } + /* Malloc up new buffer. */ new_skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2); if (new_skb == NULL) { @@ -463,7 +488,7 @@ static void sonic_rx(struct net_device *dev) /* now we have a new skb to replace it, pass the used one up the stack */ dma_unmap_single(lp->device, lp->rx_laddr[entry], SONIC_RBSIZE, DMA_FROM_DEVICE); - used_skb = lp->rx_skb[entry]; + used_skb = lp->rx_skb[i]; pkt_len = sonic_rda_get(dev, entry, SONIC_RD_PKTLEN); skb_trim(used_skb, pkt_len); used_skb->protocol = eth_type_trans(used_skb, dev); @@ -472,13 +497,13 @@ static void sonic_rx(struct net_device *dev) lp->stats.rx_bytes += pkt_len; /* and insert the new skb */ - lp->rx_laddr[entry] = new_laddr; - lp->rx_skb[entry] = new_skb; + lp->rx_laddr[i] = new_laddr; + lp->rx_skb[i] = new_skb; bufadr_l = (unsigned long)new_laddr & 0xffff; bufadr_h = (unsigned long)new_laddr >> 16; - sonic_rra_put(dev, entry, SONIC_RR_BUFADR_L, bufadr_l); - sonic_rra_put(dev, entry, SONIC_RR_BUFADR_H, bufadr_h); + sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l); + sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h); } else { /* This should only happen, if we enable accepting broken packets. */ lp->stats.rx_errors++; diff --git a/drivers/net/ethernet/natsemi/sonic.h b/drivers/net/ethernet/natsemi/sonic.h index 7057760cb55c..83905eee6960 100644 --- a/drivers/net/ethernet/natsemi/sonic.h +++ b/drivers/net/ethernet/natsemi/sonic.h @@ -274,8 +274,9 @@ #define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */ #define SONIC_NUM_TDS 16 /* number of transmit descriptors */ -#define SONIC_RDS_MASK (SONIC_NUM_RDS-1) -#define SONIC_TDS_MASK (SONIC_NUM_TDS-1) +#define SONIC_RRS_MASK (SONIC_NUM_RRS - 1) +#define SONIC_RDS_MASK (SONIC_NUM_RDS - 1) +#define SONIC_TDS_MASK (SONIC_NUM_TDS - 1) #define SONIC_RBSIZE 1520 /* size of one resource buffer */ -- GitLab From 772c96a03b0d0e45170cf8352078fcbf9ba9dd7c Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Thu, 23 Jan 2020 09:07:26 +1100 Subject: [PATCH 0785/1055] net/sonic: Quiesce SONIC before re-initializing descriptor memory [ Upstream commit 3f4b7e6a2be982fd8820a2b54d46dd9c351db899 ] Make sure the SONIC's DMA engine is idle before altering the transmit and receive descriptors. Add a helper for this as it will be needed again. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Tested-by: Stan Johnson Signed-off-by: Finn Thain Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/natsemi/sonic.c | 25 +++++++++++++++++++++++++ drivers/net/ethernet/natsemi/sonic.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c index b6599aa22504..254e6dbc4c6a 100644 --- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -103,6 +103,24 @@ static int sonic_open(struct net_device *dev) return 0; } +/* Wait for the SONIC to become idle. */ +static void sonic_quiesce(struct net_device *dev, u16 mask) +{ + struct sonic_local * __maybe_unused lp = netdev_priv(dev); + int i; + u16 bits; + + for (i = 0; i < 1000; ++i) { + bits = SONIC_READ(SONIC_CMD) & mask; + if (!bits) + return; + if (irqs_disabled() || in_interrupt()) + udelay(20); + else + usleep_range(100, 200); + } + WARN_ONCE(1, "command deadline expired! 0x%04x\n", bits); +} /* * Close the SONIC device @@ -120,6 +138,9 @@ static int sonic_close(struct net_device *dev) /* * stop the SONIC, disable interrupts */ + SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS); + sonic_quiesce(dev, SONIC_CR_ALL); + SONIC_WRITE(SONIC_IMR, 0); SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); @@ -159,6 +180,9 @@ static void sonic_tx_timeout(struct net_device *dev) * put the Sonic into software-reset mode and * disable all interrupts before releasing DMA buffers */ + SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS); + sonic_quiesce(dev, SONIC_CR_ALL); + SONIC_WRITE(SONIC_IMR, 0); SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); @@ -638,6 +662,7 @@ static int sonic_init(struct net_device *dev) */ SONIC_WRITE(SONIC_CMD, 0); SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS); + sonic_quiesce(dev, SONIC_CR_ALL); /* * initialize the receive resource area diff --git a/drivers/net/ethernet/natsemi/sonic.h b/drivers/net/ethernet/natsemi/sonic.h index 83905eee6960..7dc011655e70 100644 --- a/drivers/net/ethernet/natsemi/sonic.h +++ b/drivers/net/ethernet/natsemi/sonic.h @@ -110,6 +110,9 @@ #define SONIC_CR_TXP 0x0002 #define SONIC_CR_HTX 0x0001 +#define SONIC_CR_ALL (SONIC_CR_LCAM | SONIC_CR_RRRA | \ + SONIC_CR_RXEN | SONIC_CR_TXP) + /* * SONIC data configuration bits */ -- GitLab From b2fd13e9ced42f35deb3faa0b65966ec9fd237a4 Mon Sep 17 00:00:00 2001 From: Vasily Averin Date: Thu, 23 Jan 2020 10:11:08 +0300 Subject: [PATCH 0786/1055] seq_tab_next() should increase position index [ Upstream commit 70a87287c821e9721b62463777f55ba588ac4623 ] if seq_file .next fuction does not change position index, read after some lseek can generate unexpected output. https://bugzilla.kernel.org/show_bug.cgi?id=206283 Signed-off-by: Vasily Averin Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index 9e5cd18e7358..8bd90ad15607 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -66,8 +66,7 @@ static void *seq_tab_start(struct seq_file *seq, loff_t *pos) static void *seq_tab_next(struct seq_file *seq, void *v, loff_t *pos) { v = seq_tab_get_idx(seq->private, *pos + 1); - if (v) - ++*pos; + ++(*pos); return v; } -- GitLab From 964646964ef4028148b5916f6ad5b55a2d9c9152 Mon Sep 17 00:00:00 2001 From: Vasily Averin Date: Thu, 23 Jan 2020 10:11:13 +0300 Subject: [PATCH 0787/1055] l2t_seq_next should increase position index [ Upstream commit 66018a102f7756cf72db4d2704e1b93969d9d332 ] if seq_file .next fuction does not change position index, read after some lseek can generate unexpected output. https://bugzilla.kernel.org/show_bug.cgi?id=206283 Signed-off-by: Vasily Averin Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- drivers/net/ethernet/chelsio/cxgb4/l2t.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index f7ef8871dd0b..67aa3c997417 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -682,8 +682,7 @@ static void *l2t_seq_start(struct seq_file *seq, loff_t *pos) static void *l2t_seq_next(struct seq_file *seq, void *v, loff_t *pos) { v = l2t_get_idx(seq, *pos); - if (v) - ++*pos; + ++(*pos); return v; } -- GitLab From 9b7a4bed4c7894442fd0f339b84e022a02174c5d Mon Sep 17 00:00:00 2001 From: Praveen Chaudhary Date: Thu, 23 Jan 2020 12:33:28 -0800 Subject: [PATCH 0788/1055] net: Fix skb->csum update in inet_proto_csum_replace16(). [ Upstream commit 189c9b1e94539b11c80636bc13e9cf47529e7bba ] skb->csum is updated incorrectly, when manipulation for NF_NAT_MANIP_SRC\DST is done on IPV6 packet. Fix: There is no need to update skb->csum in inet_proto_csum_replace16(), because update in two fields a.) IPv6 src/dst address and b.) L4 header checksum cancels each other for skb->csum calculation. Whereas inet_proto_csum_replace4 function needs to update skb->csum, because update in 3 fields a.) IPv4 src/dst address, b.) IPv4 Header checksum and c.) L4 header checksum results in same diff as L4 Header checksum for skb->csum calculation. [ pablo@netfilter.org: a few comestic documentation edits ] Signed-off-by: Praveen Chaudhary Signed-off-by: Zhenggen Xu Signed-off-by: Andy Stracner Reviewed-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- net/core/utils.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/net/core/utils.c b/net/core/utils.c index 93066bd0305a..b1823e76b877 100644 --- a/net/core/utils.c +++ b/net/core/utils.c @@ -419,6 +419,23 @@ void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb, } EXPORT_SYMBOL(inet_proto_csum_replace4); +/** + * inet_proto_csum_replace16 - update layer 4 header checksum field + * @sum: Layer 4 header checksum field + * @skb: sk_buff for the packet + * @from: old IPv6 address + * @to: new IPv6 address + * @pseudohdr: True if layer 4 header checksum includes pseudoheader + * + * Update layer 4 header as per the update in IPv6 src/dst address. + * + * There is no need to update skb->csum in this function, because update in two + * fields a.) IPv6 src/dst address and b.) L4 header checksum cancels each other + * for skb->csum calculation. Whereas inet_proto_csum_replace4 function needs to + * update skb->csum, because update in 3 fields a.) IPv4 src/dst address, + * b.) IPv4 Header checksum and c.) L4 header checksum results in same diff as + * L4 Header checksum for skb->csum calculation. + */ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, const __be32 *from, const __be32 *to, bool pseudohdr) @@ -430,9 +447,6 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, if (skb->ip_summed != CHECKSUM_PARTIAL) { *sum = csum_fold(csum_partial(diff, sizeof(diff), ~csum_unfold(*sum))); - if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) - skb->csum = ~csum_partial(diff, sizeof(diff), - ~skb->csum); } else if (pseudohdr) *sum = ~csum_fold(csum_partial(diff, sizeof(diff), csum_unfold(*sum))); -- GitLab From e1404bf5369466ec41eb57852ccf5c24d5c69fe4 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Fri, 31 Jan 2020 09:31:05 -0500 Subject: [PATCH 0789/1055] btrfs: do not zero f_bavail if we have available space commit d55966c4279bfc6a0cf0b32bf13f5df228a1eeb6 upstream. There was some logic added a while ago to clear out f_bavail in statfs() if we did not have enough free metadata space to satisfy our global reserve. This was incorrect at the time, however didn't really pose a problem for normal file systems because we would often allocate chunks if we got this low on free metadata space, and thus wouldn't really hit this case unless we were actually full. Fast forward to today and now we are much better about not allocating metadata chunks all of the time. Couple this with d792b0f19711 ("btrfs: always reserve our entire size for the global reserve") which now means we'll easily have a larger global reserve than our free space, we are now more likely to trip over this while still having plenty of space. Fix this by skipping this logic if the global rsv's space_info is not full. space_info->full is 0 unless we've attempted to allocate a chunk for that space_info and that has failed. If this happens then the space for the global reserve is definitely sacred and we need to report b_avail == 0, but before then we can just use our calculated b_avail. Reported-by: Martin Steigerwald Fixes: ca8a51b3a979 ("btrfs: statfs: report zero available if metadata are exhausted") CC: stable@vger.kernel.org # 4.5+ Reviewed-by: Qu Wenruo Tested-By: Martin Steigerwald Signed-off-by: Josef Bacik Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/super.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 204d585e012a..3ab79fa00dc7 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -2114,7 +2114,15 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) */ thresh = 4 * 1024 * 1024; - if (!mixed && total_free_meta - thresh < block_rsv->size) + /* + * We only want to claim there's no available space if we can no longer + * allocate chunks for our metadata profile and our global reserve will + * not fit in the free metadata space. If we aren't ->full then we + * still can allocate chunks and thus are fine using the currently + * calculated f_bavail. + */ + if (!mixed && block_rsv->space_info->full && + total_free_meta - thresh < block_rsv->size) buf->f_bavail = 0; buf->f_type = BTRFS_SUPER_MAGIC; -- GitLab From 5008c125d5535e7ff13085553b0ec55547ef72a3 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Wed, 8 Jan 2020 03:17:45 +0800 Subject: [PATCH 0790/1055] perf report: Fix no libunwind compiled warning break s390 issue [ Upstream commit c3314a74f86dc00827e0945c8e5039fc3aebaa3c ] Commit 800d3f561659 ("perf report: Add warning when libunwind not compiled in") breaks the s390 platform. S390 uses libdw-dwarf-unwind for call chain unwinding and had no support for libunwind. So the warning "Please install libunwind development packages during the perf build." caused the confusion even if the call-graph is displayed correctly. This patch adds checking for HAVE_DWARF_SUPPORT, which is set when libdw-dwarf-unwind is compiled in. Fixes: 800d3f561659 ("perf report: Add warning when libunwind not compiled in") Signed-off-by: Jin Yao Reviewed-by: Thomas Richter Tested-by: Thomas Richter Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jin Yao Cc: Kan Liang Cc: Peter Zijlstra Link: http://lore.kernel.org/lkml/20200107191745.18415-1-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin --- tools/perf/builtin-report.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 17b26661b2f6..429c3e140dc3 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -342,10 +342,10 @@ static int report__setup_sample_type(struct report *rep) PERF_SAMPLE_BRANCH_ANY)) rep->nonany_branch_mode = true; -#ifndef HAVE_LIBUNWIND_SUPPORT +#if !defined(HAVE_LIBUNWIND_SUPPORT) && !defined(HAVE_DWARF_SUPPORT) if (dwarf_callchain_users) { - ui__warning("Please install libunwind development packages " - "during the perf build.\n"); + ui__warning("Please install libunwind or libdw " + "development packages during the perf build.\n"); } #endif -- GitLab From e0f8b8a65a473a8baa439cf865a694bbeb83fe90 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 5 Feb 2020 14:18:29 +0000 Subject: [PATCH 0791/1055] Linux 4.14.170 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 795d93bfe156..b614291199f8 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 4 PATCHLEVEL = 14 -SUBLEVEL = 169 +SUBLEVEL = 170 EXTRAVERSION = NAME = Petit Gorille -- GitLab From b1962a40ffff442bdfafd711aa8c9296b894e067 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 13 Feb 2018 11:04:11 -0800 Subject: [PATCH 0792/1055] rpmsg: smd: Use spinlock in tx path Backporting the change from 4.19 kernel to 4.14 kernel. By switching the tx_lock to a spinlock we allow clients to use rpmsg_trysend() from atomic context. The mutex was interruptable as it was previously held for the duration of some client waiting for available space in the FIFO, but this was recently changed to only be held temporarily - allowing us to replace it with a spinlock. Change-Id: Ib645758b7c5f7e8b475dfa0c7dab4b11d30ea6b9 Signed-off-by: Bjorn Andersson Git-commit: 33e3820dda8876792bd8135db633c741a07263be Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Prudhvi Yarlagadda --- drivers/rpmsg/qcom_smd.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index f8b4b24fe736..795f7f011ed3 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2015, Sony Mobile Communications AB. - * Copyright (c) 2012-2013, 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, 2019-2020 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 @@ -205,7 +206,7 @@ struct qcom_smd_channel { struct smd_channel_info_pair *info; struct smd_channel_info_word_pair *info_word; - struct mutex tx_lock; + spinlock_t tx_lock; wait_queue_head_t fblockread_event; void *tx_fifo; @@ -746,6 +747,7 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data, { __le32 hdr[5] = { cpu_to_le32(len), }; int tlen = sizeof(hdr) + len; + unsigned long flags; int ret; /* Word aligned channels only accept word size aligned data */ @@ -756,9 +758,11 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data, if (tlen >= channel->fifo_size) return -EINVAL; - ret = mutex_lock_interruptible(&channel->tx_lock); - if (ret) - return ret; + /* Highlight the fact that if we enter the loop below we might sleep */ + if (wait) + might_sleep(); + + spin_lock_irqsave(&channel->tx_lock, flags); while (qcom_smd_get_tx_avail(channel) < tlen) { if (!wait) { @@ -773,11 +777,16 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data, SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 0); + /* Wait without holding the tx_lock */ + spin_unlock_irqrestore(&channel->tx_lock, flags); + ret = wait_event_interruptible(channel->fblockread_event, qcom_smd_get_tx_avail(channel) >= tlen || channel->state != SMD_CHANNEL_OPENED); if (ret) - goto out; + return ret; + + spin_lock_irqsave(&channel->tx_lock, flags); SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1); } @@ -795,7 +804,7 @@ static int __qcom_smd_send(struct qcom_smd_channel *channel, const void *data, qcom_smd_signal_channel(channel); out: - mutex_unlock(&channel->tx_lock); + spin_unlock_irqrestore(&channel->tx_lock, flags); return ret; } @@ -1109,7 +1118,7 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed goto free_channel; } - mutex_init(&channel->tx_lock); + spin_lock_init(&channel->tx_lock); spin_lock_init(&channel->recv_lock); init_waitqueue_head(&channel->fblockread_event); -- GitLab From 554749fccb3430f0c45df501bb86bc7c210c7493 Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Fri, 22 May 2020 16:36:43 -0700 Subject: [PATCH 0793/1055] msm: ipa3: increase pkt ctx for cv2x rsrc grp Made the changes to increase rsrc pkt conexts from 1 to 6 to support cv2x auto case. Change-Id: I2f9774fd473248ce4f86748be83c2a9b58ab16a8 Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index ac42a899b617..127a5a64410b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -409,7 +409,7 @@ static const struct rsrc_min_max ipa3_rsrc_src_grp_config [IPA_4_5_MHI] = { /* PCIE DDR DMA QDSS unused N/A */ [IPA_v4_0_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = { - {3, 8}, {4, 11}, {1, 1}, {1, 1}, {0, 0}, {0, 0} }, + {3, 8}, {4, 11}, {1, 6}, {1, 1}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = { {9, 9}, {12, 12}, {2, 2}, {2, 2}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_SRC_DESCRIPTOR_BUFF] = { @@ -435,7 +435,7 @@ static const struct rsrc_min_max ipa3_rsrc_src_grp_config [IPA_4_5_AUTO_MHI] = { /* PCIE DDR DMA/CV2X QDSS unused N/A */ [IPA_v4_0_RSRC_GRP_TYPE_SRC_PKT_CONTEXTS] = { - {3, 8}, {4, 11}, {1, 1}, {1, 1}, {0, 0}, {0, 0} }, + {3, 8}, {4, 11}, {1, 6}, {1, 1}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_SRS_DESCRIPTOR_LISTS] = { {9, 9}, {12, 12}, {2, 2}, {2, 2}, {0, 0}, {0, 0} }, [IPA_v4_0_RSRC_GRP_TYPE_SRC_DESCRIPTOR_BUFF] = { -- GitLab From ec7f581e34d9be1fe195a48897bfda41274f060d Mon Sep 17 00:00:00 2001 From: Rohith Kollalsi Date: Fri, 24 Apr 2020 17:16:34 +0530 Subject: [PATCH 0794/1055] usb: f_cdev: USB remote wake up feature implementation for DUN Implement usb remote wake up feature for DUN on sdx55. For super speed this feature supports wake up of a particular function from suspend, where as for high speed, remote wakeup doesn't support wakeup of a particular function from suspend, but entire usb bus needs to wakeup. Change-Id: Ia4392fbb65c9302926d26f13f7f776d6bdbdccaf Signed-off-by: Rohith Kollalsi --- drivers/usb/gadget/function/f_cdev.c | 146 ++++++++++++++++++++++++--- 1 file changed, 130 insertions(+), 16 deletions(-) diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 2152220d6cc1..7c87e5821d86 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -107,6 +107,7 @@ struct f_cdev { struct list_head read_pool; struct list_head read_queued; struct list_head write_pool; + struct list_head write_pending; /* current active USB RX request */ struct usb_request *current_rx_req; @@ -130,6 +131,8 @@ struct f_cdev { struct workqueue_struct *fcdev_wq; bool is_connected; bool port_open; + bool is_suspended; + bool pending_state_notify; unsigned long nbytes_from_host; unsigned long nbytes_to_host; @@ -538,6 +541,52 @@ static int usb_cser_set_alt(struct usb_function *f, unsigned int intf, return rc; } +static int port_notify_serial_state(struct cserial *cser); + +static void usb_cser_resume(struct usb_function *f) +{ + struct f_cdev *port = func_to_port(f); + unsigned long flags; + int ret; + + struct usb_request *req, *t; + struct usb_ep *in; + + pr_debug("%s\n", __func__); + port->is_suspended = false; + + /* process pending state notifications */ + if (port->pending_state_notify) + port_notify_serial_state(&port->port_usb); + + spin_lock_irqsave(&port->port_lock, flags); + in = port->port_usb.in; + /* process any pending requests */ + list_for_each_entry_safe(req, t, &port->write_pending, list) { + list_del_init(&req->list); + spin_unlock_irqrestore(&port->port_lock, flags); + + ret = usb_ep_queue(in, req, GFP_KERNEL); + spin_lock_irqsave(&port->port_lock, flags); + if (ret) { + pr_err("EP QUEUE failed:%d\n", ret); + list_add(&req->list, &port->write_pool); + } else { + port->nbytes_from_port_bridge += req->length; + } + } + + spin_unlock_irqrestore(&port->port_lock, flags); +} + +static void usb_cser_suspend(struct usb_function *f) +{ + struct f_cdev *port = func_to_port(f); + + pr_debug("%s\n", __func__); + port->is_suspended = true; +} + static int usb_cser_func_suspend(struct usb_function *f, u8 options) { bool func_wakeup_allowed; @@ -547,15 +596,28 @@ static int usb_cser_func_suspend(struct usb_function *f, u8 options) f->func_wakeup_allowed = func_wakeup_allowed; if (options & FUNC_SUSPEND_OPT_SUSP_MASK) { - if (!f->func_is_suspended) + if (!f->func_is_suspended) { + usb_cser_suspend(f); f->func_is_suspended = true; + } } else { - if (f->func_is_suspended) + if (f->func_is_suspended) { f->func_is_suspended = false; + usb_cser_resume(f); + } } return 0; } +static int usb_cser_get_remote_wakeup_capable(struct usb_function *f, + struct usb_gadget *g) +{ + + return ((g->speed >= USB_SPEED_SUPER && f->func_wakeup_allowed) || + (g->speed < USB_SPEED_SUPER && g->remote_wakeup)); + +} + static int usb_cser_get_status(struct usb_function *f) { bool remote_wakeup_en_status = f->func_wakeup_allowed ? 1 : 0; @@ -630,7 +692,17 @@ static int port_notify_serial_state(struct cserial *cser) unsigned long flags; struct usb_composite_dev *cdev = port->port_usb.func.config->cdev; + + if (port->is_suspended) { + port->pending_state_notify = true; + pr_debug("%s: port is suspended\n", __func__); + return 0; + } + spin_lock_irqsave(&port->port_lock, flags); + if (port->pending_state_notify) + port->pending_state_notify = false; + if (!port->port_usb.pending) { port->port_usb.pending = true; spin_unlock_irqrestore(&port->port_lock, flags); @@ -1095,6 +1167,7 @@ static void usb_cser_stop_io(struct f_cdev *port) usb_cser_free_requests(out, &port->read_queued); usb_cser_free_requests(out, &port->read_pool); usb_cser_free_requests(in, &port->write_pool); + usb_cser_free_requests(in, &port->write_pending); spin_unlock_irqrestore(&port->port_lock, flags); } @@ -1266,6 +1339,9 @@ ssize_t f_cdev_write(struct file *file, struct list_head *pool; unsigned int xfer_size; struct usb_ep *in; + struct cserial *cser; + struct usb_function *func; + struct usb_gadget *gadget; port = file->private_data; if (!port) { @@ -1273,6 +1349,9 @@ ssize_t f_cdev_write(struct file *file, return -EINVAL; } + cser = &port->port_usb; + func = &cser->func; + spin_lock_irqsave(&port->port_lock, flags); pr_debug("write on port(%s)(%pK)\n", port->name, port); @@ -1304,9 +1383,40 @@ ssize_t f_cdev_write(struct file *file, if (ret) { pr_err("copy_from_user failed: err %d\n", ret); ret = -EFAULT; - } else { - req->length = xfer_size; - req->zero = 1; + goto err_exit; + } + + req->length = xfer_size; + req->zero = 1; + if (port->is_suspended) { + gadget = cser->func.config->cdev->gadget; + if (!usb_cser_get_remote_wakeup_capable(func, gadget)) { + pr_debug("%s remote-wakeup not capable\n", + __func__); + ret = -EOPNOTSUPP; + goto err_exit; + } + + spin_lock_irqsave(&port->port_lock, flags); + list_add(&req->list, &port->write_pending); + spin_unlock_irqrestore(&port->port_lock, flags); + + if (gadget->speed >= USB_SPEED_SUPER + && func->func_is_suspended) + ret = usb_func_wakeup(func); + else + ret = usb_gadget_wakeup(gadget); + + if (ret < 0 && ret != -EACCES) { + pr_err("Remote wakeup failed:%d\n", ret); + spin_lock_irqsave(&port->port_lock, flags); + req = list_first_entry(&port->write_pending, + struct usb_request, list); + list_del(&req->list); + spin_unlock_irqrestore(&port->port_lock, flags); + goto err_exit; + } + } else { ret = usb_ep_queue(in, req, GFP_KERNEL); if (ret) { pr_err("EP QUEUE failed:%d\n", ret); @@ -1318,19 +1428,18 @@ ssize_t f_cdev_write(struct file *file, spin_unlock_irqrestore(&port->port_lock, flags); } + return xfer_size; + err_exit: - if (ret) { - spin_lock_irqsave(&port->port_lock, flags); - /* USB cable is connected, add it back otherwise free request */ - if (port->is_connected) - list_add(&req->list, &port->write_pool); - else - usb_cser_free_req(in, req); - spin_unlock_irqrestore(&port->port_lock, flags); - return ret; - } + spin_lock_irqsave(&port->port_lock, flags); + /* USB cable is connected, add it back otherwise free request */ + if (port->is_connected) + list_add(&req->list, &port->write_pool); + else + usb_cser_free_req(in, req); + spin_unlock_irqrestore(&port->port_lock, flags); - return xfer_size; + return ret; } static unsigned int f_cdev_poll(struct file *file, poll_table *wait) @@ -1566,6 +1675,8 @@ int usb_cser_connect(struct f_cdev *port) cser->pending = false; cser->q_again = false; port->is_connected = true; + port->pending_state_notify = false; + port->is_suspended = false; spin_unlock_irqrestore(&port->port_lock, flags); usb_cser_start_io(port); @@ -1759,6 +1870,7 @@ static struct f_cdev *f_cdev_alloc(char *func_name, int portno) INIT_LIST_HEAD(&port->read_pool); INIT_LIST_HEAD(&port->read_queued); INIT_LIST_HEAD(&port->write_pool); + INIT_LIST_HEAD(&port->write_pending); port->fcdev_wq = create_singlethread_workqueue(port->name); if (!port->fcdev_wq) { @@ -2053,6 +2165,8 @@ static struct usb_function *cser_alloc(struct usb_function_instance *fi) port->port_usb.func.func_suspend = usb_cser_func_suspend; port->port_usb.func.get_status = usb_cser_get_status; port->port_usb.func.free_func = usb_cser_free_func; + port->port_usb.func.resume = usb_cser_resume; + port->port_usb.func.suspend = usb_cser_suspend; return &port->port_usb.func; } -- GitLab From b043e42f0ff3a94e968499c46bd1909ed6d81254 Mon Sep 17 00:00:00 2001 From: Suraj Jaiswal Date: Fri, 29 May 2020 18:15:08 +0530 Subject: [PATCH 0795/1055] net: stmmac: copy from user fail handle Handle the fail case of copy from user & return proper error. Change-Id: I02fba52587aa91a46fd035286027510a310d23d4 Signed-off-by: Suraj Jaiswal --- .../net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 10 +++++++--- .../net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index ed6981aaf774..49d5842b488b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -112,18 +112,21 @@ u16 dwmac_qcom_select_queue( return txqueue_select; } -void dwmac_qcom_program_avb_algorithm( +int dwmac_qcom_program_avb_algorithm( struct stmmac_priv *priv, struct ifr_data_struct *req) { struct dwmac_qcom_avb_algorithm l_avb_struct, *u_avb_struct = (struct dwmac_qcom_avb_algorithm *)req->ptr; struct dwmac_qcom_avb_algorithm_params *avb_params; + int ret = 0; ETHQOSDBG("\n"); if (copy_from_user(&l_avb_struct, (void __user *)u_avb_struct, - sizeof(struct dwmac_qcom_avb_algorithm))) + sizeof(struct dwmac_qcom_avb_algorithm))) { ETHQOSERR("Failed to fetch AVB Struct\n"); + return -EFAULT; + } if (priv->speed == SPEED_1000) avb_params = &l_avb_struct.speed1000params; @@ -158,6 +161,7 @@ void dwmac_qcom_program_avb_algorithm( l_avb_struct.qinx); ETHQOSDBG("\n"); + return ret; } unsigned int dwmac_qcom_get_plat_tx_coal_frames( @@ -223,7 +227,7 @@ int ethqos_handle_prv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ret = ppsout_config(pdata, ð_pps_cfg); break; case ETHQOS_AVB_ALGORITHM: - dwmac_qcom_program_avb_algorithm(pdata, &req); + ret = dwmac_qcom_program_avb_algorithm(pdata, &req); break; default: break; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h index ea864cd28a31..56824edc0c37 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h @@ -583,7 +583,7 @@ struct dwmac_qcom_avb_algorithm { enum dwmac_qcom_queue_operating_mode op_mode; }; -void dwmac_qcom_program_avb_algorithm( +int dwmac_qcom_program_avb_algorithm( struct stmmac_priv *priv, struct ifr_data_struct *req); unsigned int dwmac_qcom_get_plat_tx_coal_frames( struct sk_buff *skb); -- GitLab From 703333543986e9e5cad1d7ac293094a0163fa8eb Mon Sep 17 00:00:00 2001 From: Zhiqiang Tu Date: Wed, 29 Apr 2020 14:25:03 +0800 Subject: [PATCH 0796/1055] clk: qcom: Add pcie1 virtio clocks for sa8155 Add clocks and resets required by pcie1 pass-through on sa8155 virtual machine. Change-Id: Ic403dab7096e9fdd35e8261aa62be757a0293e20 Signed-off-by: Zhiqiang Tu --- drivers/clk/qcom/virtio_clk_sm8150.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/clk/qcom/virtio_clk_sm8150.c b/drivers/clk/qcom/virtio_clk_sm8150.c index 7ccab3d24a55..8f2ca9430858 100644 --- a/drivers/clk/qcom/virtio_clk_sm8150.c +++ b/drivers/clk/qcom/virtio_clk_sm8150.c @@ -67,8 +67,16 @@ static const char * const sm8150_gcc_virtio_clocks[] = { [GCC_PCIE_0_SLV_AXI_CLK] = "gcc_pcie_0_slv_axi_clk", [GCC_PCIE_0_CLKREF_CLK] = "gcc_pcie_0_clkref_en", [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = "gcc_pcie_0_slv_q2a_axi_clk", + [GCC_PCIE_1_PIPE_CLK] = "gcc_pcie_1_pipe_clk", + [GCC_PCIE_1_AUX_CLK] = "gcc_pcie_1_aux_clk", + [GCC_PCIE_1_CFG_AHB_CLK] = "gcc_pcie_1_cfg_ahb_clk", + [GCC_PCIE_1_MSTR_AXI_CLK] = "gcc_pcie_1_mstr_axi_clk", + [GCC_PCIE_1_SLV_AXI_CLK] = "gcc_pcie_1_slv_axi_clk", + [GCC_PCIE_1_CLKREF_CLK] = "gcc_pcie_1_clkref_en", + [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = "gcc_pcie_1_slv_q2a_axi_clk", [GCC_AGGRE_NOC_PCIE_TBU_CLK] = "gcc_aggre_noc_pcie_tbu_clk", [GCC_PCIE0_PHY_REFGEN_CLK] = "gcc_pcie0_phy_refgen_clk", + [GCC_PCIE1_PHY_REFGEN_CLK] = "gcc_pcie1_phy_refgen_clk", [GCC_PCIE_PHY_AUX_CLK] = "gcc_pcie_phy_aux_clk", [GCC_SDCC2_AHB_CLK] = "gcc_sdcc2_ahb_clk", [GCC_SDCC2_APPS_CLK] = "gcc_sdcc2_apps_clk", @@ -86,6 +94,8 @@ static const char * const sm8150_gcc_virtio_resets[] = { [GCC_USB30_SEC_BCR] = "gcc_usb30_sec_master_clk", [GCC_PCIE_0_BCR] = "gcc_pcie_0_mstr_axi_clk", [GCC_PCIE_0_PHY_BCR] = "gcc_pcie_0_phy_bcr", + [GCC_PCIE_1_BCR] = "gcc_pcie_1_mstr_axi_clk", + [GCC_PCIE_1_PHY_BCR] = "gcc_pcie_1_phy_bcr", }; const struct clk_virtio_desc clk_virtio_sm8150_gcc = { -- GitLab From c68a679d8cc4452ab70c5b94dc66d786a6c1ea9c Mon Sep 17 00:00:00 2001 From: Zhiqiang Tu Date: Wed, 29 Apr 2020 15:20:59 +0800 Subject: [PATCH 0797/1055] ARM: dts: msm: Add pcie1 support for sa8155 virtual machine Add pcie1 root complex support for sa8155 virtual machine. Change-Id: I41dba27b80bd309d31573d74d44c24dd03744f9f Signed-off-by: Zhiqiang Tu --- arch/arm64/boot/dts/qcom/sa8155-vm-pcie.dtsi | 318 ++++++++++++++++++- 1 file changed, 317 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-pcie.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-pcie.dtsi index 25a6729be286..aaa7cdd99828 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-pcie.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, 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 @@ -283,4 +283,320 @@ status = "disabled"; }; + + pcie1: qcom,pcie@1c08000 { + compatible = "qcom,pci-msm"; + cell-index = <1>; + + reg = <0x1c08000 0x4000>, + <0x1c0e000 0x2000>, + <0x40000000 0xf1d>, + <0x40000f20 0xa8>, + <0x40001000 0x1000>, + <0x40100000 0x100000>, + <0x40200000 0x100000>, + <0x40300000 0x1fd00000>; + + reg-names = "parf", "phy", "dm_core", "elbi", + "iatu", "conf", "io", "bars"; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x40200000 0x40200000 0x0 0x100000>, + <0x02000000 0x0 0x40300000 0x40300000 0x0 0x1fd00000>; + interrupt-parent = <&pcie1>; + interrupts = <0 1 2 3 4>; + interrupt-names = "int_global_int", "int_a", "int_b", "int_c", + "int_d"; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0xffffffff>; + interrupt-map = <0 0 0 0 &intc 0 306 0 + 0 0 0 1 &intc 0 434 0 + 0 0 0 2 &intc 0 435 0 + 0 0 0 3 &intc 0 438 0 + 0 0 0 4 &intc 0 439 0>; + + qcom,phy-sequence = <0x0a40 0x03 0x0 + 0x0010 0x00 0x0 + 0x001c 0x31 0x0 + 0x0020 0x01 0x0 + 0x0024 0xde 0x0 + 0x0028 0x07 0x0 + 0x0030 0x4c 0x0 + 0x0034 0x06 0x0 + 0x0048 0x90 0x0 + 0x0058 0x0f 0x0 + 0x0074 0x06 0x0 + 0x0078 0x06 0x0 + 0x007c 0x16 0x0 + 0x0080 0x16 0x0 + 0x0084 0x36 0x0 + 0x0088 0x36 0x0 + 0x0094 0x08 0x0 + 0x00a4 0x42 0x0 + 0x00ac 0x0a 0x0 + 0x00b0 0x1a 0x0 + 0x00b4 0x14 0x0 + 0x00b8 0x34 0x0 + 0x00bc 0x82 0x0 + 0x00c4 0x68 0x0 + 0x00cc 0x55 0x0 + 0x00d0 0x55 0x0 + 0x00d4 0x03 0x0 + 0x00d8 0xab 0x0 + 0x00dc 0xaa 0x0 + 0x00e0 0x02 0x0 + 0x010c 0x02 0x0 + 0x0110 0x24 0x0 + 0x0118 0xb4 0x0 + 0x011c 0x03 0x0 + 0x0154 0x34 0x0 + 0x0158 0x01 0x0 + 0x016c 0x08 0x0 + 0x01ac 0xb9 0x0 + 0x01b0 0x1e 0x0 + 0x01b4 0x94 0x0 + 0x01b8 0x18 0x0 + 0x01bc 0x11 0x0 + 0x023c 0x11 0x0 + 0x0284 0x35 0x0 + 0x0288 0x82 0x0 + 0x029c 0x12 0x0 + 0x0304 0x02 0x0 + 0x0408 0x0c 0x0 + 0x0414 0x03 0x0 + 0x0434 0x7f 0x0 + 0x0444 0x70 0x0 + 0x0460 0x30 0x0 + 0x0464 0x00 0x0 + 0x04d4 0x04 0x0 + 0x04d8 0x07 0x0 + 0x04dc 0x0d 0x0 + 0x04e8 0x00 0x0 + 0x04ec 0x0e 0x0 + 0x04f0 0x4a 0x0 + 0x04f4 0x0f 0x0 + 0x04f8 0xc0 0x0 + 0x04fc 0x00 0x0 + 0x0510 0x17 0x0 + 0x0518 0x1c 0x0 + 0x051c 0x03 0x0 + 0x0524 0x1e 0x0 + 0x0570 0xff 0x0 + 0x0574 0xff 0x0 + 0x0578 0xff 0x0 + 0x057c 0x7f 0x0 + 0x0580 0x66 0x0 + 0x0584 0x24 0x0 + 0x0588 0xe4 0x0 + 0x058c 0xec 0x0 + 0x0590 0x3b 0x0 + 0x0594 0x36 0x0 + 0x0598 0xd4 0x0 + 0x059c 0x54 0x0 + 0x05a0 0xdb 0x0 + 0x05a4 0x3b 0x0 + 0x05a8 0x31 0x0 + 0x05bc 0x0c 0x0 + 0x063c 0x11 0x0 + 0x0684 0x35 0x0 + 0x0688 0x82 0x0 + 0x069c 0x12 0x0 + 0x0704 0x20 0x0 + 0x0808 0x0c 0x0 + 0x0814 0x03 0x0 + 0x0834 0x7f 0x0 + 0x0844 0x70 0x0 + 0x0860 0x30 0x0 + 0x0864 0x00 0x0 + 0x08d4 0x04 0x0 + 0x08d8 0x07 0x0 + 0x08dc 0x0d 0x0 + 0x08e8 0x00 0x0 + 0x08ec 0x0e 0x0 + 0x08f0 0x4a 0x0 + 0x08f4 0x0f 0x0 + 0x08f8 0xc0 0x0 + 0x08fc 0x00 0x0 + 0x0910 0x17 0x0 + 0x0918 0x1c 0x0 + 0x091c 0x03 0x0 + 0x0924 0x1e 0x0 + 0x0970 0xff 0x0 + 0x0974 0xff 0x0 + 0x0978 0xff 0x0 + 0x097c 0x7f 0x0 + 0x0980 0x66 0x0 + 0x0984 0x24 0x0 + 0x0988 0xe4 0x0 + 0x098c 0xec 0x0 + 0x0990 0x3b 0x0 + 0x0994 0x36 0x0 + 0x0998 0xd4 0x0 + 0x099c 0x54 0x0 + 0x09a0 0xdb 0x0 + 0x09a4 0x3b 0x0 + 0x09a8 0x31 0x0 + 0x09bc 0x0c 0x0 + 0x0adc 0x05 0x0 + 0x0b88 0x88 0x0 + 0x0b98 0x0b 0x0 + 0x0ba4 0x01 0x0 + 0x0bec 0x12 0x0 + 0x0e0c 0x0d 0x0 + 0x0e14 0x07 0x0 + 0x0e1c 0xc1 0x0 + 0x0e40 0x01 0x0 + 0x0e48 0x01 0x0 + 0x0e90 0x00 0x0 + 0x0eb4 0x33 0x0 + 0x0ebc 0x00 0x0 + 0x0ee0 0x58 0x0 + 0x0ea4 0x0f 0x0 + 0x0a00 0x00 0x0 + 0x0a44 0x03 0x0>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie1_clkreq_default + &pcie1_perst_default + &pcie1_wake_default>; + + perst-gpio = <&tlmm 102 0>; + wake-gpio = <&tlmm 104 0>; + + gdsc-vdd-supply = <&pcie_1_gdsc>; + vreg-1.8-supply = <&pm8150_2_l8>; + vreg-0.9-supply = <&pm8150_2_l18>; + vreg-cx-supply = <&VDD_CX_LEVEL>; + + qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>; + qcom,vreg-0.9-voltage-level = <880000 880000 24000>; + qcom,vreg-cx-voltage-level = ; + qcom,bw-scale = ; + + msi-parent = <&pcie1_msi>; + + qcom,no-l0s-supported; + + qcom,ep-latency = <10>; + + qcom,slv-addr-space-size = <0x20000000>; + + qcom,phy-status-offset = <0xa14>; + qcom,phy-status-bit = <6>; + qcom,phy-power-down-offset = <0xa40>; + qcom,core-preset = <0x77777777>; + + qcom,boot-option = <0x1>; + + linux,pci-domain = <1>; + + qcom,pcie-phy-ver = <2111>; + qcom,use-19p2mhz-aux-clk; + + qcom,smmu-sid-base = <0x1e00>; + + iommu-map = <0x0 &apps_smmu 0x1e00 0x1>, + <0x100 &apps_smmu 0x1e01 0x1>, + <0x200 &apps_smmu 0x1e02 0x1>, + <0x300 &apps_smmu 0x1e03 0x1>, + <0x400 &apps_smmu 0x1e04 0x1>, + <0x500 &apps_smmu 0x1e05 0x1>, + <0x600 &apps_smmu 0x1e06 0x1>, + <0x700 &apps_smmu 0x1e07 0x1>, + <0x800 &apps_smmu 0x1e08 0x1>, + <0x900 &apps_smmu 0x1e09 0x1>, + <0xa00 &apps_smmu 0x1e0a 0x1>, + <0xb00 &apps_smmu 0x1e0b 0x1>, + <0xc00 &apps_smmu 0x1e0c 0x1>, + <0xd00 &apps_smmu 0x1e0d 0x1>, + <0xe00 &apps_smmu 0x1e0e 0x1>, + <0xf00 &apps_smmu 0x1e0f 0x1>; + + qcom,msm-bus,name = "pcie1"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 500 800>; + + clocks = <&clock_virt GCC_PCIE_1_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_virt GCC_PCIE_1_AUX_CLK>, + <&clock_virt GCC_PCIE_1_CFG_AHB_CLK>, + <&clock_virt GCC_PCIE_1_MSTR_AXI_CLK>, + <&clock_virt GCC_PCIE_1_SLV_AXI_CLK>, + <&clock_virt GCC_PCIE_1_CLKREF_CLK>, + <&clock_virt GCC_PCIE_1_SLV_Q2A_AXI_CLK>, + <&clock_virt GCC_AGGRE_NOC_PCIE_TBU_CLK>, + <&clock_virt GCC_PCIE1_PHY_REFGEN_CLK>, + <&clock_virt GCC_PCIE_PHY_AUX_CLK>; + + clock-names = "pcie_1_pipe_clk", "pcie_1_ref_clk_src", + "pcie_1_aux_clk", "pcie_1_cfg_ahb_clk", + "pcie_1_mstr_axi_clk", "pcie_1_slv_axi_clk", + "pcie_1_ldo", "pcie_1_slv_q2a_axi_clk", + "pcie_tbu_clk", "pcie_phy_refgen_clk", + "pcie_phy_aux_clk"; + + max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, <0>, + <0>, <0>, <0>, <0>, <100000000>, <0>; + + resets = <&clock_virt GCC_PCIE_1_BCR>, + <&clock_virt GCC_PCIE_1_PHY_BCR>; + + reset-names = "pcie_1_core_reset", + "pcie_1_phy_reset"; + + status = "disabled"; + + pcie_rc1: pcie_rc1 { + #address-cells = <5>; + #size-cells = <0>; + reg = <0 0 0 0 0>; + pci-ids = "17cb:0108"; + }; + }; + + pcie1_msi: qcom,pcie1_msi@17a00040 { + compatible = "qcom,pci-msi"; + msi-controller; + reg = <0x17a00040 0x0>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + status = "disabled"; + }; }; -- GitLab From edd6206bd7db671ef1cb86c64492573a77c8ef90 Mon Sep 17 00:00:00 2001 From: Sanjana B Date: Fri, 8 May 2020 11:15:31 +0530 Subject: [PATCH 0798/1055] arm64: dts: qcs405: Add src clk strings Add src clk strings for integral and fract clk source names. Change-Id: I9fab98a9a23a7ced7330f577abdc362594b291ce Signed-off-by: Sanjana B --- arch/arm64/boot/dts/qcom/qcs405-audio.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi b/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi index feb80a1c13bd..4d7d69791971 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-audio.dtsi @@ -81,6 +81,9 @@ qcom,ep92-busnum = <3>; qcom,ep92-reg = <0x64>; + qcom,clk-src-name-integ = "LPAPLL0"; + qcom,clk-src-name-fract = "LPAPLL2"; + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, <&afe>, <&lsm>, <&routing>, <&compr>, -- GitLab From 2c949e199bf2394c769823fe2b3cc9f17ba3d67d Mon Sep 17 00:00:00 2001 From: Ashish Kori Date: Tue, 2 Jun 2020 14:48:31 +0530 Subject: [PATCH 0799/1055] ARM: dts: msm: Correct pinctrl console UART setting Change UART sleep state bias configuration to bias-pull-down to save power in system suspend state. Change-Id: I0ed2b7c314a373d6a6fabd29b5386cf2f3de3098 Signed-off-by: Ashish Kori --- arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi index d401ac179daf..bf2ec94a56b7 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-pinctrl.dtsi @@ -5001,7 +5001,7 @@ config { pins = "gpio85", "gpio86"; drive-strength = <2>; - bias-disable; + bias-pull-down; }; }; }; -- GitLab From 17762e9a30070ab673a8fa26c79b3efe62b57a3b Mon Sep 17 00:00:00 2001 From: Jilai Wang Date: Wed, 3 Jun 2020 13:35:26 -0400 Subject: [PATCH 0800/1055] msm: npu: refactor wait_for_status_ready to reduce the latency This change is to refactor function wait_for_status_ready to support register polling without context switch. If the fw processing time is very short and the task requires short processing latency, polling mode should be used. Change-Id: Ia6cd630451eee593f6e07ce73172fac4def8b9d8 Signed-off-by: Jilai Wang --- drivers/media/platform/msm/npu/npu_mgr.c | 44 ++++++++++++++++-------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/msm/npu/npu_mgr.c b/drivers/media/platform/msm/npu/npu_mgr.c index 539cf843872f..d29212635d1c 100644 --- a/drivers/media/platform/msm/npu/npu_mgr.c +++ b/drivers/media/platform/msm/npu/npu_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, 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 @@ -32,7 +32,7 @@ #define LOG_MSG_TOTAL_SIZE_INDEX 0 #define LOG_MSG_MSG_ID_INDEX 1 -#define NPU_FW_TIMEOUT_POLL_INTERVAL_MS 20 +#define NPU_FW_TIMEOUT_POLL_INTERVAL_MS 10 #define NPU_FW_TIMEOUT_MS 1000 /* ------------------------------------------------------------------------- @@ -43,7 +43,7 @@ static void host_irq_wq(struct work_struct *work); static void fw_deinit_wq(struct work_struct *work); static void turn_off_fw_logging(struct npu_device *npu_dev); static int wait_for_status_ready(struct npu_device *npu_dev, - uint32_t status_reg, uint32_t status_bits); + uint32_t status_reg, uint32_t status_bits, bool poll); static struct npu_network *alloc_network(struct npu_host_ctx *ctx, struct npu_client *client); static struct npu_network *get_network_by_hdl(struct npu_host_ctx *ctx, @@ -158,7 +158,7 @@ int fw_init(struct npu_device *npu_dev) pr_debug("waiting for status ready from fw\n"); if (wait_for_status_ready(npu_dev, REG_NPU_FW_CTRL_STATUS, - FW_CTRL_STATUS_MAIN_THREAD_READY_VAL)) { + FW_CTRL_STATUS_MAIN_THREAD_READY_VAL, true)) { ret = -EPERM; need_retry = true; goto wait_fw_ready_fail; @@ -255,7 +255,7 @@ void fw_deinit(struct npu_device *npu_dev, bool ssr, bool fw_alive) pr_debug("waiting for shutdown status from fw\n"); if (wait_for_status_ready(npu_dev, REG_NPU_FW_CTRL_STATUS, - FW_CTRL_STATUS_SHUTDOWN_DONE_VAL)) { + FW_CTRL_STATUS_SHUTDOWN_DONE_VAL, true)) { pr_err("wait for fw shutdown timedout\n"); ret = -ETIMEDOUT; } @@ -468,7 +468,7 @@ static void turn_off_fw_logging(struct npu_device *npu_dev) } static int wait_for_status_ready(struct npu_device *npu_dev, - uint32_t status_reg, uint32_t status_bits) + uint32_t status_reg, uint32_t status_bits, bool poll) { uint32_t ctrl_sts = 0; uint32_t wait_cnt = 0, max_wait_ms; @@ -476,20 +476,36 @@ static int wait_for_status_ready(struct npu_device *npu_dev, max_wait_ms = (host_ctx->fw_dbg_mode & FW_DBG_MODE_INC_TIMEOUT) ? NW_DEBUG_TIMEOUT_MS : NPU_FW_TIMEOUT_MS; + if (poll) + wait_cnt = max_wait_ms * 10; + else + wait_cnt = max_wait_ms / NPU_FW_TIMEOUT_POLL_INTERVAL_MS; /* keep reading status register until bits are set */ - while ((ctrl_sts & status_bits) != status_bits) { + do { ctrl_sts = REGR(npu_dev, status_reg); - msleep(NPU_FW_TIMEOUT_POLL_INTERVAL_MS); - wait_cnt += NPU_FW_TIMEOUT_POLL_INTERVAL_MS; - if (wait_cnt >= max_wait_ms) { + if ((ctrl_sts & status_bits) == status_bits) { + pr_debug("status %x[reg %x] ready received\n", + status_bits, status_reg); + break; + } + + if (!wait_cnt) { pr_err("timeout wait for status %x[%x] in reg %x\n", status_bits, ctrl_sts, status_reg); - return -EPERM; + return -ETIMEDOUT; } - } - pr_debug("status %x[reg %x] ready received\n", status_bits, status_reg); + + if (poll) + udelay(100); + else + msleep(NPU_FW_TIMEOUT_POLL_INTERVAL_MS); + + wait_cnt--; + } while (1); + return 0; + } static int npu_notify_dsp(struct npu_device *npu_dev, bool pwr_up) @@ -513,7 +529,7 @@ static int npu_notify_dsp(struct npu_device *npu_dev, bool pwr_up) INTERRUPT_RAISE_DSP(npu_dev); ret = wait_for_status_ready(npu_dev, REG_HOST_DSP_CTRL_STATUS, - ack_val); + ack_val, true); if (ret) pr_warn("No response from dsp\n"); -- GitLab From 27669dcffb91f407ee0ce0a8d184ff815785278a Mon Sep 17 00:00:00 2001 From: Ajay Prathi Date: Thu, 21 May 2020 11:47:10 +0530 Subject: [PATCH 0801/1055] ARM: dts: msm: Fix register offset to read PHY status Fix register offset used to check the PHY status after enabling the PCIe pipe clock. Access to the DBI registers requires an active pipe clock and the status register indicates if the PHY is ready. Change-Id: I8a50835e698714bf96b56735b0b17af60adb535c Signed-off-by: Siddartha Mohanadoss Signed-off-by: Ajay Prathi --- arch/arm64/boot/dts/qcom/sdxprairie.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index 4282950bec5e..b2e0fb5853bf 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -1236,7 +1236,7 @@ qcom,pcie-active-config; qcom,pcie-aggregated-irq; qcom,pcie-mhi-a7-irq; - qcom,phy-status-reg = <0x814>; + qcom,phy-status-reg2 = <0x1214>; qcom,mhi-soc-reset-offset = <0xb01b8>; qcom,phy-init = <0x1240 0x001 0x0 0x1 -- GitLab From decc40cefa1969531c82a419eaf4704d276b9a45 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 4 Jun 2020 14:45:42 -0700 Subject: [PATCH 0802/1055] mhi: cntrl: qcom: Add EDL image to the firmware table Some devices support Emergency Download Mode or EDL and could enter EDL which requires host firmware load path to push the EDL image to the device. Allow this for tests and debug mode on all devices except sdx50m as there is no expected use case for it. Change-Id: I662520a11f04fa5cf4080e73947389a7e07db83b Signed-off-by: Bhaumik Bhatt --- drivers/bus/mhi/controllers/mhi_qcom.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/bus/mhi/controllers/mhi_qcom.c b/drivers/bus/mhi/controllers/mhi_qcom.c index 81a7ee796487..26811368e6c3 100644 --- a/drivers/bus/mhi/controllers/mhi_qcom.c +++ b/drivers/bus/mhi/controllers/mhi_qcom.c @@ -33,13 +33,16 @@ struct firmware_info { }; static const struct firmware_info firmware_table[] = { - {.dev_id = 0x308, .fw_image = "sdx65m/sbl1.mbn"}, - {.dev_id = 0x307, .fw_image = "sdx60m/sbl1.mbn"}, - {.dev_id = 0x306, .fw_image = "sdx55m/sbl1.mbn"}, + {.dev_id = 0x308, .fw_image = "sdx65m/sbl1.mbn", + .edl_image = "sdx65m/edl.mbn"}, + {.dev_id = 0x307, .fw_image = "sdx60m/sbl1.mbn", + .edl_image = "sdx60m/edl.mbn"}, + {.dev_id = 0x306, .fw_image = "sdx55m/sbl1.mbn", + .edl_image = "sdx55m/edl.mbn"}, {.dev_id = 0x305, .fw_image = "sdx50m/sbl1.mbn"}, {.dev_id = 0x304, .fw_image = "sbl.mbn", .edl_image = "edl.mbn"}, /* default, set to debug.mbn */ - {.fw_image = "debug.mbn"}, + {.fw_image = "debug.mbn", .edl_image = "debug.mbn"}, }; static int debug_mode; -- GitLab From f4c681c6b7c58aec0f85aa1560311d9e462e7091 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Wed, 1 Apr 2020 16:51:39 +0530 Subject: [PATCH 0803/1055] ARM: dts: msm: Remove low temperature monitor thermal zones for SA8155 Remove low temperature monitor thermal zones for SA8155 as per latest recommendation. Change-Id: Ifdd660a4a9d45b2b431e491dd61d26d8d572d0a0 Signed-off-by: Manaf Meethalavalappu Pallikunhi --- .../arm64/boot/dts/qcom/sa8155-regulator.dtsi | 24 +------------------ arch/arm64/boot/dts/qcom/sa8155.dtsi | 24 ++++--------------- 2 files changed, 5 insertions(+), 43 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi b/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi index 33e45516d62d..994c4bf4eb71 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-regulator.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, 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 @@ -459,13 +459,6 @@ = ; qcom,min-dropout-voltage-level = <(-1)>; }; - - cx_cdev: regulator-cdev { - compatible = "qcom,rpmh-reg-cdev"; - mboxes = <&qmp_aop 0>; - qcom,reg-resource-name = "cx"; - #cooling-cells = <2>; - }; }; /* PM8150_2 S10 = VDD_MX supply */ @@ -497,14 +490,6 @@ qcom,init-voltage-level = ; }; - - mx_cdev: mx-cdev-lvl { - compatible = "qcom,regulator-cooling-device"; - regulator-cdev-supply = <&VDD_MX_LEVEL>; - regulator-levels = ; - #cooling-cells = <2>; - }; }; rpmh-regulator-ldoc1 { @@ -617,13 +602,6 @@ qcom,init-voltage-level = ; }; - - ebi_cdev: regulator-cdev { - compatible = "qcom,rpmh-reg-cdev"; - mboxes = <&qmp_aop 0>; - qcom,reg-resource-name = "ebi"; - #cooling-cells = <2>; - }; }; rpmh-regulator-ldoc12 { diff --git a/arch/arm64/boot/dts/qcom/sa8155.dtsi b/arch/arm64/boot/dts/qcom/sa8155.dtsi index c41c5e788f1a..68b14f4a71bd 100644 --- a/arch/arm64/boot/dts/qcom/sa8155.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155.dtsi @@ -221,26 +221,10 @@ }; &thermal_zones { - cpu-1-7-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; - gpuss-0-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; - camera-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; - mdm-scl-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; + /delete-node/ cpu-1-7-lowf; + /delete-node/ gpuss-0-lowf; + /delete-node/ camera-lowf; + /delete-node/ mdm-scl-lowf; lmh-dcvs-01 { trips { -- GitLab From fe63f1d68d737a32c2ee56851ed676245189a0d1 Mon Sep 17 00:00:00 2001 From: Arun Prakash Date: Sun, 17 May 2020 12:58:02 +0530 Subject: [PATCH 0804/1055] soc: qcom: smem: Support to parse smem host id The current implementation will use hard coded smem host id which will cause conflicts when gvm want to communicate with remote sub system through new smem partition area. Adding support to parse smem host id from dt entry. This will help to configure unique smem host id for gvm which needs direct communication with different sub system. Change-Id: I49865968d24a3979c766a006b16e44099a5cbd7f Signed-off-by: Arun Prakash --- drivers/soc/qcom/smem.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index fd350aee2675..0cdd98ca48f3 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -280,6 +280,9 @@ struct qcom_smem { /* Pointer to the one and only smem handle */ static struct qcom_smem *__smem; +/* default smem host id for apps is SMEM_HOST_APPS */ +static u32 smem_host_id = SMEM_HOST_APPS; + /* Timeout (ms) for the trylock of remote spinlocks */ #define HWSPINLOCK_TIMEOUT 1000 @@ -986,6 +989,7 @@ static int qcom_smem_probe(struct platform_device *pdev) int hwlock_id; u32 version; int ret; + u32 host_id; num_regions = 1; if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL)) @@ -1007,6 +1011,10 @@ static int qcom_smem_probe(struct platform_device *pdev) "qcom,rpm-msg-ram", 1))) return ret; + ret = of_property_read_u32(pdev->dev.of_node, "smem-host-id", &host_id); + if (!ret) + smem_host_id = host_id; + header = smem->regions[0].virt_base; if (le32_to_cpu(header->initialized) != 1 || le32_to_cpu(header->reserved)) { @@ -1030,7 +1038,7 @@ static int qcom_smem_probe(struct platform_device *pdev) return -EINVAL; } - ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS); + ret = qcom_smem_enumerate_partitions(smem, smem_host_id); if (ret < 0) return ret; -- GitLab From a114bcb3182a4e5cb32d62da44c367483067173b Mon Sep 17 00:00:00 2001 From: Arun Prakash Date: Sun, 1 Mar 2020 23:40:58 +0530 Subject: [PATCH 0805/1055] ARM: dts: msm: Add MPROC glink related node for gvm Adding MPROC glink related dt nodes to enable direct glink communication between GVM and remote sub system (CDSP). Change-Id: Ibf01aa831db8402c2f36f09d16de48ec01271224 Signed-off-by: Arun Prakash --- arch/arm64/boot/dts/qcom/sa8155-vm.dtsi | 59 +++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi index 5689a863ec98..f16787ef425b 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi @@ -20,6 +20,14 @@ pci-domain0 = &pcie0; /* PCIe0 domain */ sdhc2 = &sdhc_2; /* SDC2 SD card slot */ }; + + reserved_memory: reserved-memory { + + smem_region: smem { + no-map; + reg = <0x0 0x86000000 0x0 0x200000>; + }; + }; }; @@ -871,6 +879,57 @@ qcom,glb-db-receivers = <&hgsl_tcsr_receiver0 &hgsl_tcsr_receiver1>; }; + + tcsr_mutex_block: syscon@1f40000 { + compatible = "syscon"; + reg = <0x1f40000 0x20000>; + }; + + tcsr_mutex: hwlock@1f40000 { + compatible = "qcom,tcsr-mutex"; + syscon = <&tcsr_mutex_block 0 0x1000>; + #hwlock-cells = <1>; + mutex-id = <11>; + }; + + smem: qcom,smem@8600000 { + compatible = "qcom,smem"; + memory-region = <&smem_region>; + hwlocks = <&tcsr_mutex 3>; + smem-host-id = <10>; + }; + + gvm_intr: mailbox@17c00000 { + compatible = "qcom,sm8150-apcs-hmss-global"; + reg = <0x1c900000 0x100>; + #mbox-cells = <1>; + }; + + qcom,glink { + compatible = "qcom,glink"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + glink_cdsp: cdsp { + qcom,remote-pid = <5>; + transport = "smem"; + mboxes = <&gvm_intr 4>; + mbox-names = "cdsp_smem"; + interrupts = <0 51 0>; + vm-support; + + label = "cdsp"; + qcom,glink-label = "cdsp"; + + qcom,cdsp_qrtr { + qcom,glink-channels = "IPCRTR"; + qcom,intents = <0x800 5 + 0x2000 3 + 0x4400 2>; + }; + }; + }; }; #include "sm8150-pinctrl.dtsi" -- GitLab From 0c1990690606b2cad753540c8156fabfe0310110 Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Mon, 8 Jun 2020 09:56:44 +0530 Subject: [PATCH 0806/1055] diag: Add debug logs tracing diag mhi read and write paths Add debug logs to trace the status of read and write in mhi driver when external proc is undergoing ssr. Change-Id: I8dc26864236700973da100646f30f201aa07e253 Signed-off-by: Manoj Prabhu B --- drivers/char/diag/diagchar_core.c | 2 +- drivers/char/diag/diagfwd_bridge.c | 2 +- drivers/char/diag/diagfwd_mhi.c | 59 ++++++++++++++++++++++-------- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 8629e3e28886..9b953e6b7b5c 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -4290,7 +4290,7 @@ static void diag_debug_init(void) * to be logged to IPC */ diag_debug_mask = DIAG_DEBUG_PERIPHERALS | DIAG_DEBUG_DCI | - DIAG_DEBUG_USERSPACE | DIAG_DEBUG_BRIDGE; + DIAG_DEBUG_MHI | DIAG_DEBUG_USERSPACE | DIAG_DEBUG_BRIDGE; } #else static void diag_debug_init(void) diff --git a/drivers/char/diag/diagfwd_bridge.c b/drivers/char/diag/diagfwd_bridge.c index 754a53a4e229..f8f4425df428 100644 --- a/drivers/char/diag/diagfwd_bridge.c +++ b/drivers/char/diag/diagfwd_bridge.c @@ -87,7 +87,7 @@ static int diagfwd_bridge_mux_write_done(unsigned char *buf, int len, return -EINVAL; ch = &bridge_info[buf_ctx]; if (ch->dev_ops && ch->dev_ops->fwd_complete) { - DIAG_LOG(DIAG_DEBUG_MHI, + DIAG_LOG(DIAG_DEBUG_BRIDGE, "Write done completion received for buf %pK len:%d\n", buf, len); ch->dev_ops->fwd_complete(ch->ctxt, buf, len, 0); diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index 404f265beb2a..a5c3832f46f3 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2020, 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 @@ -149,9 +149,12 @@ static void mhi_buf_tbl_remove(struct diag_mhi_info *mhi_info, int type, list_del(&item->link); if (type == TYPE_MHI_READ_CH) { DIAG_LOG(DIAG_DEBUG_MHI, - "Callback received on buffer:%pK from mhi\n", buf); + "Freeing read channel buffer: %pK\n", buf); diagmem_free(driver, item->buf, mhi_info->mempool); } + DIAG_LOG(DIAG_DEBUG_MHI, + "Removing %s channel item entry from table: %pK\n", + mhi_info->name, buf); kfree(item); found = 1; } @@ -189,7 +192,7 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) &mhi_info->read_done_list, link) { if (tp->buf == buf) { DIAG_LOG(DIAG_DEBUG_MHI, - "buffer:%pK removed from table for ch:%s\n", + "Read buffer:%pK removed from table for ch:%s\n", buf, mhi_info->name); list_del(&tp->link); kfree(tp); @@ -211,6 +214,9 @@ static void mhi_buf_tbl_clear(struct diag_mhi_info *mhi_info) item = list_entry(start, struct diag_mhi_buf_tbl_t, link); list_del(&item->link); + DIAG_LOG(DIAG_DEBUG_MHI, + "Write buffer %pK removed from table for ch: %s\n", + buf, mhi_info->name); diag_remote_dev_write_done(mhi_info->dev_id, item->buf, item->len, mhi_info->id); kfree(item); @@ -237,6 +243,9 @@ static int __mhi_close(struct diag_mhi_info *mhi_info, int close_flag) if (close_flag == CLOSE_CHANNELS) { mutex_lock(&mhi_info->ch_mutex); + DIAG_LOG(DIAG_DEBUG_MHI, + "diag: %s mhi channel closed, calling mhi unprepare\n", + mhi_info->name); mhi_unprepare_from_transfer(mhi_info->mhi_dev); mutex_unlock(&mhi_info->ch_mutex); } @@ -252,8 +261,11 @@ static int mhi_close(int id) return -EINVAL; } - if (!diag_mhi[id].enabled) + if (!diag_mhi[id].enabled) { + pr_err("diag: %s: mhi channel with index: %d is not enabled\n", + __func__, id); return -ENODEV; + } /* * This function is called whenever the channel needs to be closed * explicitly by Diag. Close both the read and write channels (denoted @@ -286,9 +298,16 @@ static int __mhi_open(struct diag_mhi_info *mhi_info, int open_flag) return -ENODEV; if (open_flag == OPEN_CHANNELS) { if ((atomic_read(&(mhi_info->read_ch.opened))) && - (atomic_read(&(mhi_info->write_ch.opened)))) + (atomic_read(&(mhi_info->write_ch.opened)))) { + DIAG_LOG(DIAG_DEBUG_MHI, + "Read and write channel already open: %s\n", + mhi_info->name); return 0; + } mutex_lock(&mhi_info->ch_mutex); + DIAG_LOG(DIAG_DEBUG_MHI, + "Prepare mhi for transfer on port: %s\n", + mhi_info->name); err = mhi_prepare_for_transfer(mhi_info->mhi_dev); mutex_unlock(&mhi_info->ch_mutex); if (err) { @@ -298,9 +317,9 @@ static int __mhi_open(struct diag_mhi_info *mhi_info, int open_flag) } atomic_set(&mhi_info->read_ch.opened, 1); atomic_set(&mhi_info->write_ch.opened, 1); - DIAG_LOG(DIAG_DEBUG_BRIDGE, - "opened mhi read/write channel, port: %d\n", - mhi_info->id); + DIAG_LOG(DIAG_DEBUG_MHI, + "opened mhi read/write channel, port: %s\n", + mhi_info->name); } else if (open_flag == CHANNELS_OPENED) { if (!atomic_read(&(mhi_info->read_ch.opened)) || !atomic_read(&(mhi_info->write_ch.opened))) { @@ -387,7 +406,7 @@ static void mhi_read_done_work_fn(struct work_struct *work) spin_unlock_irqrestore(&mhi_info->read_ch.lock, flags); if (!buf) break; - DIAG_LOG(DIAG_DEBUG_BRIDGE, + DIAG_LOG(DIAG_DEBUG_MHI, "read from mhi port %d buf %pK len:%d\n", mhi_info->id, buf, len); /* @@ -453,7 +472,7 @@ static void mhi_read_work_fn(struct work_struct *work) goto fail; } - DIAG_LOG(DIAG_DEBUG_BRIDGE, + DIAG_LOG(DIAG_DEBUG_MHI, "queueing a read buf %pK, ch: %s\n", buf, mhi_info->name); @@ -525,6 +544,8 @@ static int mhi_write(int id, unsigned char *buf, int len, int ctxt) spin_unlock_irqrestore(&ch->lock, flags); goto fail; } + DIAG_LOG(DIAG_DEBUG_MHI, "diag: queueing a write buf %pK, ch: %s\n", + buf, diag_mhi[id].name); err = mhi_queue_transfer(diag_mhi[id].mhi_dev, DMA_TO_DEVICE, buf, len, mhi_flags); @@ -602,7 +623,7 @@ static void diag_mhi_read_cb(struct mhi_device *mhi_dev, spin_lock_irqsave(&mhi_info->read_ch.lock, flags); tp = kmalloc(sizeof(*tp), GFP_ATOMIC); if (!tp) { - DIAG_LOG(DIAG_DEBUG_BRIDGE, + DIAG_LOG(DIAG_DEBUG_MHI, "no mem for list\n"); spin_unlock_irqrestore(&mhi_info->read_ch.lock, flags); return; @@ -611,7 +632,7 @@ static void diag_mhi_read_cb(struct mhi_device *mhi_dev, &mhi_info->read_ch.buf_tbl, link) { if (item->buf == buf) { DIAG_LOG(DIAG_DEBUG_MHI, - "Callback received on buffer:%pK from mhi\n", + "Read callback received on buffer:%pK from mhi\n", buf); tp->buf = buf; tp->len = result->bytes_xferd; @@ -651,6 +672,9 @@ static void diag_mhi_write_cb(struct mhi_device *mhi_dev, __func__); return; } + DIAG_LOG(DIAG_DEBUG_MHI, + "Write callback received on buffer:%pK from mhi\n", + buf); mhi_buf_tbl_remove(mhi_info, TYPE_MHI_WRITE_CH, buf, result->bytes_xferd); diag_remote_dev_write_done(mhi_info->dev_id, buf, @@ -670,6 +694,11 @@ static void diag_mhi_remove(struct mhi_device *mhi_dev) return; if (!mhi_info->enabled) return; + + DIAG_LOG(DIAG_DEBUG_MHI, + "Remove called on mhi channel: %s\n", + mhi_info->name); + __mhi_close(mhi_info, CHANNELS_CLOSED); spin_lock_irqsave(&mhi_info->lock, flags); mhi_info->enabled = 0; @@ -684,11 +713,11 @@ static int diag_mhi_probe(struct mhi_device *mhi_dev, unsigned long flags; struct diag_mhi_info *mhi_info = &diag_mhi[index]; - DIAG_LOG(DIAG_DEBUG_BRIDGE, + DIAG_LOG(DIAG_DEBUG_MHI, "received probe for %d\n", index); diag_mhi[index].mhi_dev = mhi_dev; - DIAG_LOG(DIAG_DEBUG_BRIDGE, + DIAG_LOG(DIAG_DEBUG_MHI, "diag: mhi device is ready to open\n"); spin_lock_irqsave(&mhi_info->lock, flags); mhi_info->enabled = 1; @@ -758,7 +787,7 @@ int diag_mhi_init(void) i, err); goto fail; } - DIAG_LOG(DIAG_DEBUG_BRIDGE, "mhi port %d is initailzed\n", i); + DIAG_LOG(DIAG_DEBUG_MHI, "mhi port %d is initailzed\n", i); } return 0; -- GitLab From ceca36175e3f4722aef23d81dcb63d59644ededf Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Wed, 20 May 2020 16:45:47 +0530 Subject: [PATCH 0807/1055] ARM: dts: msm: Remove GPU min, low and svs levels for 8195 As per new voltage plan for MMCX rail, min, low and svs levels are not required so update the pwr levels accordingly. Change-Id: I84ab565f95fe5d089eaaa9c16f8b453b8531be88 Signed-off-by: Rahul Sharma --- arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi | 25 -------------- arch/arm64/boot/dts/qcom/sdmshrike-v2.dtsi | 38 --------------------- 2 files changed, 63 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi index 9bf56e7ddaba..65b478bb9716 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-gpu.dtsi @@ -70,15 +70,6 @@ opp-microvolt = ; }; - opp-256000000 { - opp-hz = /bits/ 64 <256000000>; - opp-microvolt = ; - }; - - opp-177000000 { - opp-hz = /bits/ 64 <177000000>; - opp-microvolt = ; - }; }; msm_gpu: qcom,kgsl-3d0@2c00000 { @@ -247,22 +238,6 @@ qcom,gpu-pwrlevel@5 { reg = <5>; - qcom,gpu-freq = <256000000>; - qcom,bus-freq = <5>; - qcom,bus-min = <5>; - qcom,bus-max = <7>; - }; - - qcom,gpu-pwrlevel@6 { - reg = <6>; - qcom,gpu-freq = <177000000>; - qcom,bus-freq = <4>; - qcom,bus-min = <3>; - qcom,bus-max = <5>; - }; - - qcom,gpu-pwrlevel@7 { - reg = <7>; qcom,gpu-freq = <0>; qcom,bus-freq = <0>; qcom,bus-min = <0>; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-v2.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-v2.dtsi index 4140806336ae..22b5b9dc3c31 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-v2.dtsi @@ -45,20 +45,6 @@ opp-microvolt = ; }; - opp-315000000 { - opp-hz = /bits/ 64 <315000000>; - opp-microvolt = ; - }; - - opp-235000000 { - opp-hz = /bits/ 64 <235000000>; - opp-microvolt = ; - }; - - opp-156000000 { - opp-hz = /bits/ 64 <156000000>; - opp-microvolt = ; - }; }; }; /* GPU overrides */ @@ -144,30 +130,6 @@ qcom,gpu-pwrlevel@5 { reg = <5>; - qcom,gpu-freq = <315000000>; - qcom,bus-freq = <3>; - qcom,bus-min = <3>; - qcom,bus-max = <8>; - }; - - qcom,gpu-pwrlevel@6 { - reg = <6>; - qcom,gpu-freq = <235000000>; - qcom,bus-freq = <2>; - qcom,bus-min = <1>; - qcom,bus-max = <8>; - }; - - qcom,gpu-pwrlevel@7 { - reg = <7>; - qcom,gpu-freq = <156000000>; - qcom,bus-freq = <2>; - qcom,bus-min = <1>; - qcom,bus-max = <8>; - }; - - qcom,gpu-pwrlevel@8 { - reg = <8>; qcom,gpu-freq = <0>; qcom,bus-freq = <0>; qcom,bus-min = <0>; -- GitLab From 379abf34617ab40bed4256c985b236d53434f37a Mon Sep 17 00:00:00 2001 From: Nagireddy Annem Date: Mon, 8 Jun 2020 20:12:07 +0530 Subject: [PATCH 0808/1055] arm: Make COMMAND_LINE_SIZE a kernel config option Make COMMAND_LINE_SIZE a kernel config option to configure command line size as required per target. Change-Id: I1fe01812fd04940987230286381b9ed11d630f19 Signed-off-by: Nagireddy Annem --- arch/arm/Kconfig | 6 ++++++ arch/arm/include/uapi/asm/setup.h | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9d2001edb7b2..7e23076b2817 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1471,6 +1471,12 @@ config PAGE_OFFSET default 0xB0000000 if VMSPLIT_3G_OPT default 0xC0000000 +config COMMAND_LINE_SIZE + int "Maximum size of the command line." + default "1024" + help + This is the per architecture maximum command line size. + config NR_CPUS int "Maximum number of CPUs (2-32)" range 2 32 diff --git a/arch/arm/include/uapi/asm/setup.h b/arch/arm/include/uapi/asm/setup.h index 6b335a9ff8c8..977373fa9992 100644 --- a/arch/arm/include/uapi/asm/setup.h +++ b/arch/arm/include/uapi/asm/setup.h @@ -17,7 +17,9 @@ #include -#define COMMAND_LINE_SIZE 1024 +#ifdef CONFIG_COMMAND_LINE_SIZE +#define COMMAND_LINE_SIZE CONFIG_COMMAND_LINE_SIZE +#endif /* The list ends with an ATAG_NONE node. */ #define ATAG_NONE 0x00000000 -- GitLab From c18da7fa06ca56135517f5573317ec90dbf60231 Mon Sep 17 00:00:00 2001 From: Nagireddy Annem Date: Mon, 8 Jun 2020 20:42:25 +0530 Subject: [PATCH 0809/1055] defconfig: Increase command line size to 2048 for SDM429 BG Increase Command line size to 2048 to accommodate avb2.0 boot arguemnets. Change-Id: I59ff896ac112641a5db239d4b10da39daf549ffa Signed-off-by: Nagireddy Annem --- arch/arm/configs/vendor/sdm429-bg-perf_defconfig | 1 + arch/arm/configs/vendor/sdm429-bg_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig index c885f8a5de34..f7b1fbb3a6ab 100644 --- a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig @@ -59,6 +59,7 @@ CONFIG_ARCH_SDM429W=y CONFIG_PCI_MSM=y CONFIG_SMP=y CONFIG_SCHED_MC=y +CONFIG_COMMAND_LINE_SIZE=2048 CONFIG_NR_CPUS=8 CONFIG_ARM_PSCI=y CONFIG_PREEMPT=y diff --git a/arch/arm/configs/vendor/sdm429-bg_defconfig b/arch/arm/configs/vendor/sdm429-bg_defconfig index dccf0a684ba5..072e44e45f2e 100644 --- a/arch/arm/configs/vendor/sdm429-bg_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg_defconfig @@ -59,6 +59,7 @@ CONFIG_ARCH_SDM429W=y # CONFIG_VDSO is not set CONFIG_SMP=y CONFIG_SCHED_MC=y +CONFIG_COMMAND_LINE_SIZE=2048 CONFIG_NR_CPUS=8 CONFIG_ARM_PSCI=y CONFIG_PREEMPT=y -- GitLab From 128102b456e4cbb6b6cbd6323acfb08cb50bd7dd Mon Sep 17 00:00:00 2001 From: Bojun Pan Date: Fri, 22 May 2020 13:38:17 -0700 Subject: [PATCH 0810/1055] msm: ipa: Move the QMI for mhi pipe info to modem bootup In Q6 standalone ssr, the mhi host is not aware of the ssr so it will not stop/start the channel. In this case, the QMI won't be send again so that Q6 will lose the pipe info. The fix here is to move the QMI to modem bootup routine so after ssr, this qmi would be sent again. Change-Id: I3c9e4830359f05bc9ab729ffca30a1a0bcba7407 Signed-off-by: Bojun Pan --- drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c | 40 --------------------- drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 32 ++++++++++++++++- 2 files changed, 31 insertions(+), 41 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c index 75c4bb1ed76f..1f7feb320e0f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c @@ -20,7 +20,6 @@ #include #include "../ipa_common_i.h" #include "ipa_i.h" -#include "ipa_qmi_service.h" #define IPA_MHI_DRV_NAME "ipa_mhi" @@ -106,33 +105,6 @@ bool ipa3_mhi_stop_gsi_channel(enum ipa_client_type client) return false; } -static int ipa3_mhi_send_endp_ind_to_modem(void) -{ - struct ipa_endp_desc_indication_msg_v01 req; - struct ipa_ep_id_type_v01 *ep_info; - int ipa_mhi_prod_ep_idx = - ipa3_get_ep_mapping(IPA_CLIENT_MHI_LOW_LAT_PROD); - int ipa_mhi_cons_ep_idx = - ipa3_get_ep_mapping(IPA_CLIENT_MHI_LOW_LAT_CONS); - - memset(&req, 0, sizeof(struct ipa_endp_desc_indication_msg_v01)); - req.ep_info_len = 2; - req.ep_info_valid = true; - req.num_eps_valid = true; - req.num_eps = 2; - ep_info = &req.ep_info[0]; - ep_info->ep_id = ipa_mhi_cons_ep_idx; - ep_info->ic_type = DATA_IC_TYPE_MHI_V01; - ep_info->ep_type = DATA_EP_DESC_TYPE_EMB_FLOW_CTL_PROD_V01; - ep_info->ep_status = DATA_EP_STATUS_CONNECTED_V01; - ep_info = &req.ep_info[1]; - ep_info->ep_id = ipa_mhi_prod_ep_idx; - ep_info->ic_type = DATA_IC_TYPE_MHI_V01; - ep_info->ep_type = DATA_EP_DESC_TYPE_EMB_FLOW_CTL_CONS_V01; - ep_info->ep_status = DATA_EP_STATUS_CONNECTED_V01; - return ipa3_qmi_send_endp_desc_indication(&req); -} - static int ipa3_mhi_reset_gsi_channel(enum ipa_client_type client) { int res; @@ -559,10 +531,6 @@ int ipa3_connect_mhi_pipe(struct ipa_mhi_connect_params_internal *in, int ipa_ep_idx; int res; enum ipa_client_type client; - int ipa_mhi_prod_ep_idx = - ipa3_get_ep_mapping(IPA_CLIENT_MHI_LOW_LAT_PROD); - int ipa_mhi_cons_ep_idx = - ipa3_get_ep_mapping(IPA_CLIENT_MHI_LOW_LAT_CONS); IPA_MHI_FUNC_ENTRY(); @@ -608,14 +576,6 @@ int ipa3_connect_mhi_pipe(struct ipa_mhi_connect_params_internal *in, ipa3_ctx->skip_ep_cfg_shadow[ipa_ep_idx] = ep->skip_ep_cfg; IPA_MHI_DBG("client %d (ep: %d) connected\n", client, ipa_ep_idx); - if ((client == IPA_CLIENT_MHI_LOW_LAT_PROD || - client == IPA_CLIENT_MHI_LOW_LAT_CONS) && - ipa_mhi_prod_ep_idx != -1 && - ipa3_ctx->ep[ipa_mhi_prod_ep_idx].valid && - ipa_mhi_cons_ep_idx != -1 && - ipa3_ctx->ep[ipa_mhi_cons_ep_idx].valid) - ipa3_mhi_send_endp_ind_to_modem(); - IPA_MHI_FUNC_EXIT(); return 0; diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 5bc34f896cd9..8c2f12e6dc2c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -1486,8 +1486,35 @@ static void apps_ipa_packet_receive_notify(void *priv, } } -/* Send RSC endpoint info to modem using QMI indication message */ +/* Send MHI endpoint info to modem using QMI indication message */ +static int ipa_send_mhi_endp_ind_to_modem(void) +{ + struct ipa_endp_desc_indication_msg_v01 req; + struct ipa_ep_id_type_v01 *ep_info; + int ipa_mhi_prod_ep_idx = + ipa3_get_ep_mapping(IPA_CLIENT_MHI_LOW_LAT_PROD); + int ipa_mhi_cons_ep_idx = + ipa3_get_ep_mapping(IPA_CLIENT_MHI_LOW_LAT_CONS); + + memset(&req, 0, sizeof(struct ipa_endp_desc_indication_msg_v01)); + req.ep_info_len = 2; + req.ep_info_valid = true; + req.num_eps_valid = true; + req.num_eps = 2; + ep_info = &req.ep_info[0]; + ep_info->ep_id = ipa_mhi_cons_ep_idx; + ep_info->ic_type = DATA_IC_TYPE_MHI_V01; + ep_info->ep_type = DATA_EP_DESC_TYPE_EMB_FLOW_CTL_PROD_V01; + ep_info->ep_status = DATA_EP_STATUS_CONNECTED_V01; + ep_info = &req.ep_info[1]; + ep_info->ep_id = ipa_mhi_prod_ep_idx; + ep_info->ic_type = DATA_IC_TYPE_MHI_V01; + ep_info->ep_type = DATA_EP_DESC_TYPE_EMB_FLOW_CTL_CONS_V01; + ep_info->ep_status = DATA_EP_STATUS_CONNECTED_V01; + return ipa3_qmi_send_endp_desc_indication(&req); +} +/* Send RSC endpoint info to modem using QMI indication message */ static int ipa_send_rsc_pipe_ind_to_modem(void) { struct ipa_endp_desc_indication_msg_v01 req; @@ -4137,6 +4164,9 @@ void ipa3_q6_handshake_complete(bool ssr_bootup) } if (ipa3_ctx->ipa_mhi_proxy) imp_handle_modem_ready(); + + if (ipa3_ctx->ipa_config_is_mhi) + ipa_send_mhi_endp_ind_to_modem(); } static inline bool rmnet_ipa3_check_any_client_inited -- GitLab From 01c2f19797c24f2176c5a15a63eae3dc154b8d26 Mon Sep 17 00:00:00 2001 From: Sivasri Kumar Vanka Date: Tue, 9 Jun 2020 10:01:35 +0530 Subject: [PATCH 0811/1055] usb: gadget: notify suspend clear to usb phy in udc When usb composition switch happens from composition containing adb eg. 9025 to non adb compositions like 905B/9063, usb goes to lpm in middle of MBIM/RNDIS protocol transaction. PCNOC crash happens when MBIM/RNDIS call ep_queue. When usb composition switch happens from non adb composition like F000 to non adb compositions like 905B/9063, then usb goes to lpm before usb composition switch complete. Also MBIM/RNDIS protocol transactions do not happen. By notify suspend clear to usb phy in udc, solves the problem. Change-Id: Ibe7df918b22ca8422d50e3cc76ade1e14f4a5312 Signed-off-by: Sivasri Kumar Vanka --- drivers/usb/gadget/ci13xxx_udc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index be3172e385b5..3a61ee06e201 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -3543,6 +3543,15 @@ static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_active) hw_device_state(udc->ep0out.qh.dma); } else { hw_device_state(0); + if (udc->suspended) { + if (udc->udc_driver->notify_event) + udc->udc_driver->notify_event(udc, + CI13XXX_CONTROLLER_RESUME_EVENT); + if (udc->transceiver) + usb_phy_set_suspend(udc->transceiver, 0); + udc->driver->resume(&udc->gadget); + udc->suspended = 0; + } spin_unlock_irqrestore(udc->lock, flags); _gadget_stop_activity(&udc->gadget); spin_lock_irqsave(udc->lock, flags); -- GitLab From c0dbf3be0891622c5c7abcef26361f934575e7d4 Mon Sep 17 00:00:00 2001 From: Sridhar Arra Date: Tue, 9 Jun 2020 12:58:11 +0530 Subject: [PATCH 0812/1055] ARM: dts: msm: Retain the copyright year Retain the copyright year for commit 731696ac2986 ("ARM: dts: msm: Add eMMC and SD card support on QCS410"). Change-Id: I54122e336b183c75e6379c0ae628020ada4749fd Signed-off-by: Sridhar Arra --- arch/arm64/boot/dts/qcom/qcs410-iot.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi b/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi index 96fb1d37b317..2d35d00c1847 100644 --- a/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, 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 -- GitLab From 1cdff5beebf7959a360891355c321bf9a6204c4e Mon Sep 17 00:00:00 2001 From: Sneh Shah Date: Tue, 26 May 2020 22:11:33 +0530 Subject: [PATCH 0813/1055] arm: dts: msm: set descriptor count to 512 for IPA channel Add dt entry to set desciprot count to 512 for IPA channel. Change-Id: I9c4ba59f8efa79465d76a9d0468ba2375d74875e Signed-off-by: sneh shah --- arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi | 2 ++ arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi b/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi index f7a7966cd9d2..e0d03885f69d 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi @@ -246,6 +246,8 @@ pinctrl-1 = <&emac_pin_pps_0>; pinctrl-2 = <&emac_pin_pps_1>; qcom,phy-reset-delay-msecs = <10>; + ipa-dma-rx-desc-cnt = <512>; + ipa-dma-tx-desc-cnt = <512>; }; &vreg_rgmii_io_pads { diff --git a/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi b/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi index 8fac0f31e969..ff584090a004 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi +++ b/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi @@ -59,6 +59,11 @@ status = "disabled"; }; +ðqos_hw { + ipa-dma-rx-desc-cnt = <512>; + ipa-dma-tx-desc-cnt = <512>; +}; + &soc { bluetooth: bt_qca6390 { compatible = "qca,qca6390"; -- GitLab From 05990e2bfa15dd4ffe7cfea712182aa3d2d3d1ea Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Tue, 9 Jun 2020 18:32:28 +0530 Subject: [PATCH 0814/1055] ARM: dts: msm: Add WLAN pin control support on sdm429w Add wlan pin controls for pronto wlan target. Change-Id: I2534ba00d4fb84ba46a393393a63ff51bfea7433 Signed-off-by: Govind Singh --- arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi | 79 ++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi index 78e6b2cf2c3b..292a515a9982 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi @@ -825,5 +825,84 @@ }; }; }; + + wcnss_pmux_5wire { + /* Active configuration of bus pins */ + wcnss_default: wcnss_default { + wcss_wlan2 { + pins = "gpio76"; + function = "wcss_wlan2"; + }; + wcss_wlan1 { + pins = "gpio77"; + function = "wcss_wlan1"; + }; + wcss_wlan0 { + pins = "gpio78"; + function = "wcss_wlan0"; + }; + wcss_wlan { + pins = "gpio79", "gpio80"; + function = "wcss_wlan"; + }; + + config { + pins = "gpio76", "gpio77", + "gpio78", "gpio79", + "gpio80"; + drive-strength = <6>; /* 6 MA */ + bias-pull-up; /* PULL UP */ + }; + }; + + wcnss_sleep: wcnss_sleep { + wcss_wlan2 { + pins = "gpio76"; + function = "wcss_wlan2"; + }; + wcss_wlan1 { + pins = "gpio77"; + function = "wcss_wlan1"; + }; + wcss_wlan0 { + pins = "gpio78"; + function = "wcss_wlan0"; + }; + wcss_wlan { + pins = "gpio79", "gpio80"; + function = "wcss_wlan"; + }; + + config { + pins = "gpio76", "gpio77", + "gpio78", "gpio79", + "gpio80"; + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* PULL Down */ + }; + }; + }; + + wcnss_pmux_gpio: wcnss_pmux_gpio { + wcnss_gpio_default: wcnss_gpio_default { + /* Active configuration of bus pins */ + mux { + /* Uses general purpose pins */ + pins = "gpio76", "gpio77", + "gpio78", "gpio79", + "gpio80"; + function = "gpio"; + + }; + + config { + pins = "gpio76", "gpio77", + "gpio78", "gpio79", + "gpio80"; + drive-strength = <6>; /* 6 MA */ + bias-pull-up; /* PULL UP */ + }; + }; + }; }; }; -- GitLab From ee94052b11c8ee351a9c3046d52ed9c7768e9872 Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Tue, 9 Jun 2020 19:10:40 +0530 Subject: [PATCH 0815/1055] mtd: msm_qpic_nand: Add a check to read an ONFI parameter page Add support to read an ONFI parameter page from the device on QPIC 2.0 controllers. Change-Id: I30e8696c17733dc745c6857c0dcb436764f229e2 Signed-off-by: Pradeep P V K --- drivers/mtd/devices/msm_qpic_nand.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c index e094673f9cac..ea6c4ed2c1f8 100644 --- a/drivers/mtd/devices/msm_qpic_nand.c +++ b/drivers/mtd/devices/msm_qpic_nand.c @@ -881,10 +881,12 @@ static int msm_nand_flash_onfi_probe(struct msm_nand_info *info) struct version nandc_version = {0}; ret = msm_nand_version_check(info, &nandc_version); - if (!ret && !(nandc_version.nand_major == 1 && + if (!ret && !((nandc_version.nand_major == 1 && nandc_version.nand_minor >= 5 && nandc_version.qpic_major == 1 && - nandc_version.qpic_minor >= 5)) { + nandc_version.qpic_minor >= 5) || + (nandc_version.nand_major >= 2 && + nandc_version.qpic_major >= 2))) { ret = -EPERM; goto out; } -- GitLab From 17db480695c50cae58b099775161b999e13e4da4 Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Thu, 21 May 2020 14:56:46 -0700 Subject: [PATCH 0816/1055] net: stmmac: Fix reading IOMACRO por values Support reading por values for different EMAC versions. Change-Id: I17f8e9c4d461abec29761bc96dfc1e701771de08 Acked-by: Rahul Kawadgave Signed-off-by: Sunil Paidimarri --- .../stmicro/stmmac/dwmac-qcom-ethqos.c | 35 +++++++++++++++++-- .../stmicro/stmmac/dwmac-qcom-ethqos.h | 21 +++-------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index f1626e102e50..25c05007c20a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -33,6 +33,20 @@ static unsigned long tlmm_central_base_addr; bool phy_intr_en; +static struct ethqos_emac_por emac_por[] = { + { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x0 }, + { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x0 }, + { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x0 }, + { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x0 }, + { .offset = SDCC_USR_CTL, .value = 0x0 }, + { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x0}, +}; + +static struct ethqos_emac_driver_data emac_por_data = { + .por = emac_por, + .num_por = ARRAY_SIZE(emac_por), +}; + struct qcom_ethqos *pethqos; struct stmmac_emb_smmu_cb_ctx stmmac_emb_smmu_ctx = {0}; @@ -48,6 +62,21 @@ static struct qmp_pkt pkt; static char qmp_buf[MAX_QMP_MSG_SIZE + 1] = {0}; static struct ip_params pparams = {"", "", "", ""}; +static void qcom_ethqos_read_iomacro_por_values(struct qcom_ethqos *ethqos) +{ + int i; + + ethqos->por = emac_por_data.por; + ethqos->num_por = emac_por_data.num_por; + + /* Read to POR values and enable clk */ + for (i = 0; i < ethqos->num_por; i++) + ethqos->por[i].value = + readl_relaxed( + ethqos->rgmii_base + + ethqos->por[i].offset); +} + static inline unsigned int dwmac_qcom_get_eth_type(unsigned char *buf) { return @@ -1045,7 +1074,7 @@ static void ethqos_pps_irq_config(struct qcom_ethqos *ethqos) } static const struct of_device_id qcom_ethqos_match[] = { - { .compatible = "qcom,sdxprairie-ethqos", .data = &emac_v2_3_2_por}, + { .compatible = "qcom,sdxprairie-ethqos",}, { .compatible = "qcom,emac-smmu-embedded", }, { .compatible = "qcom,stmmac-ethqos", }, {} @@ -1771,8 +1800,6 @@ static int qcom_ethqos_probe(struct platform_device *pdev) goto err_mem; } - ethqos->por = of_device_get_match_data(&pdev->dev); - ethqos->rgmii_clk = devm_clk_get(&pdev->dev, "rgmii"); if (!ethqos->rgmii_clk) { ret = -ENOMEM; @@ -1880,6 +1907,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev) pethqos = ethqos; ethqos_create_debugfs(ethqos); + qcom_ethqos_read_iomacro_por_values(ethqos); + ndev = dev_get_drvdata(ðqos->pdev->dev); priv = netdev_priv(ndev); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h index 73849621f46e..5b06145c6e8e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h @@ -380,22 +380,9 @@ struct ethqos_emac_por { unsigned int value; }; -static const struct ethqos_emac_por emac_v2_3_0_por[] = { - { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x00C01343 }, - { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642C }, - { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x00000000 }, - { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, - { .offset = SDCC_USR_CTL, .value = 0x00010800 }, - { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, -}; - -static const struct ethqos_emac_por emac_v2_3_2_por[] = { - { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x00C01343 }, - { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642C }, - { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x80040800 }, - { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, - { .offset = SDCC_USR_CTL, .value = 0x00010800 }, - { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, +struct ethqos_emac_driver_data { + struct ethqos_emac_por *por; + unsigned int num_por; }; struct qcom_ethqos { @@ -415,7 +402,7 @@ struct qcom_ethqos { /* Work struct for handling phy interrupt */ struct work_struct emac_phy_work; - const struct ethqos_emac_por *por; + struct ethqos_emac_por *por; unsigned int num_por; unsigned int emac_ver; -- GitLab From 7367282db19dd0b8ba15cbedbed4141821d941e8 Mon Sep 17 00:00:00 2001 From: Krishna Manikandan Date: Tue, 27 Aug 2019 14:31:44 +0530 Subject: [PATCH 0817/1055] ARM: dts: msm: remove qdss offset for trinket Remove qdss offset entry for trinket target. Change-Id: I80e7ae4c49a0398e66639a0310805f54a3221d93 Signed-off-by: Krishna Manikandan --- arch/arm64/boot/dts/qcom/trinket-sde.dtsi | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/trinket-sde.dtsi b/arch/arm64/boot/dts/qcom/trinket-sde.dtsi index 880b7857510c..1d06c5eb9ec7 100644 --- a/arch/arm64/boot/dts/qcom/trinket-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket-sde.dtsi @@ -99,9 +99,6 @@ qcom,sde-cdm-off = <0x7a200>; qcom,sde-cdm-size = <0x224>; - - qcom,sde-qdss-off = <0x81a00>; - qcom,sde-dither-off = <0x30e0 0x30e0>; qcom,sde-dither-version = <0x00010000>; qcom,sde-dither-size = <0x20>; -- GitLab From f3f51ded1c4ab6d6171a4b1951dc28e097fd2f50 Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Thu, 19 Mar 2020 19:18:13 +0800 Subject: [PATCH 0818/1055] block, bfq: fix use-after-free in bfq_idle_slice_timer_body In bfq_idle_slice_timer func, bfqq = bfqd->in_service_queue is not in bfqd-lock critical section. The bfqq, which is not equal to NULL in bfq_idle_slice_timer, may be freed after passing to bfq_idle_slice_timer_body. So we will access the freed memory. In addition, considering the bfqq may be in race, we should firstly check whether bfqq is in service before doing something on it in bfq_idle_slice_timer_body func. If the bfqq in race is not in service, it means the bfqq has been expired through __bfq_bfqq_expire func, and wait_request flags has been cleared in __bfq_bfqd_reset_in_service func. So we do not need to re-clear the wait_request of bfqq which is not in service. KASAN log is given as follows: [13058.354613] ============================================================== [13058.354640] BUG: KASAN: use-after-free in bfq_idle_slice_timer+0xac/0x290 [13058.354644] Read of size 8 at addr ffffa02cf3e63f78 by task fork13/19767 [13058.354646] [13058.354655] CPU: 96 PID: 19767 Comm: fork13 [13058.354661] Call trace: [13058.354667] dump_backtrace+0x0/0x310 [13058.354672] show_stack+0x28/0x38 [13058.354681] dump_stack+0xd8/0x108 [13058.354687] print_address_description+0x68/0x2d0 [13058.354690] kasan_report+0x124/0x2e0 [13058.354697] __asan_load8+0x88/0xb0 [13058.354702] bfq_idle_slice_timer+0xac/0x290 [13058.354707] __hrtimer_run_queues+0x298/0x8b8 [13058.354710] hrtimer_interrupt+0x1b8/0x678 [13058.354716] arch_timer_handler_phys+0x4c/0x78 [13058.354722] handle_percpu_devid_irq+0xf0/0x558 [13058.354731] generic_handle_irq+0x50/0x70 [13058.354735] __handle_domain_irq+0x94/0x110 [13058.354739] gic_handle_irq+0x8c/0x1b0 [13058.354742] el1_irq+0xb8/0x140 [13058.354748] do_wp_page+0x260/0xe28 [13058.354752] __handle_mm_fault+0x8ec/0x9b0 [13058.354756] handle_mm_fault+0x280/0x460 [13058.354762] do_page_fault+0x3ec/0x890 [13058.354765] do_mem_abort+0xc0/0x1b0 [13058.354768] el0_da+0x24/0x28 [13058.354770] [13058.354773] Allocated by task 19731: [13058.354780] kasan_kmalloc+0xe0/0x190 [13058.354784] kasan_slab_alloc+0x14/0x20 [13058.354788] kmem_cache_alloc_node+0x130/0x440 [13058.354793] bfq_get_queue+0x138/0x858 [13058.354797] bfq_get_bfqq_handle_split+0xd4/0x328 [13058.354801] bfq_init_rq+0x1f4/0x1180 [13058.354806] bfq_insert_requests+0x264/0x1c98 [13058.354811] blk_mq_sched_insert_requests+0x1c4/0x488 [13058.354818] blk_mq_flush_plug_list+0x2d4/0x6e0 [13058.354826] blk_flush_plug_list+0x230/0x548 [13058.354830] blk_finish_plug+0x60/0x80 [13058.354838] read_pages+0xec/0x2c0 [13058.354842] __do_page_cache_readahead+0x374/0x438 [13058.354846] ondemand_readahead+0x24c/0x6b0 [13058.354851] page_cache_sync_readahead+0x17c/0x2f8 [13058.354858] generic_file_buffered_read+0x588/0xc58 [13058.354862] generic_file_read_iter+0x1b4/0x278 [13058.354965] ext4_file_read_iter+0xa8/0x1d8 [ext4] [13058.354972] __vfs_read+0x238/0x320 [13058.354976] vfs_read+0xbc/0x1c0 [13058.354980] ksys_read+0xdc/0x1b8 [13058.354984] __arm64_sys_read+0x50/0x60 [13058.354990] el0_svc_common+0xb4/0x1d8 [13058.354994] el0_svc_handler+0x50/0xa8 [13058.354998] el0_svc+0x8/0xc [13058.354999] [13058.355001] Freed by task 19731: [13058.355007] __kasan_slab_free+0x120/0x228 [13058.355010] kasan_slab_free+0x10/0x18 [13058.355014] kmem_cache_free+0x288/0x3f0 [13058.355018] bfq_put_queue+0x134/0x208 [13058.355022] bfq_exit_icq_bfqq+0x164/0x348 [13058.355026] bfq_exit_icq+0x28/0x40 [13058.355030] ioc_exit_icq+0xa0/0x150 [13058.355035] put_io_context_active+0x250/0x438 [13058.355038] exit_io_context+0xd0/0x138 [13058.355045] do_exit+0x734/0xc58 [13058.355050] do_group_exit+0x78/0x220 [13058.355054] __wake_up_parent+0x0/0x50 [13058.355058] el0_svc_common+0xb4/0x1d8 [13058.355062] el0_svc_handler+0x50/0xa8 [13058.355066] el0_svc+0x8/0xc. Change-Id: I510c704a6f2324741d70db33f0350e14642fe92f Acked-by: Paolo Valente Reported-by: Wang Wang Signed-off-by: Zhiqiang Liu Signed-off-by: Feilong Lin Signed-off-by: Jens Axboe Git-commit: 2f95fa5c955d0a9987ffdc3a095e2f4e62c5f2a9 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block Signed-off-by: Pradeep P V K --- block/bfq-iosched.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 93863c6173e6..959bee9fa911 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -4541,20 +4541,28 @@ static void bfq_prepare_request(struct request *rq, struct bio *bio) spin_unlock_irq(&bfqd->lock); } -static void bfq_idle_slice_timer_body(struct bfq_queue *bfqq) +static void +bfq_idle_slice_timer_body(struct bfq_data *bfqd, struct bfq_queue *bfqq) { - struct bfq_data *bfqd = bfqq->bfqd; enum bfqq_expiration reason; unsigned long flags; spin_lock_irqsave(&bfqd->lock, flags); - bfq_clear_bfqq_wait_request(bfqq); + /* + * Considering that bfqq may be in race, we should firstly check + * whether bfqq is in service before doing something on it. If + * the bfqq in race is not in service, it has already been expired + * through __bfq_bfqq_expire func and its wait_request flags has + * been cleared in __bfq_bfqd_reset_in_service func. + */ if (bfqq != bfqd->in_service_queue) { spin_unlock_irqrestore(&bfqd->lock, flags); return; } + bfq_clear_bfqq_wait_request(bfqq); + if (bfq_bfqq_budget_timeout(bfqq)) /* * Also here the queue can be safely expired @@ -4599,7 +4607,7 @@ static enum hrtimer_restart bfq_idle_slice_timer(struct hrtimer *timer) * early. */ if (bfqq) - bfq_idle_slice_timer_body(bfqq); + bfq_idle_slice_timer_body(bfqd, bfqq); return HRTIMER_NORESTART; } -- GitLab From 7ae7d0f464bf9efbd485955972f450782365be8d Mon Sep 17 00:00:00 2001 From: Jhansi Konathala Date: Thu, 2 Jan 2020 17:55:12 +0530 Subject: [PATCH 0819/1055] ARM: dts: msm: Add pseudo port entries Add pseudo port entries to enable Incall music downlink. Change-Id: Id26acf12767dd7f73497185c4035ab2b98a6c10e Signed-off-by: Anurag Chouhan Signed-off-by: Jhansi Konathala Signed-off-by: Meghana Reddy Mula --- .../devicetree/bindings/sound/qcom-audio-dev.txt | 13 +++++++++---- arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi | 4 ++-- arch/arm64/boot/dts/qcom/sdx-audio-lpass.dtsi | 4 ++++ arch/arm64/boot/dts/qcom/sdxprairie-audio.dtsi | 4 ++-- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 715855b3fa5a..437c33d3d149 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -700,6 +700,11 @@ Example: compatible = "qcom,msm-dai-q6-dev"; qcom,msm-dai-q6-dev-id = <32770>; }; + + qcom,msm-dai-q6-incall-music-dl-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32774>; + }; }; qcom,msm-pri-auxpcm { @@ -1929,7 +1934,7 @@ Example: <&afe_proxy_tx>, <&incall_record_rx>, <&incall_record_tx>, <&incall_music_rx>, <&dai_sec_auxpcm>, <&incall2_record_rx>, - <&incall_music_2_rx>; + <&incall_music_2_rx>, <&incall_music_dl_rx>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", @@ -1939,7 +1944,7 @@ Example: "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-auxpcm.2", "msm-dai-q6-dev.32769", - "msm-dai-q6-dev.32770"; + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.32774"; }; * SDX ASoC Auto Machine driver @@ -1998,7 +2003,7 @@ Example: <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, <&dai_sec_auxpcm>, <&incall2_record_rx>, - <&incall_music_2_rx>; + <&incall_music_2_rx>, <&incall_music_dl_rx>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", @@ -2010,7 +2015,7 @@ Example: "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", "msm-dai-q6-auxpcm.2", "msm-dai-q6-dev.32769", - "msm-dai-q6-dev.32770"; + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.32774"; asoc-codec = <&tlv320aic3x_codec>, <&stub_codec>; asoc-codec-names = "tlv320aic3x-codec", "msm-stub-codec.1"; }; diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi b/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi index f7a7966cd9d2..225a936cd07d 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi @@ -53,7 +53,7 @@ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, <&dai_sec_auxpcm>, <&incall2_record_rx>, - <&incall_music_2_rx>; + <&incall_music_2_rx>, <&incall_music_dl_rx>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", @@ -65,7 +65,7 @@ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", "msm-dai-q6-auxpcm.2", "msm-dai-q6-dev.32769", - "msm-dai-q6-dev.32770"; + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.32774"; asoc-codec = <&tlv320aic3x_codec>, <&stub_codec>; asoc-codec-names = "tlv320aic3x-codec", "msm-stub-codec.1"; }; diff --git a/arch/arm64/boot/dts/qcom/sdx-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/sdx-audio-lpass.dtsi index ad75e4a25663..ac9e214cce1c 100644 --- a/arch/arm64/boot/dts/qcom/sdx-audio-lpass.dtsi +++ b/arch/arm64/boot/dts/qcom/sdx-audio-lpass.dtsi @@ -162,6 +162,10 @@ qcom,msm-dai-q6-dev-id = <32770>; }; + incall_music_dl_rx: qcom,msm-dai-q6-incall-music-dl-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32774>; + }; }; pcm_dtmf: qcom,msm-pcm-dtmf { diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-audio.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-audio.dtsi index 1501f2ee2226..26204b4f6814 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-audio.dtsi @@ -40,7 +40,7 @@ <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, <&dai_sec_auxpcm>, <&incall2_record_rx>, - <&incall_music_2_rx>; + <&incall_music_2_rx>, <&incall_music_dl_rx>; asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-stub-dev.4", "msm-dai-stub-dev.5", @@ -52,6 +52,6 @@ "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", "msm-dai-q6-auxpcm.2", "msm-dai-q6-dev.32769", - "msm-dai-q6-dev.32770"; + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.32774"; }; }; -- GitLab From a9b3166b51f83e97c48f8c3db841c6278ec91be6 Mon Sep 17 00:00:00 2001 From: Rahul Shahare Date: Wed, 10 Jun 2020 15:35:30 +0530 Subject: [PATCH 0820/1055] defconfig: msm: Disable CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE flag To support Boot image with header version v2, disable CONFIG_BUILD_ARM64_APPENDED_DTB flag in defconfig and perf_defconfig for SM6150. Change-Id: If1c3886b0c97b8be1ce5b4578f63c53d50858911 Signed-off-by: Rahul Shahare --- arch/arm64/configs/vendor/sdmsteppe-perf_defconfig | 1 - arch/arm64/configs/vendor/sdmsteppe_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index ace282a41b0b..c3cc5faa32d6 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -76,7 +76,6 @@ CONFIG_SETEND_EMULATION=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y # CONFIG_EFI is not set -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y CONFIG_KRYO_PMU_WORKAROUND=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index d796e2fe093e..12aec7f1b0da 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -81,7 +81,6 @@ CONFIG_CP15_BARRIER_EMULATION=y CONFIG_SETEND_EMULATION=y # CONFIG_ARM64_VHE is not set CONFIG_RANDOMIZE_BASE=y -CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y CONFIG_KRYO_PMU_WORKAROUND=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_COMPAT=y -- GitLab From b1535c878f4e130b131cb926c7b3c1237d8f542f Mon Sep 17 00:00:00 2001 From: Venkata Rao Kakani Date: Fri, 29 May 2020 18:41:59 +0530 Subject: [PATCH 0821/1055] ARM: dts: msm: update board-id for different linux variants Add board-id for different linux guest variants to recognize and load from host. Change-Id: I34607b7c76a295d81a38368a9bfa55c2e5b27e82 Signed-off-by: Venkata Rao Kakani --- arch/arm64/boot/dts/qcom/sa6155p-vm-la.dts | 2 +- arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dts | 2 +- arch/arm64/boot/dts/qcom/sa8155-vm-la.dts | 2 +- arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dts | 2 +- arch/arm64/boot/dts/qcom/sa8155-vm-lv.dts | 2 +- arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dts | 2 +- arch/arm64/boot/dts/qcom/sa8195-vm-la.dts | 2 +- arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dts | 2 +- arch/arm64/boot/dts/qcom/sa8195-vm-lv.dts | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa6155p-vm-la.dts b/arch/arm64/boot/dts/qcom/sa6155p-vm-la.dts index 8a2835a735dc..ba1dc8d7dc83 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-vm-la.dts +++ b/arch/arm64/boot/dts/qcom/sa6155p-vm-la.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA6155P Virtual Machine"; compatible = "qcom,sa6155p"; qcom,pmic-name = "PM6150"; - qcom,board-id = <0 0>; + qcom,board-id = <0x1000001 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dts b/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dts index d544cb066f2f..0e2e5d138d32 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dts +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA8155 Multi LA Virtual Machine"; compatible = "qcom,sa8155"; qcom,pmic-name = "PM8150"; - qcom,board-id = <0 0>; + qcom,board-id = <0x2000001 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-la.dts b/arch/arm64/boot/dts/qcom/sa8155-vm-la.dts index ae614ef9b5f7..30cffa4f8ea3 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-la.dts +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-la.dts @@ -20,5 +20,5 @@ model = "Qualcomm Technologies, Inc. SA8155 Single LA Virtual Machine"; compatible = "qcom,sa8155"; qcom,pmic-name = "PM8150"; - qcom,board-id = <0 0>; + qcom,board-id = <0x1000001 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dts b/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dts index aefc080f6b71..7c5562bf00f4 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dts +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA8155 Multi LV Virtual Machine"; compatible = "qcom,sa8155"; qcom,pmic-name = "PM8150"; - qcom,board-id = <0 0>; + qcom,board-id = <0x2000002 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dts b/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dts index 7eec6fa776fd..46b3281f8716 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dts +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dts @@ -19,6 +19,6 @@ model = "Qualcomm Technologies, Inc. SA8155 Single LV Virtual Machine"; compatible = "qcom,sa8155"; qcom,pmic-name = "PM8150"; - qcom,board-id = <0 0>; + qcom,board-id = <0x1000002 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dts b/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dts index 69fc9ed11e9b..c59921d1b4c5 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dts +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA8195 Multi LA Virtual Machine"; compatible = "qcom,sa8195p"; qcom,pmic-name = "PM8195"; - qcom,board-id = <0 0>; + qcom,board-id = <0x2000001 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-la.dts b/arch/arm64/boot/dts/qcom/sa8195-vm-la.dts index 1d54538f77f9..bb721e12b648 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-la.dts +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-la.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA8195 Single LA Virtual Machine"; compatible = "qcom,sa8195p"; qcom,pmic-name = "PM8195"; - qcom,board-id = <0 0>; + qcom,board-id = <0x1000001 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dts b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dts index 4a570f9897d9..76a24b42f78e 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dts +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA8195 Multi LV Virtual Machine"; compatible = "qcom,sa8195p"; qcom,pmic-name = "PM8195"; - qcom,board-id = <0 0>; + qcom,board-id = <0x2000002 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-lv.dts b/arch/arm64/boot/dts/qcom/sa8195-vm-lv.dts index 10b40d2c3e50..107d2016c9c9 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-lv.dts +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-lv.dts @@ -19,5 +19,5 @@ model = "Qualcomm Technologies, Inc. SA8195 Single LV Virtual Machine"; compatible = "qcom,sa8195p"; qcom,pmic-name = "PM8195"; - qcom,board-id = <0 0>; + qcom,board-id = <0x1000002 0>; }; -- GitLab From ae1039250482b4bcb9e04ef2906b024d2a2b4572 Mon Sep 17 00:00:00 2001 From: Arun Prakash Date: Tue, 9 Jun 2020 13:38:42 +0530 Subject: [PATCH 0822/1055] ARM: dts: msm: Add smp2p based shutdown-ack Add smp2p based shutdown-ack support for both cdsp and adsp sub system as qmi based indication failing in graceful shutdown case. Change-Id: I01f0be88999a1219df61fc2178b795fe94d07e1b Signed-off-by: Arun Prakash --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 12 ++++++++---- arch/arm64/boot/dts/qcom/sm8150.dtsi | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 4eed5815d029..4cac5c0ccb46 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -2387,13 +2387,15 @@ <&adsp_smp2p_in 0 0>, <&adsp_smp2p_in 2 0>, <&adsp_smp2p_in 1 0>, - <&adsp_smp2p_in 3 0>; + <&adsp_smp2p_in 3 0>, + <&adsp_smp2p_in 7 0>; interrupt-names = "qcom,wdog", "qcom,err-fatal", "qcom,proxy-unvote", "qcom,err-ready", - "qcom,stop-ack"; + "qcom,stop-ack", + "qcom,shutdown-ack"; /* Outputs to lpass */ qcom,smem-states = <&adsp_smp2p_out 0>; @@ -2478,13 +2480,15 @@ <&cdsp_smp2p_in 0 0>, <&cdsp_smp2p_in 2 0>, <&cdsp_smp2p_in 1 0>, - <&cdsp_smp2p_in 3 0>; + <&cdsp_smp2p_in 3 0>, + <&cdsp_smp2p_in 7 0>; interrupt-names = "qcom,wdog", "qcom,err-fatal", "qcom,proxy-unvote", "qcom,err-ready", - "qcom,stop-ack"; + "qcom,stop-ack", + "qcom,shutdown-ack"; /* Outputs to turing */ qcom,smem-states = <&cdsp_smp2p_out 0>; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index f4db2d9f7441..aa0d882dad60 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -1736,13 +1736,15 @@ <&adsp_smp2p_in 0 0>, <&adsp_smp2p_in 2 0>, <&adsp_smp2p_in 1 0>, - <&adsp_smp2p_in 3 0>; + <&adsp_smp2p_in 3 0>, + <&adsp_smp2p_in 7 0>; interrupt-names = "qcom,wdog", "qcom,err-fatal", "qcom,proxy-unvote", "qcom,err-ready", - "qcom,stop-ack"; + "qcom,stop-ack", + "qcom,shutdown-ack"; /* Outputs to lpass */ qcom,smem-states = <&adsp_smp2p_out 0>; @@ -1893,13 +1895,15 @@ <&cdsp_smp2p_in 0 0>, <&cdsp_smp2p_in 2 0>, <&cdsp_smp2p_in 1 0>, - <&cdsp_smp2p_in 3 0>; + <&cdsp_smp2p_in 3 0>, + <&cdsp_smp2p_in 7 0>; interrupt-names = "qcom,wdog", "qcom,err-fatal", "qcom,proxy-unvote", "qcom,err-ready", - "qcom,stop-ack"; + "qcom,stop-ack", + "qcom,shutdown-ack"; /* Outputs to turing */ qcom,smem-states = <&cdsp_smp2p_out 0>; -- GitLab From 8dba8a95d5e7b9db86b5f5dda8503521d98214fd Mon Sep 17 00:00:00 2001 From: Yuanfang Zhang Date: Thu, 11 Jun 2020 11:12:30 +0800 Subject: [PATCH 0823/1055] coresight: etx4x: sysfs: fix spinlock unlock issue If an error is detected in addr_range_show() or addr_range_store(), need to unlock spinlock and then return. Change-Id: I84be54a1906fd3a9d5f24946a7941e87595e95c1 Signed-off-by: Yuanfang Zhang --- drivers/hwtracing/coresight/coresight-etm4x-sysfs.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index 19d33fbdb6f6..7d79f0dfd01d 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c @@ -964,8 +964,11 @@ static ssize_t addr_range_show(struct device *dev, spin_lock(&drvdata->spinlock); idx = config->addr_idx; - if (idx >= ETM_MAX_SINGLE_ADDR_CMP) + if (idx >= ETM_MAX_SINGLE_ADDR_CMP) { + spin_unlock(&drvdata->spinlock); return -EINVAL; + } + if (idx % 2 != 0) { spin_unlock(&drvdata->spinlock); return -EPERM; @@ -1002,8 +1005,11 @@ static ssize_t addr_range_store(struct device *dev, spin_lock(&drvdata->spinlock); idx = config->addr_idx; - if (idx >= ETM_MAX_SINGLE_ADDR_CMP) + if (idx >= ETM_MAX_SINGLE_ADDR_CMP) { + spin_unlock(&drvdata->spinlock); return -EINVAL; + } + if (idx % 2 != 0) { spin_unlock(&drvdata->spinlock); return -EPERM; -- GitLab From 969e89825fb0637c1e4a8bceaf7eaddc1b5a8a79 Mon Sep 17 00:00:00 2001 From: Suraj Jaiswal Date: Thu, 11 Jun 2020 11:52:21 +0530 Subject: [PATCH 0824/1055] net: stmmac: copyright year fix Add proper copyright year. Change-Id: I34fc3d1a93481bb8b97d15d9219e938186996f2f Signed-off-by: Suraj Jaiswal --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c index adfe4b81525b..76aafe700851 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, 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 -- GitLab From 5c7f3c52b7d750d6f19fc0df158cd62f2227b336 Mon Sep 17 00:00:00 2001 From: Yadu MG Date: Sat, 30 May 2020 01:39:28 +0530 Subject: [PATCH 0825/1055] ARM: dts: msm: Add coresight nodes for sdmshrike Enable coresight components for tracing APPS ATB source. Change-Id: Iaf0107e0773c6b51073837a92f285c9264ec1afc Signed-off-by: Yadu MG --- .../boot/dts/qcom/sdmshrike-coresight.dtsi | 1088 +++++++++++++++++ arch/arm64/boot/dts/qcom/sdmshrike.dtsi | 1 + 2 files changed, 1089 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi new file mode 100644 index 000000000000..8f4e7a9c8d4a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi @@ -0,0 +1,1088 @@ +/* Copyright (c) 2020, 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. + */ + +&soc { + csr: csr@0x6001000 { + compatible = "qcom,coresight-csr"; + reg = <0x6001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + + qcom,blk-size = <1>; + }; + + replicator_qdss: replicator@6046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator0_out_tmc_etr: endpoint { + remote-endpoint= + <&tmc_etr_in_replicator0>; + }; + }; + + port@2 { + reg = <0>; + replicator0_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint= + <&tmc_etf_out_replicator0>; + }; + }; + }; + }; + + tmc_etr: tmc@6048000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6048000 0x1000>, + <0x6064000 0x15000>; + reg-names = "tmc-base", "bam-base"; + + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x05e0 0>, + <&apps_smmu 0x04a0 0>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + arm,buffer-size = <0x400000>; + + coresight-name = "coresight-tmc-etr"; + coresight-ctis = <&cti0>; + coresight-csr = <&csr>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + interrupts = ; + interrupt-names = "byte-cntr-irq"; + + port { + tmc_etr_in_replicator0: endpoint { + slave-mode; + remote-endpoint = <&replicator0_out_tmc_etr>; + }; + }; + }; + + tmc_etf: tmc@6047000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6047000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + coresight-ctis = <&cti0>; + coresight-csr = <&csr>; + arm,default-sink; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_out_replicator0: endpoint { + remote-endpoint = + <&replicator0_in_tmc_etf>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_in_funnel_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_merg_out_tmc_etf>; + }; + }; + }; + + }; + + funnel_merg: funnel@6045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merg"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_merg_out_tmc_etf: endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_merg>; + }; + }; + + port@2 { + reg = <1>; + funnel_merg_in_funnel_in1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in1_out_funnel_merg>; + }; + }; + }; + }; + + funnel_in1: funnel@0x6042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + + port@3 { + reg = <4>; + funnel_in1_in_funnel_apss_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merg_out_funnel_in1>; + }; + }; + }; + }; + + funnel_apss_merg: funnel@7810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7810000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss-merg"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_merg_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_funnel_apss_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_merg_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_apss_merg>; + }; + }; + + port@2 { + reg = <2>; + funnel_apss_merg_in_tpda_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpda_olc_out_funnel_apss_merg>; + }; + }; + + port@3 { + reg = <3>; + funnel_apss_merg_in_tpda_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_silver_out_funnel_apss_merg>; + }; + }; + + port@4 { + reg = <4>; + funnel_apss_merg_in_tpda_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_gold_out_funnel_apss_merg>; + }; + }; + + port@5 { + reg = <5>; + funnel_apss_merg_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss_merg>; + }; + }; + }; + }; + + tpda_olc: tpda@7832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7832000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-olc"; + + qcom,tpda-atid = <69>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_olc_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_olc>; + }; + }; + + port@1 { + reg = <0>; + tpda_olc_in_tpdm_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_olc_out_tpda_olc>; + }; + }; + }; + }; + + tpdm_olc: tpdm@7830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-olc"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port{ + tpdm_olc_out_tpda_olc: endpoint { + remote-endpoint = <&tpda_olc_in_tpdm_olc>; + }; + }; + }; + + tpda_apss: tpda@7862000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7862000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-apss"; + + qcom,tpda-atid = <66>; + qcom,dsb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_apss>; + }; + }; + + port@1 { + reg = <0>; + tpda_apss_in_tpdm_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_apss_out_tpda_apss>; + }; + }; + }; + }; + + tpdm_apss: tpdm@7860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-apss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_apss_out_tpda_apss: endpoint { + remote-endpoint = <&tpda_apss_in_tpdm_apss>; + }; + }; + }; + + tpda_llm_silver: tpda@78c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78c0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-silver"; + + qcom,tpda-atid = <72>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_llm_silver_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_silver>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_silver_in_tpdm_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_silver_out_tpda_llm_silver>; + }; + }; + }; + }; + + tpdm_llm_silver: tpdm@78a0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x78a0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-silver"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_silver_out_tpda_llm_silver: endpoint { + remote-endpoint = + <&tpda_llm_silver_in_tpdm_llm_silver>; + }; + }; + }; + + tpda_llm_gold: tpda@78d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78d0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-gold"; + + qcom,tpda-atid = <73>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_llm_gold_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_gold>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_gold_in_tpdm_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_gold_out_tpda_llm_gold>; + }; + }; + }; + }; + + tpdm_llm_gold: tpdm@78b0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x78b0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-llm-gold"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_llm_gold_out_tpda_llm_gold: endpoint { + remote-endpoint = + <&tpda_llm_gold_in_tpdm_llm_gold>; + }; + }; + }; + + funnel_apss: funnel@7800000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x7800000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_apss_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_funnel_apss>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss>; + }; + }; + + port@2 { + reg = <1>; + funnel_apss_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss>; + }; + }; + + port@3 { + reg = <2>; + funnel_apss_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss>; + }; + }; + + port@4 { + reg = <3>; + funnel_apss_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss>; + }; + }; + + port@5 { + reg = <4>; + funnel_apss_in_etm4: endpoint { + slave-mode; + remote-endpoint = + <&etm4_out_funnel_apss>; + }; + }; + + port@6 { + reg = <5>; + funnel_apss_in_etm5: endpoint { + slave-mode; + remote-endpoint = + <&etm5_out_funnel_apss>; + }; + }; + + port@7 { + reg = <6>; + funnel_apss_in_etm6: endpoint { + slave-mode; + remote-endpoint = + <&etm6_out_funnel_apss>; + }; + }; + + port@8 { + reg = <7>; + funnel_apss_in_etm7: endpoint { + slave-mode; + remote-endpoint = + <&etm7_out_funnel_apss>; + }; + }; + }; + }; + + etm0: etm@7040000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7040000 0x1000>; + cpu = <&CPU0>; + + coresight-name = "coresight-etm0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + arm,coresight-loses-context-with-cpu; + + port { + etm0_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm0>; + }; + }; + }; + + etm1: etm@7140000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7140000 0x1000>; + cpu = <&CPU1>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm1_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm1>; + }; + }; + }; + + etm2: etm@7240000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7240000 0x1000>; + cpu = <&CPU2>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm2_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm2>; + }; + }; + }; + + etm3: etm@7340000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7340000 0x1000>; + cpu = <&CPU3>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm3_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm3>; + }; + }; + }; + + etm4: etm@7440000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7440000 0x1000>; + cpu = <&CPU4>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm4"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm4_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm4>; + }; + }; + }; + + etm5: etm@7540000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7540000 0x1000>; + cpu = <&CPU5>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm5"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm5_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm5>; + }; + }; + }; + + etm6: etm@7640000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7640000 0x1000>; + cpu = <&CPU6>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm6_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm6>; + }; + }; + }; + + etm7: etm@7740000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7740000 0x1000>; + cpu = <&CPU7>; + + qcom,tupwr-disable; + coresight-name = "coresight-etm7"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + etm7_out_funnel_apss: endpoint { + remote-endpoint = <&funnel_apss_in_etm7>; + }; + }; + }; + + cti0_apss: cti@78e0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x78e0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_apss: cti@78f0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x78f0000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_apss: cti@7900000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7900000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0: cti@6010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6010000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1: cti@6011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6011000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2: cti@6012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6012000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti3: cti@6013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6013000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti4: cti@6014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6014000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti4"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti5: cti@6015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6015000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti5"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti6: cti@6016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6016000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti7: cti@6017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6017000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti7"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti8: cti@6018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6018000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti8"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti9: cti@6019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6019000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti9"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti10: cti@601a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti10"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti11: cti@601b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti11"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti12: cti@601c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti12"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti13: cti@601d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti13"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti14: cti@601e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti14"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti15: cti@601f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x601f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti15"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu0: cti@7020000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7020000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu0"; + cpu = <&CPU0>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu1: cti@7120000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7120000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu1"; + cpu = <&CPU1>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu2: cti@7220000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7220000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu2"; + cpu = <&CPU2>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu3: cti@7320000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7320000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu3"; + cpu = <&CPU3>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu4: cti@7420000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7420000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu4"; + cpu = <&CPU4>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu5: cti@7520000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7520000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu5"; + cpu = <&CPU5>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu6: cti@7620000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7620000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu6"; + cpu = <&CPU6>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_cpu7: cti@7720000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x7720000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu7"; + cpu = <&CPU7>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi index d967177aec66..d417ff891224 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike.dtsi @@ -2841,6 +2841,7 @@ #include "sdmshrike-regulators.dtsi" #include "sdmshrike-ion.dtsi" #include "sdmshrike-bus.dtsi" +#include "sdmshrike-coresight.dtsi" #include "msm-arm-smmu-sdmshrike.dtsi" #include "sdmshrike-usb.dtsi" #include "sdmshrike-qupv3.dtsi" -- GitLab From daf77adb47a32b24631caa37248d7b003cc418ed Mon Sep 17 00:00:00 2001 From: Yadu MG Date: Thu, 4 Jun 2020 18:26:34 +0530 Subject: [PATCH 0826/1055] ARM: dts: msm: Enable hwevents coresight nodes for sdmshrike Add coresight hwevent node to enable tracing of hardware events Change-Id: I65a2ac9ac583e31807cc31fc04918255897aea22 Signed-off-by: Yadu MG --- .../boot/dts/qcom/sdmshrike-coresight.dtsi | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi index 8f4e7a9c8d4a..ef5a2ca7ff51 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi @@ -1085,4 +1085,26 @@ clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; }; + + hwevent: hwevent@91866f0 { + compatible = "qcom,coresight-hwevent"; + reg = <0x091866f0 0x4>, + <0x91966f0 0x4>, + <0x9186038 0x4>, + <0x9196038 0x4>, + <0x17e00034 0x4>, + <0x18200050 0x80>, + <0x02c8d050 0x80>, + <0x0af20050 0x80>; + reg-names = "ddr-ch0-cfg", "ddr-ch23-cfg", "ddr-ch0-ctrl", + "ddr-ch23-ctrl", "apss-testbus-mux-cfg", + "apss-rsc-hwevent-mux0-select", + "gpu-rsc-hwevent-mux0-select", + "sde-rsc-hwevent-mux0-select"; + + coresight-name = "coresight-hwevent"; + coresight-csr = <&csr>; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; }; -- GitLab From 2333e49532ee65c62b5ac8a6b4fd7df2fed7d071 Mon Sep 17 00:00:00 2001 From: Yadu MG Date: Thu, 4 Jun 2020 18:47:59 +0530 Subject: [PATCH 0827/1055] ARM: dts: msm: Enable ddr coresight nodes for sdmshrike Enable coresight components for tracing DDR ATB source Change-Id: Ia4c9c4241ed1d9da8e8dca63191bf6a0a63da2e9 Signed-off-by: Yadu MG --- .../boot/dts/qcom/sdmshrike-coresight.dtsi | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi index ef5a2ca7ff51..e5404fa19d8b 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi @@ -157,6 +157,15 @@ }; }; + port@1 { + reg = <0>; + funnel_merg_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_funnel_merg>; + }; + }; + port@2 { reg = <1>; funnel_merg_in_funnel_in1: endpoint { @@ -168,6 +177,41 @@ }; }; + funnel_in0: funnel@6041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6041000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in0_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in0>; + }; + }; + + port@1 { + reg = <6>; + funnel_in0_in_funnel_qatb: endpoint { + slave-mode; + remote-endpoint = + <&funnel_qatb_out_funnel_in0>; + }; + }; + }; + }; + funnel_in1: funnel@0x6042000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b908>; @@ -1107,4 +1151,145 @@ clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; }; + + funnel_qatb: funnel@6005000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6005000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-qatb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_qatb_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_qatb>; + }; + }; + + port@1 { + reg = <0>; + funnel_qatb_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_qatb>; + }; + }; + }; + }; + + tpda: tpda@6004000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6004000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <65>; + qcom,bc-elem-size = <10 32>, + <13 32>; + qcom,tc-elem-size = <13 32>; + qcom,dsb-elem-size = <0 32>, + <2 32>, + <3 32>, + <5 32>, + <6 32>, + <10 32>, + <11 32>, + <13 32>; + qcom,cmb-elem-size = <3 64>, + <7 64>, + <13 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_tpda>; + }; + + }; + + port@1 { + reg = <5>; + tpda_in_funnel_ddr_0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_ddr_0_out_tpda>; + }; + }; + }; + }; + + funnel_ddr_0: funnel@6a05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6a05000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-ddr-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_ddr_0_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_ddr_0>; + }; + }; + + port@1 { + reg = <0>; + funnel_ddr_0_in_tpdm_ddr: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_out_funnel_ddr_0>; + }; + }; + }; + }; + + tpdm_ddr: tpdm@6a00000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6a00000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ddr"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_ddr_out_funnel_ddr_0: endpoint { + remote-endpoint = <&funnel_ddr_0_in_tpdm_ddr>; + }; + }; + }; }; -- GitLab From 10406d23889ef337a8366ac67137d1e7b2d7f8c7 Mon Sep 17 00:00:00 2001 From: Yadu MG Date: Thu, 4 Jun 2020 20:54:50 +0530 Subject: [PATCH 0828/1055] ARM: dts: msm: Enable STM coresight node for sdmshrike Enable system trace macrocell coresight component for software instrumented trace. Change-Id: I00e4b88f3d92c1be0ecaf29635eaa10731e90c17 Signed-off-by: Yadu MG --- .../boot/dts/qcom/sdmshrike-coresight.dtsi | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi index e5404fa19d8b..9305469824e9 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi @@ -209,6 +209,14 @@ <&funnel_qatb_out_funnel_in0>; }; }; + + port@2 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = <&stm_out_funnel_in0>; + }; + }; }; }; @@ -1292,4 +1300,25 @@ }; }; }; + + stm: stm@6002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b962>; + + reg = <0x6002000 0x1000>, + <0x16280000 0x180000>, + <0x7820f0 0x4>; + reg-names = "stm-base", "stm-stimulus-base", "stm-debug-status"; + + coresight-name = "coresight-stm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + }; }; -- GitLab From 98acb1b5c983a3d6a7c201b911db45be9cf95662 Mon Sep 17 00:00:00 2001 From: Ritesh Kumar Date: Sun, 25 Aug 2019 00:02:38 +0530 Subject: [PATCH 0829/1055] clk: qcom: mdss: Improve logging for 10nm dsi pll Avoid warning of slave pll unavailable for chipsets not having slave pll. Change-Id: Id32af235f2fbefa4869b5c8236436e8e6ed84d60 Signed-off-by: Ritesh Kumar --- drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c index ab44b3964f71..e549ef13f578 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c @@ -470,7 +470,7 @@ static void dsi_pll_config_slave(struct mdss_pll_resources *rsc) rsc->slave = NULL; if (!orsc) { - pr_warn("slave PLL unavilable, assuming standalone config\n"); + pr_debug("slave PLL unavilable, assuming standalone config\n"); return; } -- GitLab From 0639025a7cb1fa9c2747c0321efd55e72d84011b Mon Sep 17 00:00:00 2001 From: Sundara Vinayagam Date: Tue, 27 Mar 2018 16:48:53 +0530 Subject: [PATCH 0830/1055] input: qpnp-power-on: Add a property to force hard-reset offset Some (PON gen2) platforms still use legacy hard-reset offset [7:2] of the PON_RB_SPARE register. Add a DT property to support it. Change-Id: I8fd3434bcc064965b11aaf3e9c7fcbf694145d21 Signed-off-by: Sundara Vinayagam --- Documentation/devicetree/bindings/input/qpnp-power-on.txt | 3 +++ drivers/input/misc/qpnp-power-on.c | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/input/qpnp-power-on.txt b/Documentation/devicetree/bindings/input/qpnp-power-on.txt index a78f088b7e0e..e13669a6acbd 100644 --- a/Documentation/devicetree/bindings/input/qpnp-power-on.txt +++ b/Documentation/devicetree/bindings/input/qpnp-power-on.txt @@ -116,6 +116,9 @@ Optional properties: configured to support TWM modes. - qcom,pbs-client: Phandle of the PBS client node. Should be defined if 'qcom,support-twm-config' is present. +- qcom,use-legacy-hard-reset-offset Boolean property to support legacy + hard-reset offset of the PON_RB_SPARE register for + some (PON gen2) platforms. Optional Sub-nodes: - qcom,pon_1 ... qcom,pon_n: These PON child nodes correspond to features diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c index df9fa421072f..d930b6b451b9 100644 --- a/drivers/input/misc/qpnp-power-on.c +++ b/drivers/input/misc/qpnp-power-on.c @@ -242,6 +242,7 @@ struct qpnp_pon { bool resin_pon_reset; ktime_t kpdpwr_last_release_time; struct notifier_block pon_nb; + bool legacy_hard_reset_offset; }; static int pon_ship_mode_en; @@ -423,7 +424,7 @@ int qpnp_pon_set_restart_reason(enum pon_restart_reason reason) if (!pon->store_hard_reset_reason) return 0; - if (is_pon_gen2(pon)) + if (is_pon_gen2(pon) && !pon->legacy_hard_reset_offset) rc = qpnp_pon_masked_write(pon, QPNP_PON_SOFT_RB_SPARE(pon), GENMASK(7, 1), (reason << 1)); else @@ -2416,6 +2417,9 @@ static int qpnp_pon_probe(struct platform_device *pdev) pon->store_hard_reset_reason = of_property_read_bool(dev->of_node, "qcom,store-hard-reset-reason"); + pon->legacy_hard_reset_offset = of_property_read_bool(pdev->dev.of_node, + "qcom,use-legacy-hard-reset-offset"); + if (of_property_read_bool(dev->of_node, "qcom,secondary-pon-reset")) { if (sys_reset) { dev_err(dev, "qcom,system-reset property shouldn't be used along with qcom,secondary-pon-reset property\n"); -- GitLab From c07dc62f3a98e7ddd8855ec093fd01f6b5ae2757 Mon Sep 17 00:00:00 2001 From: Akshay Pandit Date: Thu, 11 Jun 2020 08:21:56 -0700 Subject: [PATCH 0831/1055] Revert "ARM: dts: msm: Move pil region of ipa fws for SA8155 VM " This reverts commit 731bbd35dd811950d513da70e2002f47895f2023. Change-Id: Id0cc5f69f0f02cfd5af67063d49db22f08060df2 Signed-off-by: Akshay Pandit --- arch/arm64/boot/dts/qcom/sa8155-vm-la.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-la.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-la.dtsi index f15391179db0..edf3146af5e8 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-la.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-la.dtsi @@ -30,7 +30,7 @@ pil_ipa_fw_mem: pil_ipa_fw_region { compatible = "removed-dma-pool"; no-map; - reg = <0x0 0x99700000 0x0 0x10000>; + reg = <0x0 0x98700000 0x0 0x10000>; }; pil_ipa_gsi_mem: pil_ipa_gsi_region { -- GitLab From adeca7003c7fd171f063ae810275383216a7da6c Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Mon, 8 Jun 2020 21:31:40 -0700 Subject: [PATCH 0832/1055] net: stmmac: Disable flow ctrl for RX AVB queues and enable TX AVB queues Ported fix from 5.4: Flow control must be disabled for AVB enabled queues and TX AVB queues must be enabled by setting BIT(2) of TXQEN. Correct this by passing the queue mode to DMA callbacks and by checking in these functions whether we are in AVB performing the necessary adjustments. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller . Change-Id: I4daa59a97d78a427a5bb6f5f0fefb0519aad800e Signed-off-by: Sunil Paidimarri --- drivers/net/ethernet/stmicro/stmmac/common.h | 4 ++-- drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 2 ++ .../net/ethernet/stmicro/stmmac/dwmac4_dma.c | 16 +++++++++++----- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 18 +++++++++++++----- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 7a1678edafa5..3bf926585fa0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -448,9 +448,9 @@ struct stmmac_dma_ops { void (*dma_mode)(void __iomem *ioaddr, int txmode, int rxmode, int rxfifosz); void (*dma_rx_mode)(void __iomem *ioaddr, int mode, u32 channel, - int fifosz); + int fifosz, u8 qmode); void (*dma_tx_mode)(void __iomem *ioaddr, int mode, u32 channel, - int fifosz); + int fifosz, u8 qmode); /* To track extra statistic (if supported) */ void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x, void __iomem *ioaddr); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index ed79bdbfc4f6..aa56a6258ba9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -229,6 +229,8 @@ enum power_event { #define MTL_CHAN_RX_DEBUG(x) (MTL_CHANX_BASE_ADDR(x) + 0x38) #define MTL_OP_MODE_RSF BIT(5) +#define MTL_OP_MODE_TXQEN_MASK GENMASK(3, 2) +#define MTL_OP_MODE_TXQEN_AV BIT(2) #define MTL_OP_MODE_TXQEN BIT(3) #define MTL_OP_MODE_TSF BIT(1) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c index 2bec6118a062..9cdc06a3a113 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c @@ -191,7 +191,7 @@ static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 number_chan) } static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode, - u32 channel, int fifosz) + u32 channel, int fifosz, u8 qmode) { unsigned int rqs = fifosz / 256 - 1; u32 mtl_rx_op, mtl_rx_int; @@ -218,8 +218,10 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode, mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK; mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT; - /* enable flow control only if each channel gets 4 KiB or more FIFO */ - if (fifosz >= 4096) { + /* Enable flow control only if each channel gets 4 KiB or more FIFO and + * only if channel is not an AVB channel. + */ + if (fifosz >= 4096 && qmode != MTL_QUEUE_AVB) { unsigned int rfd, rfa; mtl_rx_op |= MTL_OP_MODE_EHFC; @@ -271,7 +273,7 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode, } static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode, - u32 channel, int fifosz) + u32 channel, int fifosz, u8 qmode) { u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(channel)); unsigned int tqs = fifosz / 256 - 1; @@ -311,7 +313,11 @@ static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode, * reflect the available fifo size per queue (total fifo size / number * of enabled queues). */ - mtl_tx_op |= MTL_OP_MODE_TXQEN; + mtl_tx_op &= ~MTL_OP_MODE_TXQEN_MASK; + if (qmode != MTL_QUEUE_AVB) + mtl_tx_op |= MTL_OP_MODE_TXQEN; + else + mtl_tx_op |= MTL_OP_MODE_TXQEN_AV; mtl_tx_op &= ~MTL_OP_MODE_TQS_MASK; mtl_tx_op |= tqs << MTL_OP_MODE_TQS_SHIFT; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index f6ba02ef92e2..c56ac5cf2e75 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1866,6 +1866,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) u32 rxmode = 0; u32 chan = 0; u32 mtl_rx_int; + u8 qmode = 0; if (rxfifosz == 0) rxfifosz = priv->dma_cap.rx_fifo_size; @@ -1898,8 +1899,10 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) /* configure all channels */ if (priv->synopsys_id >= DWMAC_CORE_4_00) { for (chan = 0; chan < rx_channels_count; chan++) { + qmode = priv->plat->rx_queues_cfg[chan].mode_to_use; + priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan, - rxfifosz); + rxfifosz, qmode); if (priv->rx_queue[chan].skip_sw) { mtl_rx_int = readl_relaxed(priv->ioaddr + (0x00000d00 + 0x2c)); @@ -1909,9 +1912,12 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) } } - for (chan = 0; chan < tx_channels_count; chan++) + for (chan = 0; chan < tx_channels_count; chan++) { + qmode = priv->plat->tx_queues_cfg[chan].mode_to_use; + priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan, - txfifosz); + txfifosz, qmode); + } } else { priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode, rxfifosz); @@ -2094,6 +2100,8 @@ static void stmmac_tx_err(struct stmmac_priv *priv, u32 chan) static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode, u32 rxmode, u32 chan) { + u8 rxqmode = priv->plat->rx_queues_cfg[chan].mode_to_use; + u8 txqmode = priv->plat->tx_queues_cfg[chan].mode_to_use; u32 rx_channels_count = priv->plat->rx_queues_to_use; u32 tx_channels_count = priv->plat->tx_queues_to_use; int rxfifosz = priv->plat->rx_fifo_size; @@ -2110,9 +2118,9 @@ static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode, if (priv->synopsys_id >= DWMAC_CORE_4_00) { priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan, - rxfifosz); + rxfifosz, rxqmode); priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan, - txfifosz); + txfifosz, txqmode); } else { priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode, rxfifosz); -- GitLab From f9d29310415ce41038a92f3f999e9da9928b7643 Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Tue, 9 Jun 2020 10:45:10 -0700 Subject: [PATCH 0833/1055] net: stmmac: dwmac4_prog_mtl_tx_algorithms() missing write operation Ported fix from 5.4: The value of MTL_OPERATION_MODE is not written back. Add check in ethqos to filter unsupported tx_sched_algorithm. Signed-off-by: Cheng Han Signed-off-by: David S. Miller . Change-Id: I329e00414e0942c542eba7ea1d3b24e450400066 Signed-off-by: Sunil Paidimarri --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 7 +++++++ drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 2 ++ 2 files changed, 9 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index f1626e102e50..ecbf4ff0ae88 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -1763,6 +1763,13 @@ static int qcom_ethqos_probe(struct platform_device *pdev) return PTR_ERR(plat_dat); } + if (plat_dat->tx_sched_algorithm == MTL_TX_ALGORITHM_WFQ || + plat_dat->tx_sched_algorithm == MTL_TX_ALGORITHM_DWRR) { + ETHQOSERR("WFO and DWRR TX Algorithm is not supported\n"); + ETHQOSDBG("Set TX Algorithm to default WRR\n"); + plat_dat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR; + } + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rgmii"); ethqos->rgmii_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(ethqos->rgmii_base)) { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index c3414bd93d4a..fa99ffef6530 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -194,6 +194,8 @@ static void dwmac4_prog_mtl_tx_algorithms(struct mac_device_info *hw, default: break; } + + writel_relaxed(value, ioaddr + MTL_OPERATION_MODE); } static void dwmac4_set_mtl_tx_queue_weight(struct mac_device_info *hw, -- GitLab From 8e2c8f593f8029d417dab55c4fddf89734c56e1d Mon Sep 17 00:00:00 2001 From: Dundi Raviteja Date: Fri, 22 May 2020 16:52:00 +0530 Subject: [PATCH 0834/1055] wcnss: Include header file for show_stack() Definition of show_stack() is moved to debug.h in 4.14 kernel. Include sched/debug.h to use this API. Change-Id: I21e5e2b97b3034e9d711a048d4f67f065798fe49 CRs-Fixed: 2708804 Signed-off-by: Dundi Raviteja --- drivers/soc/qcom/wcnss/wcnss_wlan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/wcnss/wcnss_wlan.c b/drivers/soc/qcom/wcnss/wcnss_wlan.c index 5ae9596daab4..fba3dc744061 100644 --- a/drivers/soc/qcom/wcnss/wcnss_wlan.c +++ b/drivers/soc/qcom/wcnss/wcnss_wlan.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include -- GitLab From 532e420d64a8505c6bebb52cc5ab21a9979197ca Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Sat, 13 Jun 2020 10:48:45 +0800 Subject: [PATCH 0835/1055] ARM: dts: msm: Add QDSS IPA bam connection config for sdxprairie Add QDSS IPA bam connection config for QDSS to pcie hw transfer. Change-Id: Id8ab2f9a5b39bde865a8f0e97ab8bcf01fd71483 Signed-off-by: Mao Jinlong --- arch/arm64/boot/dts/qcom/sdxprairie-coresight.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-coresight.dtsi index f48d52a7c9e5..e7c6121925bd 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-coresight.dtsi @@ -165,6 +165,13 @@ arm,buffer-size = <0x400000>; + qcom,qdss-ipa-support; + ipa-conn-data-base-pa = <0x1468B000>; + ipa-conn-data-size = <0x3000>; + ipa-conn-desc-base-pa = <0x1468E000>; + ipa-conn-desc-size = <0x1000>; + ipa-peer-evt-reg-pa = <0x6077818>; + coresight-name = "coresight-tmc-etr"; coresight-ctis = <&cti0 &cti0>; coresight-csr = <&csr>; -- GitLab From 3b449fb6a5926dd3731cfaad4bb24b2dd8545174 Mon Sep 17 00:00:00 2001 From: Vishwanath Raju K Date: Wed, 29 Apr 2020 21:12:14 +0530 Subject: [PATCH 0836/1055] ARM: dts: msm: update to memory map v1 for QCS610 and QCS410 Memory map of qcs610 and qcs410 has been changed,these changes are mainly in pil subsystem. Change-Id: Ifae0d6b65d3012a2068651738d22f5d84ef7cce2 Signed-off-by: Vishwanath Raju K --- arch/arm64/boot/dts/qcom/qcs410-iot.dtsi | 30 +++++++++++++++++++++++- arch/arm64/boot/dts/qcom/qcs610-iot.dtsi | 28 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi b/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi index 96fb1d37b317..8442845503e8 100644 --- a/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, 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 @@ -185,6 +185,34 @@ reg = <0 0x8fd00000 0 0x3100000>; }; +&pil_video_mem { + reg = <0 0x92e00000 0 0x500000>; +}; + +&wlan_msa_mem { + reg = <0 0x93300000 0 0x200000>; +}; + +&pil_cdsp_mem { + reg = <0 0x93500000 0 0x1e00000>; +}; + +&pil_adsp_mem { + reg = <0 0x95300000 0 0x1e00000>; +}; + +&pil_ipa_fw_mem { + reg = <0 0x97100000 0 0x10000>; +}; + +&pil_ipa_gsi_mem { + reg = <0 0x97110000 0 0x5000>; +}; + +&pil_gpu_mem { + reg = <0 0x97115000 0 0x2000>; +}; + &L16A { regulator-max-microvolt = <3304000>; }; diff --git a/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi b/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi index 63a8139732ba..0486fd6dbcec 100644 --- a/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs610-iot.dtsi @@ -275,6 +275,34 @@ reg = <0 0x8fd00000 0 0x3100000>; }; +&pil_video_mem { + reg = <0 0x92e00000 0 0x500000>; +}; + +&wlan_msa_mem { + reg = <0 0x93300000 0 0x200000>; +}; + +&pil_cdsp_mem { + reg = <0 0x93500000 0 0x1e00000>; +}; + +&pil_adsp_mem { + reg = <0 0x95300000 0 0x1e00000>; +}; + +&pil_ipa_fw_mem { + reg = <0 0x97100000 0 0x10000>; +}; + +&pil_ipa_gsi_mem { + reg = <0 0x97110000 0 0x5000>; +}; + +&pil_gpu_mem { + reg = <0 0x97115000 0 0x2000>; +}; + &sdhc_1 { vdd-supply = <&pm6150l_l11>; qcom,vdd-voltage-level = <2950000 2950000>; -- GitLab From fec255408d0d03b016a10caf14423b370a5272df Mon Sep 17 00:00:00 2001 From: Gopala Krishna Nuthaki Date: Mon, 15 Jun 2020 11:58:59 +0530 Subject: [PATCH 0837/1055] ARM: dts: msm: Add a flag to enable TSENS re-init Add a boolean flag to enable the re-initialization of TSENS controller when goes to bad state while reading temperature for sdmmagpie. Change-Id: I3458cc71f9f941d0493fd6eb1663697e1d792f90 Signed-off-by: Ajay Prathi Signed-off-by: Gopala Krishna Nuthaki --- arch/arm64/boot/dts/qcom/sdmmagpie.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi index e5d0292f5518..86098aa8ccba 100644 --- a/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmmagpie.dtsi @@ -1470,6 +1470,7 @@ "tsens_tm_physical"; interrupts = <0 506 0>, <0 508 0>; interrupt-names = "tsens-upper-lower", "tsens-critical"; + tsens-reinit-wa; #thermal-sensor-cells = <1>; }; @@ -1481,6 +1482,7 @@ "tsens_tm_physical"; interrupts = <0 507 0>, <0 509 0>; interrupt-names = "tsens-upper-lower", "tsens-critical"; + tsens-reinit-wa; #thermal-sensor-cells = <1>; }; -- GitLab From cca6fe988afa7737af879ec4b6ee19ecd82743c0 Mon Sep 17 00:00:00 2001 From: Udipto Goswami Date: Wed, 3 Jun 2020 11:27:50 +0530 Subject: [PATCH 0838/1055] USB: f_mtp: Revert Avoid queuing of receive_file_work for 0 length Commit 76f7005ad3b4 ("USB: f_mtp: Avoid queuing of receive_file_work for 0 length") adds a check for 0 length file and avoid queuing in order to save some milliseconds in mtp file transfers. However, this approach is correct only for windows system as it ignores 0 length files but other OS like MAC & Ubuntu do not follow this logic. They allows 0 length file to be copied which is why mtp file transfer failure is observed when target is connected to MAC or Ubuntu. Fix this by reverting the check for 0 length. Change-Id: I48559e89afa7a4220bdef3f078e2aa739c402b4b Signed-off-by: Udipto Goswami --- drivers/usb/gadget/function/f_mtp.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c index f6beba60ea28..34928a0a00df 100644 --- a/drivers/usb/gadget/function/f_mtp.c +++ b/drivers/usb/gadget/function/f_mtp.c @@ -1125,18 +1125,15 @@ static long mtp_send_receive_ioctl(struct file *fp, unsigned int code, * in kernel context, which is necessary for vfs_read and * vfs_write to use our buffers in the kernel address space. */ - dev->xfer_result = 0; - if (dev->xfer_file_length) { - queue_work(dev->wq, work); - /* wait for operation to complete */ - flush_workqueue(dev->wq); - - /* read the result */ - smp_rmb(); - } - ret = dev->xfer_result; + queue_work(dev->wq, work); + /* wait for operation to complete */ + flush_workqueue(dev->wq); fput(filp); + /* read the result */ + smp_rmb(); + ret = dev->xfer_result; + fail: spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) -- GitLab From 20b8d6cad37491a5d4d22566c7747502f7b9c190 Mon Sep 17 00:00:00 2001 From: Sneh Shah Date: Mon, 13 Apr 2020 11:38:40 +0530 Subject: [PATCH 0839/1055] net: stmmac: read descriptor count for IPA rx/tx from dt entry Add support to read descriptor count for IPA ch from dt entry. Change-Id: Ice9a4034275904abef374800c99b01abce44c908 Signed-off-by: Sneh Shah --- .../ethernet/stmicro/stmmac/dwmac-qcom-ipa.c | 26 ++++++++++++++++--- .../ethernet/stmicro/stmmac/dwmac-qcom-ipa.h | 7 +++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.c index 3abe32c5842d..b0f23d70fe87 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.c @@ -95,7 +95,7 @@ static int ethqos_alloc_ipa_tx_queue_struct(struct qcom_ethqos *ethqos) goto err_out_tx_q_alloc_failed; } - eth_ipa_ctx.tx_queue->desc_cnt = IPA_TX_DESC_CNT; + eth_ipa_ctx.tx_queue->desc_cnt = eth_ipa_ctx.ipa_dma_tx_desc_cnt; /* Allocate tx_desc_ptrs */ eth_ipa_ctx.tx_queue->tx_desc_ptrs = @@ -224,7 +224,7 @@ static int ethqos_alloc_ipa_rx_queue_struct(struct qcom_ethqos *ethqos) goto err_out_rx_q_alloc_failed; } - eth_ipa_ctx.rx_queue->desc_cnt = IPA_RX_DESC_CNT; + eth_ipa_ctx.rx_queue->desc_cnt = eth_ipa_ctx.ipa_dma_rx_desc_cnt; /* Allocate rx_desc_ptrs */ eth_ipa_ctx.rx_queue->rx_desc_ptrs = @@ -1630,8 +1630,8 @@ static int ethqos_ipa_create_debugfs(struct qcom_ethqos *ethqos) debugfs_create_file("dma_stats", 0600, ethqos->debugfs_dir, ethqos, &fops_ntn_dma_stats); - if (!eth_ipa->debugfs_suspend_ipa_offload || - IS_ERR(eth_ipa->debugfs_suspend_ipa_offload)) { + if (!eth_ipa->debugfs_dma_stats || + IS_ERR(eth_ipa->debugfs_dma_stats)) { ETHQOSERR("Cannot create debugfs_dma_stats %d\n", (int)eth_ipa->debugfs_dma_stats); goto fail; @@ -2159,11 +2159,29 @@ static int ethqos_ipa_uc_ready(struct qcom_ethqos *pdata) void ethqos_ipa_offload_event_handler(void *data, int ev) { + int ret; ETHQOSDBG("Enter: event=%d\n", ev); if (ev == EV_PROBE_INIT) { eth_ipa_ctx.ethqos = data; mutex_init(ð_ipa_ctx.ipa_lock); + ret = + of_property_read_u32(eth_ipa_ctx.ethqos->pdev->dev.of_node, + "ipa-dma-rx-desc-cnt", + ð_ipa_ctx.ipa_dma_rx_desc_cnt); + if (ret) { + ETHQOSDBG(":resource ipa-dma-rx-desc-cnt not in dt\n"); + eth_ipa_ctx.ipa_dma_rx_desc_cnt = IPA_RX_DESC_CNT; + } + + ret = + of_property_read_u32(eth_ipa_ctx.ethqos->pdev->dev.of_node, + "ipa-dma-tx-desc-cnt", + ð_ipa_ctx.ipa_dma_tx_desc_cnt); + if (ret) { + ETHQOSDBG(":resource ipa-dma-tx-desc-cnt not in dt\n"); + eth_ipa_ctx.ipa_dma_tx_desc_cnt = IPA_TX_DESC_CNT; + } return; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.h b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.h index fd6dd0b2a335..419f54da1b75 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ipa.h @@ -79,8 +79,8 @@ static char * const IPA_OFFLOAD_EVENT_string[] = { #define ETHQOS_ETH_FRAME_LEN_IPA ((1 << 11)) /*IPA can support 2KB max length*/ -#define IPA_TX_DESC_CNT 128 /*Increase TX desc count to 128 for IPA offload*/ -#define IPA_RX_DESC_CNT 128 /*Increase RX desc count to 128 for IPA offload*/ +#define IPA_TX_DESC_CNT 128 /*Default TX desc count to 128 for IPA offload*/ +#define IPA_RX_DESC_CNT 128 /*Default RX desc count to 128 for IPA offload*/ #define BASE_ADDRESS (ethqos->ioaddr) @@ -647,6 +647,9 @@ struct ethqos_prv_ipa_data { phys_addr_t uc_db_tx_addr; u32 ipa_client_hndl; + u32 ipa_dma_tx_desc_cnt; + u32 ipa_dma_rx_desc_cnt; + /* IPA state variables */ /* State of EMAC HW initialization */ bool emac_dev_ready; -- GitLab From 692bb300ed2f4a8447742da7955082dae2d7618d Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Tue, 2 Jun 2020 11:30:49 -0700 Subject: [PATCH 0840/1055] net: stmmac: Fix type casting for tlmm addr Fix type casting for tlmm addr. Change-Id: I3244ab394db6fef3d78cba6c17ffb9a12534d4cb Acked-by: Rahul Kawadgave Signed-off-by: Sunil Paidimarri --- drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index f1626e102e50..671906b04af1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -30,7 +30,7 @@ #include "stmmac_ptp.h" #include "dwmac-qcom-ipa-offload.h" -static unsigned long tlmm_central_base_addr; +static void __iomem *tlmm_central_base_addr; bool phy_intr_en; struct qcom_ethqos *pethqos; @@ -1417,9 +1417,9 @@ static int ethqos_update_rgmii_tx_drv_strength(struct qcom_ethqos *ethqos) ETHQOSDBG("tlmm_central_base = 0x%x, size = 0x%x\n", tlmm_central_base, tlmm_central_size); - tlmm_central_base_addr = (unsigned long)ioremap( + tlmm_central_base_addr = ioremap( tlmm_central_base, tlmm_central_size); - if ((void __iomem *)!tlmm_central_base_addr) { + if (!tlmm_central_base_addr) { ETHQOSERR("cannot map dwc_tlmm_central reg memory, aborting\n"); ret = -EIO; goto err_out; @@ -1459,7 +1459,7 @@ static int ethqos_update_rgmii_tx_drv_strength(struct qcom_ethqos *ethqos) err_out: if (tlmm_central_base_addr) - iounmap((void __iomem *)tlmm_central_base_addr); + iounmap(tlmm_central_base_addr); return ret; } -- GitLab From 8da9587b76c6743c54e60dcb719ce8d27a7b8c01 Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Wed, 6 May 2020 11:06:57 -0700 Subject: [PATCH 0841/1055] defconfig: sa2150p: Enable STMMAC driver Enable STMMAC driver for EMAC HW. Change-Id: Id53ac552e477da0e321f5b64060938bf481176ae Acked-by: Rahul Kawadgave Signed-off-by: Sunil Paidimarri --- arch/arm64/configs/vendor/sa2150p-perf_defconfig | 4 +++- arch/arm64/configs/vendor/sa2150p_defconfig | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm64/configs/vendor/sa2150p-perf_defconfig b/arch/arm64/configs/vendor/sa2150p-perf_defconfig index 1effd0037e87..f5e65eed857b 100644 --- a/arch/arm64/configs/vendor/sa2150p-perf_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-perf_defconfig @@ -249,6 +249,9 @@ CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_STMMAC_ETH=y +# CONFIG_DWMAC_GENERIC is not set +# CONFIG_DWMAC_IPQ806X is not set CONFIG_AT803X_PHY=y CONFIG_MICREL_PHY=y CONFIG_PPP=y @@ -290,7 +293,6 @@ CONFIG_SPI_QUP=y CONFIG_SPMI=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PPS_CLIENT_GPIO=y -CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_QCS405=y CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y diff --git a/arch/arm64/configs/vendor/sa2150p_defconfig b/arch/arm64/configs/vendor/sa2150p_defconfig index 74fdcd58b816..3ed8ba7dce30 100644 --- a/arch/arm64/configs/vendor/sa2150p_defconfig +++ b/arch/arm64/configs/vendor/sa2150p_defconfig @@ -255,6 +255,9 @@ CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y +CONFIG_STMMAC_ETH=y +# CONFIG_DWMAC_GENERIC is not set +# CONFIG_DWMAC_IPQ806X is not set CONFIG_AT803X_PHY=y CONFIG_MICREL_PHY=y CONFIG_PPP=y @@ -300,7 +303,6 @@ CONFIG_SPMI=y CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PPS_CLIENT_GPIO=y -CONFIG_PTP_1588_CLOCK=y CONFIG_PINCTRL_QCS405=y CONFIG_FRAGMENTED_GPIO_ADDRESS_SPACE=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y -- GitLab From bcec534d22ddace156bded0bf401d59943a4c634 Mon Sep 17 00:00:00 2001 From: Ajay Prathi Date: Tue, 2 Jun 2020 10:58:56 +0530 Subject: [PATCH 0842/1055] msm: ep_pcie: Update bit to read if the PHY is ready Update status bit to check if PHY is ready. Change-Id: I39d1c292c1c7a98e155b0ae94103455f5c8b0e3a Signed-off-by: Siddartha Mohanadoss Signed-off-by: Ajay Prathi --- .../devicetree/bindings/pci/msm_ep_pcie.txt | 2 ++ drivers/platform/msm/ep_pcie/ep_pcie_com.h | 1 + drivers/platform/msm/ep_pcie/ep_pcie_core.c | 15 +++++++++++++++ drivers/platform/msm/ep_pcie/ep_pcie_phy.c | 4 ++-- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt b/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt index 8883f779bcd6..c364f472cc0b 100644 --- a/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt +++ b/Documentation/devicetree/bindings/pci/msm_ep_pcie.txt @@ -48,6 +48,8 @@ Optional Properties: - qcom,phy-init: The initialization sequence to bring up the PCIe PHY. Should be specified in groups (offset, value, delay, direction). - qcom,phy-status-reg: Register offset for PHY status. + - qcom,phy-status-reg2: For sdxprairie and above use only + qcom,phy-status-reg2 as register offset for PHY status. - qcom,dbi-base-reg: Register offset for DBI base address. - qcom,slv-space-reg: Register offset for slave address space size. - qcom,pcie-vendor-id: Vendor id to be written to the Vendor ID register. diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_com.h b/drivers/platform/msm/ep_pcie/ep_pcie_com.h index a6044f85c39d..e77734e1b476 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_com.h +++ b/drivers/platform/msm/ep_pcie/ep_pcie_com.h @@ -372,6 +372,7 @@ struct ep_pcie_dev_t { u32 dbi_base_reg; u32 slv_space_reg; u32 phy_status_reg; + u32 phy_status_bit_mask_bit; u32 phy_init_len; u32 mhi_soc_reset_offset; struct ep_pcie_phy_info_t *phy_init; diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index e087bd4c93bf..7372114c6fa8 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -3074,6 +3074,21 @@ static int ep_pcie_probe(struct platform_device *pdev) EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: phy-status-reg:0x%x\n", ep_pcie_dev.rev, ep_pcie_dev.phy_status_reg); + ep_pcie_dev.phy_status_bit_mask_bit = BIT(6); + + ret = of_property_read_u32((&pdev->dev)->of_node, + "qcom,phy-status-reg2", + &ep_pcie_dev.phy_status_reg); + if (ret) { + EP_PCIE_DBG(&ep_pcie_dev, + "PCIe V%d: phy-status-reg2 does not exist\n", + ep_pcie_dev.rev); + } else { + EP_PCIE_DBG(&ep_pcie_dev, "PCIe V%d: phy-status-reg2:0x%x\n", + ep_pcie_dev.rev, ep_pcie_dev.phy_status_reg); + ep_pcie_dev.phy_status_bit_mask_bit = BIT(7); + } + ep_pcie_dev.phy_rev = 1; ret = of_property_read_u32((&pdev->dev)->of_node, "qcom,pcie-phy-ver", diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c index 89562ef33cea..0b95947ba3d9 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_phy.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_phy.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, 2019-2020, 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 @@ -158,7 +158,7 @@ bool ep_pcie_phy_is_ready(struct ep_pcie_dev_t *dev) else offset = PCIE_PHY_PCS_STATUS; - if (readl_relaxed(dev->phy + offset) & BIT(6)) + if (readl_relaxed(dev->phy + offset) & dev->phy_status_bit_mask_bit) return false; else return true; -- GitLab From 38346899188a424a6eeac683249ab87fe60965cc Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Sun, 14 Jun 2020 17:22:30 +0530 Subject: [PATCH 0843/1055] ARM: dts: msm: add override nodes for SA515M CDP board This commit adds device tree overrides for PMIC, thermal, USB, SPMI, NAND and UART as applicable for SA515M CDP platform for telematics. Change-Id: I122a03d2d4093f467912dab81ed6ea378845f26b Signed-off-by: Rishi Gupta --- .../boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts b/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts index af338a7787c5..81dfac855db4 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts +++ b/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts @@ -16,9 +16,50 @@ #include "sdxprairie-cdp.dtsi" / { - model = "Qualcomm Technologies, Inc. SDXPRAIRIE v2 CDP - TELEMATICS AU DSDA"; + model = "Qualcomm Technologies, Inc. SDXPRAIRIE v2 CDP TEL AU DSDA"; compatible = "qcom,sdxprairie-cdp", "qcom,sdxprairie", "qcom,cdp"; qcom,board-id = <0x6010001 0x0>; }; + +/* delete pm8150b nodes */ +&thermal_zones { + /delete-node/ pm8150b-wp-therm; + /delete-node/ pm8150b_tz; + /delete-node/ pm8150b-ibat-lvl0; + /delete-node/ pm8150b-ibat-lvl1; + /delete-node/ pm8150b-vbat-lvl0; + /delete-node/ pm8150b-vbat-lvl1; + /delete-node/ pm8150b-vbat-lvl2; + /delete-node/ pm8150b-bcl-lvl0; + /delete-node/ pm8150b-bcl-lvl1; + /delete-node/ pm8150b-bcl-lvl2; + /delete-node/ soc; +}; + +&usb { + extcon = <&vbus_detect>; +}; + +&spmi_bus { + /delete-node/ qpnp,fg; + /delete-node/ bcl@1d00; + /delete-node/ qcom,usb-pdphy@1700; + /delete-node/ qcom,qpnp-smb5; + /delete-node/ adc_tm@3500; + /delete-node/ vadc@3100; + /delete-node/ qcom,pm8150b@2; + /delete-node/ qcom,pm8150b@3; +}; + +&qnand_1 { + status = "ok"; +}; + +&blsp1_uart2b_hs { + status = "okay"; +}; + +&vbus_detect { + status = "okay"; +}; -- GitLab From c3b28f9aaa0741cb12715dd431c4083dfb65dc64 Mon Sep 17 00:00:00 2001 From: Elson Roy Serrao Date: Tue, 15 Oct 2019 13:52:45 -0700 Subject: [PATCH 0844/1055] usb: gadget: Reset string ids upon unbind String ids for qdss,cdev and gsi based interfaces are re-used even though the device re-enumerates. This is causing string id sequence mismatch and resulting in adb using the string id of qdss interface. Reset the string ids for these functions in their respective unbind calls to fix this issue. Change-Id: Ia9b196734a99ccc2e8c35073ec4e535755774c16 Signed-off-by: Elson Roy Serrao --- drivers/usb/gadget/function/f_cdev.c | 3 +++ drivers/usb/gadget/function/f_gsi.c | 7 +++++++ drivers/usb/gadget/function/f_qdss.c | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 0d3e8c6f15cb..b5926b0d0c30 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -898,6 +898,9 @@ static void usb_cser_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_cdev *port = func_to_port(f); + /* Reset string id */ + cser_string_defs[0].id = 0; + usb_free_all_descriptors(f); usb_cser_free_req(port->port_usb.notify, port->port_usb.notify_req); } diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c index 4a8da48b76dd..5a2b8ab2b95c 100644 --- a/drivers/usb/gadget/function/f_gsi.c +++ b/drivers/usb/gadget/function/f_gsi.c @@ -3359,6 +3359,13 @@ static void gsi_unbind(struct usb_configuration *c, struct usb_function *f) drain_workqueue(gsi->d_port.ipa_usb_wq); ipa_usb_deinit_teth_prot((enum ipa_usb_teth_prot)gsi->prot_id); + /* Reset string ids */ + rndis_gsi_string_defs[0].id = 0; + ecm_gsi_string_defs[0].id = 0; + rmnet_gsi_string_defs[0].id = 0; + mbim_gsi_string_defs[0].id = 0; + qdss_gsi_string_defs[0].id = 0; + skip_ipa_dinit: if (gsi->prot_id == USB_PROT_RNDIS_IPA) { gsi->d_port.sm_state = STATE_UNINITIALIZED; diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 41c92e8e6198..6695a40d2af5 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -526,6 +526,10 @@ static void qdss_unbind(struct usb_configuration *c, struct usb_function *f) flush_workqueue(qdss->wq); + /* Reset string ids */ + qdss_string_defs[QDSS_DATA_IDX].id = 0; + qdss_string_defs[QDSS_CTRL_IDX].id = 0; + qdss->debug_inface_enabled = 0; clear_eps(f); -- GitLab From daee5bd65dfca23adf7364d445cc804da9103f61 Mon Sep 17 00:00:00 2001 From: Charan Teja Reddy Date: Fri, 17 Apr 2020 22:03:30 +0530 Subject: [PATCH 0845/1055] dma-buf: fix race while reading the dma_buf in dmabuffs_dname The following race occurs while reading the dma_buf: P1 P2 dma_buf_release() dmabuffs_dname()[say from /proc/pid/fd/num] read dmabuf stored in dentry->fsdata Free the dmabuf object Start accessing the dmabuf structure As said above, we access the dmabuf structure after we free the dmabuf object resulting into the below 'use-after-free' issue. __mutex_lock_common+0x174/0x1020 mutex_lock_nested+0x40/0x50 dmabuffs_dname+0x48/0xc8 d_path+0x84/0x290 proc_pid_readlink+0xb4/0x1c8 vfs_readlink+0x128/0x130 do_readlinkat+0xc8/0x148 __arm64_sys_readlinkat+0x24/0x38 el0_svc_common+0xa4/0x178 el0_svc_handler+0x6c/0x88 el0_svc+0x8/0xc. Fixes: bf93f26 ("UPSTREAM: dma-buf: add DMA_BUF_SET_NAME ioctls") Change-Id: Ie0a833f185687f4cc7ab8189b17fde3516270572 Signed-off-by: Charan Teja Reddy Signed-off-by: Naitik Bharadiya --- drivers/dma-buf/dma-buf.c | 27 ++++++++++++++++++++++++--- include/linux/dma-buf.h | 2 ++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index a9c82e9b8892..8798370b0250 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -69,18 +70,34 @@ struct dma_proc { static struct dma_buf_list db_list; +static void dmabuf_dent_put(struct dma_buf *dmabuf) +{ + if (atomic_dec_and_test(&dmabuf->dent_count)) { + kfree(dmabuf->name); + kfree(dmabuf); + } +} + + static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen) { struct dma_buf *dmabuf; char name[DMA_BUF_NAME_LEN]; size_t ret = 0; + spin_lock(&dentry->d_lock); dmabuf = dentry->d_fsdata; + if (!dmabuf || !atomic_add_unless(&dmabuf->dent_count, 1, 0)) { + spin_unlock(&dentry->d_lock); + goto out; + } + spin_unlock(&dentry->d_lock); mutex_lock(&dmabuf->lock); if (dmabuf->name) ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN); mutex_unlock(&dmabuf->lock); - + dmabuf_dent_put(dmabuf); +out: return dynamic_dname(dentry, buffer, buflen, "/%s:%s", dentry->d_name.name, ret > 0 ? name : ""); } @@ -107,12 +124,16 @@ static struct file_system_type dma_buf_fs_type = { static int dma_buf_release(struct inode *inode, struct file *file) { struct dma_buf *dmabuf; + struct dentry *dentry = file->f_path.dentry; if (!is_dma_buf_file(file)) return -EINVAL; dmabuf = file->private_data; + spin_lock(&dentry->d_lock); + dentry->d_fsdata = NULL; + spin_unlock(&dentry->d_lock); BUG_ON(dmabuf->vmapping_counter); /* @@ -137,8 +158,7 @@ static int dma_buf_release(struct inode *inode, struct file *file) reservation_object_fini(dmabuf->resv); module_put(dmabuf->owner); - kfree(dmabuf->buf_name); - kfree(dmabuf); + dmabuf_dent_put(dmabuf); return 0; } @@ -608,6 +628,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) dmabuf->cb_excl.active = dmabuf->cb_shared.active = 0; dmabuf->buf_name = bufname; dmabuf->ktime = ktime_get(); + atomic_set(&dmabuf->dent_count, 1); if (!resv) { resv = (struct reservation_object *)&dmabuf[1]; diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index a3d4da1cb14d..76647fd57a0e 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -433,6 +433,8 @@ struct dma_buf { } cb_excl, cb_shared; struct list_head refs; + atomic_t dent_count; + }; /** -- GitLab From f6c095023cb211c703f365dd825ee2c293c0eb6c Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Tue, 5 Mar 2019 11:41:09 -0800 Subject: [PATCH 0846/1055] usb: gadget: f_qdss: Allocate one string ID for all instances In case multi instance of driver exist in same composition, id of the string gets overridden due to multiple bind() calls. This results in STALL on GET_DESCRIPTOR (string type) on interface string descriptor index which got overridden. Fix this issue by assigning one string ID to all interface string desc index of the driver. Change-Id: If61455e9786175a1dd435320bfb54f2949e4ffa4 Signed-off-by: Hemant Kumar --- drivers/usb/gadget/function/f_qdss.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index 6695a40d2af5..d557e2bbe4ba 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -2,7 +2,6 @@ * f_qdss.c -- QDSS function Driver * * Copyright (c) 2012-2018, 2020, 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. @@ -423,11 +422,13 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f) qdss_data_intf_desc.bInterfaceNumber = iface; qdss->data_iface_id = iface; - id = usb_string_id(c->cdev); - if (id < 0) - return id; - qdss_string_defs[QDSS_DATA_IDX].id = id; - qdss_data_intf_desc.iInterface = id; + if (!qdss_string_defs[QDSS_DATA_IDX].id) { + id = usb_string_id(c->cdev); + if (id < 0) + return id; + qdss_string_defs[QDSS_DATA_IDX].id = id; + qdss_data_intf_desc.iInterface = id; + } if (qdss->debug_inface_enabled) { /* Allocate ctrl I/F */ @@ -438,11 +439,14 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f) } qdss_ctrl_intf_desc.bInterfaceNumber = iface; qdss->ctrl_iface_id = iface; - id = usb_string_id(c->cdev); - if (id < 0) - return id; - qdss_string_defs[QDSS_CTRL_IDX].id = id; - qdss_ctrl_intf_desc.iInterface = id; + + if (!qdss_string_defs[QDSS_CTRL_IDX].id) { + id = usb_string_id(c->cdev); + if (id < 0) + return id; + qdss_string_defs[QDSS_CTRL_IDX].id = id; + qdss_ctrl_intf_desc.iInterface = id; + } } /* for non-accelerated path keep tx fifo size 1k */ -- GitLab From a2806137d27572f04bed5434da7a88b0f165daf9 Mon Sep 17 00:00:00 2001 From: Rama Krishna Phani A Date: Tue, 9 Jun 2020 22:27:49 +0530 Subject: [PATCH 0847/1055] msm: ep_pcie: Vote for pipe clk for early init case Few usecases will have early init feature enabled where PCIe link is established in PBL. In such cases EP PCIe driver is not voting for pipe clk but unvoting it as part of PCIe link suspend, causing unbalanced voting for that clk. Update logic to vote for PCIe pipe clk for early init case. Change-Id: Ibb26e88b1b3fb4426a2c03bf3031633e3fb4639f Signed-off-by: Rama Krishna Phani A --- drivers/platform/msm/ep_pcie/ep_pcie_core.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index e087bd4c93bf..c7e8f28cb91b 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -1712,6 +1712,15 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt) ep_pcie_core_init(dev, true); dev->link_status = EP_PCIE_LINK_UP; dev->l23_ready = false; + + /* enable pipe clock for early link init case*/ + ret = ep_pcie_pipe_clk_init(dev); + if (ret) { + EP_PCIE_ERR(dev, + "PCIe V%d: failed to enable pipe clock\n", + dev->rev); + goto pipe_clk_fail; + } goto checkbme; } else { ltssm_en = readl_relaxed(dev->parf -- GitLab From 9367fc75428d24f656ad84253aaedec43aca0087 Mon Sep 17 00:00:00 2001 From: Veera Vegivada Date: Thu, 28 May 2020 15:56:36 +0530 Subject: [PATCH 0848/1055] clk: Add prepare lock in clk_populate_clock_opp_table After enabling CONFIG_PROVE_LOCKING, observed dumpstacks in the boot time. Call trace: clk_core_round_rate_nolock+0xd4/0xe0 clk_hw_round_rate+0x4c/0x80 clk_populate_clock_opp_table+0x168/0x318 devm_clk_hw_register+0x88/0x9c devm_clk_register_regmap+0x54/0x60 qcom_cc_really_probe+0x114/0x208 clk_hw_round_rate() required to be called with prepare lock held. So acquire prepare lock before invoking clk_hw_round_rate(). Change-Id: I608e9e7cfe7a5a43fa0e0543b909cefe59030067 Signed-off-by: Veera Vegivada --- drivers/clk/clk.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f5a48671389b..20ac4135620a 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -4109,6 +4109,7 @@ static int clk_add_and_print_opp(struct clk_hw *hw, unsigned long rate, int uv, int n) { struct clk_core *core = hw->core; + unsigned long rrate; int j, ret = 0; for (j = 0; j < count; j++) { @@ -4119,8 +4120,11 @@ static int clk_add_and_print_opp(struct clk_hw *hw, return ret; } - if (n == 0 || n == core->num_rate_max - 1 || - rate == clk_hw_round_rate(hw, INT_MAX)) + clk_prepare_lock(); + rrate = clk_hw_round_rate(hw, INT_MAX); + clk_prepare_unlock(); + + if (n == 0 || n == core->num_rate_max - 1 || rate == rrate) pr_info("%s: set OPP pair(%lu Hz: %u uV) on %s\n", core->name, rate, uv, dev_name(device_list[j])); @@ -4175,7 +4179,9 @@ static void clk_populate_clock_opp_table(struct device_node *np, } for (n = 0; ; n++) { + clk_prepare_lock(); rrate = clk_hw_round_rate(hw, rate + 1); + clk_prepare_unlock(); if (!rrate) { pr_err("clk_round_rate failed for %s\n", core->name); -- GitLab From 6257f5b1dee06a7c474893a3d1f9050fe43c7dc0 Mon Sep 17 00:00:00 2001 From: Narender Ankam Date: Mon, 11 May 2020 16:01:02 +0530 Subject: [PATCH 0849/1055] ARM: dts: msm: Update display ram dump memory size Update display ram dump memory size to be same as splash memory size. Change-Id: Ic1eb959046f9be6a6ca8686fe2b7b5acbe71b502 Signed-off-by: Narender Ankam --- arch/arm64/boot/dts/qcom/sm6150.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm6150.dtsi b/arch/arm64/boot/dts/qcom/sm6150.dtsi index 4eed5815d029..7b832f717929 100644 --- a/arch/arm64/boot/dts/qcom/sm6150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6150.dtsi @@ -634,7 +634,7 @@ }; disp_rdump_memory: disp_rdump_region@9c000000 { - reg = <0x0 0x9c000000 0x0 0x01000000>; + reg = <0x0 0x9c000000 0x0 0x0f00000>; label = "disp_rdump_region"; }; -- GitLab From 530a18767265aff9bdef876a4d7b1d9e1fec9aa7 Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Tue, 9 Jun 2020 23:03:01 +0530 Subject: [PATCH 0850/1055] mtd: msm_qpic_nand: check for page_erased bit along with op_err Due to a hardware bug in ECC-Engine, ECC-Engine couldn't able to set OP_ERR bit in flash_status regesiter whenever an erased page encounters bitflips. Due to this, ECC-Engine is trying to correct the bitflips on an erased page and leading to data corruption. So, a check for PAGE_ERASED bit is added prior to OP_ERR bit for an erased page detection logic. Change-Id: I570625123fe828450dade06570f782ebe93d39f1 Signed-off-by: Pradeep P V K --- drivers/mtd/devices/msm_qpic_nand.c | 62 +++++++++++++++++++++++++++-- drivers/mtd/devices/msm_qpic_nand.h | 8 +++- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c index e094673f9cac..3b94bc33bcd1 100644 --- a/drivers/mtd/devices/msm_qpic_nand.c +++ b/drivers/mtd/devices/msm_qpic_nand.c @@ -1993,7 +1993,7 @@ static int msm_nand_is_erased_page_ps(struct mtd_info *mtd, loff_t from, if (last_pos < ecc_bytes_percw_in_bits) num_zero_bits++; - if (num_zero_bits > 4) { + if (num_zero_bits > MAX_ECC_BIT_FLIPS) { *erased_page = false; goto free_mem; } @@ -2005,7 +2005,7 @@ static int msm_nand_is_erased_page_ps(struct mtd_info *mtd, loff_t from, ecc_temp += chip->ecc_parity_bytes; } - if ((n == cwperpage) && (num_zero_bits <= 4)) + if ((n == cwperpage) && (num_zero_bits <= MAX_ECC_BIT_FLIPS)) *erased_page = true; free_mem: kfree(ecc); @@ -2228,6 +2228,33 @@ static int msm_nand_read_pagescope(struct mtd_info *mtd, loff_t from, goto free_dma; /* Check for flash status errors */ pageerr = rawerr = 0; + + /* + * PAGE_ERASED bit will set only if all + * CODEWORD_ERASED bit of all codewords + * of the page is set. + * + * PAGE_ERASED bit is a 'logical and' of all + * CODEWORD_ERASED bit of all codewords i.e. + * even if one codeword is detected as not + * an erased codeword, PAGE_ERASED bit will unset. + */ + for (n = rw_params.start_sector; n < cwperpage; n++) { + if ((dma_buffer->result[n].erased_cw_status & + (1 << PAGE_ERASED)) && + (dma_buffer->result[n].buffer_status & + NUM_ERRORS)) { + err = msm_nand_is_erased_page_ps(mtd, + from, ops, + &rw_params, + &erased_page); + if (err) + goto free_dma; + if (erased_page) + rawerr = -EIO; + break; + } + } for (n = rw_params.start_sector; n < cwperpage; n++) { if (dma_buffer->result[n].flash_status & (FS_OP_ERR | FS_MPU_ERR)) { @@ -2633,7 +2660,7 @@ static int msm_nand_is_erased_page(struct mtd_info *mtd, loff_t from, if (last_pos < ecc_bytes_percw_in_bits) num_zero_bits++; - if (num_zero_bits > 4) { + if (num_zero_bits > MAX_ECC_BIT_FLIPS) { *erased_page = false; goto free_mem; } @@ -2645,7 +2672,7 @@ static int msm_nand_is_erased_page(struct mtd_info *mtd, loff_t from, ecc_temp += chip->ecc_parity_bytes; } - if ((n == cwperpage) && (num_zero_bits <= 4)) + if ((n == cwperpage) && (num_zero_bits <= MAX_ECC_BIT_FLIPS)) *erased_page = true; free_mem: kfree(ecc); @@ -2840,6 +2867,33 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, goto free_dma; /* Check for flash status errors */ pageerr = rawerr = 0; + + /* + * PAGE_ERASED bit will set only if all + * CODEWORD_ERASED bit of all codewords + * of the page is set. + * + * PAGE_ERASED bit is a 'logical and' of all + * CODEWORD_ERASED bit of all codewords i.e. + * even if one codeword is detected as not + * an erased codeword, PAGE_ERASED bit will unset. + */ + for (n = rw_params.start_sector; n < cwperpage; n++) { + if ((dma_buffer->result[n].erased_cw_status & + (1 << PAGE_ERASED)) && + (dma_buffer->result[n].buffer_status & + NUM_ERRORS)) { + err = msm_nand_is_erased_page(mtd, + from, ops, + &rw_params, + &erased_page); + if (err) + goto free_dma; + if (erased_page) + rawerr = -EIO; + break; + } + } for (n = rw_params.start_sector; n < cwperpage; n++) { if (dma_buffer->result[n].flash_status & (FS_OP_ERR | FS_MPU_ERR)) { diff --git a/drivers/mtd/devices/msm_qpic_nand.h b/drivers/mtd/devices/msm_qpic_nand.h index d6c6d4080e48..b48272a552f1 100644 --- a/drivers/mtd/devices/msm_qpic_nand.h +++ b/drivers/mtd/devices/msm_qpic_nand.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2020 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 @@ -165,7 +165,10 @@ #define RESET_ERASED_DET (1 << AUTO_DETECT_RES) #define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES) #define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC) -#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC) +#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC | SET_N_MAX_ZEROS) +#define N_MAX_ZEROS 2 +#define MAX_ECC_BIT_FLIPS 4 +#define SET_N_MAX_ZEROS (MAX_ECC_BIT_FLIPS << N_MAX_ZEROS) #define MSM_NAND_ERASED_CW_DETECT_STATUS(info) MSM_NAND_REG(info, 0x300EC) #define PAGE_ALL_ERASED 7 @@ -174,6 +177,7 @@ #define CODEWORD_ERASED 4 #define ERASED_PAGE ((1 << PAGE_ALL_ERASED) | (1 << PAGE_ERASED)) #define ERASED_CW ((1 << CODEWORD_ALL_ERASED) | (1 << CODEWORD_ERASED)) +#define NUM_ERRORS 0x1f #define MSM_NAND_CTRL(info) MSM_NAND_REG(info, 0x30F00) #define BAM_MODE_EN 0 -- GitLab From a2fda05a2966ed365a6847396e362f9df7b846e2 Mon Sep 17 00:00:00 2001 From: Akshay Pandit Date: Wed, 17 Jun 2020 00:04:52 +0530 Subject: [PATCH 0851/1055] ipa3: Wait for IPA post init for 1000 msec before return If ipa receives ioctl and post init is not completed, wait for 1000 msec before timing out and returning error. The changes are made specific to msmnile gvm target. Change-Id: Icc63939840af469d1a79960927e6d343a336dcc9 Signed-off-by: Akshay Pandit --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 20 +++++++++++++++++++- drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 3 +++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index e2f6cb039253..be5c72374a45 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -1014,7 +1014,16 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (!ipa3_is_ready()) { IPAERR("IPA not ready, waiting for init completion\n"); - wait_for_completion(&ipa3_ctx->init_completion_obj); + if (ipa3_ctx->manual_fw_load) { + if (!wait_for_completion_timeout( + &ipa3_ctx->init_completion_obj, + msecs_to_jiffies(1000))) { + IPAERR("IPA not ready, return\n"); + return -ETIME; + } + } else { + wait_for_completion(&ipa3_ctx->init_completion_obj); + } } IPA_ACTIVE_CLIENTS_INC_SIMPLE(); @@ -6891,6 +6900,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->uc_act_tbl_total = 0; ipa3_ctx->uc_act_tbl_next_index = 0; ipa3_ctx->ipa_config_is_auto = resource_p->ipa_config_is_auto; + ipa3_ctx->manual_fw_load = resource_p->manual_fw_load; if (ipa3_ctx->secure_debug_check_action == USE_SCM) { if (ipa_is_mem_dump_allowed()) @@ -7556,6 +7566,7 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, ipa_drv_res->ipa_fltrt_not_hashable = false; ipa_drv_res->ipa_endp_delay_wa = false; ipa_drv_res->ipa_config_is_auto = false; + ipa_drv_res->manual_fw_load = false; /* Get IPA HW Version */ result = of_property_read_u32(pdev->dev.of_node, "qcom,ipa-hw-ver", @@ -7965,6 +7976,13 @@ static int get_ipa_dts_configuration(struct platform_device *pdev, IPADBG(": secure-debug-check-action = %d\n", ipa_drv_res->secure_debug_check_action); + ipa_drv_res->manual_fw_load = + of_property_read_bool(pdev->dev.of_node, + "qcom,manual-fw-load"); + IPADBG(": manual-fw-load (%s)\n", + ipa_drv_res->manual_fw_load + ? "True" : "False"); + return 0; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 6dd01a7a843a..a064074ea0df 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1840,6 +1840,7 @@ struct ipa3_app_clock_vote { * @app_vote: holds userspace application clock vote count * IPA context - holds all relevant info about IPA driver and its state * @coal_cmd_pyld: holds the coslescing close frame command payload + * @manual_fw_load: bool,if fw load is done manually */ struct ipa3_context { struct ipa3_char_device_context cdev; @@ -2019,6 +2020,7 @@ struct ipa3_context { struct mutex act_tbl_lock; int uc_act_tbl_total; int uc_act_tbl_next_index; + bool manual_fw_load; }; struct ipa3_plat_drv_res { @@ -2068,6 +2070,7 @@ struct ipa3_plat_drv_res { u32 secure_debug_check_action; bool ipa_mhi_proxy; bool ipa_wan_skb_page; + bool manual_fw_load; }; /** -- GitLab From 4a732119f707fc916acc7cf71e5750908ed4033e Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Mon, 4 May 2020 22:38:03 -0700 Subject: [PATCH 0852/1055] ARM: dts: msm: Add STMMAC node for qcs405 Add STMMAC node for qcs405. Change-Id: I8d2c1dfc081bc547cb38959119486a6f19a96b4a Acked-by: Rahul Kawadgave Signed-off-by: Sunil Paidimarri --- arch/arm64/boot/dts/qcom/qcs405.dtsi | 146 ++++++++++++++++++++ arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi | 17 +++ 2 files changed, 163 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index 67e3ed1fd95f..e405bf8a6226 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -1548,6 +1548,152 @@ < 1401600 MHZ_TO_MBPS( 710, 8) >; }; + mtl_rx_setup: rx-queues-config { + snps,rx-queues-to-use = <4>; + snps,rx-sched-sp; + + queue0 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x0>; + snps,route-up; + snps,priority = <0x1>; + }; + + queue1 { + snps,dcb-algorithm; + snps,map-to-dma-channel = <0x1>; + snps,route-ptp; + }; + + queue2 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x2>; + snps,route-avcp; + }; + + queue3 { + snps,avb-algorithm; + snps,map-to-dma-channel = <0x3>; + snps,priority = <0xC>; + }; + }; + + mtl_tx_setup: tx-queues-config { + snps,tx-queues-to-use = <5>; + snps,tx-sched-sp; + queue0 { + snps,dcb-algorithm; + }; + + queue1 { + snps,dcb-algorithm; + }; + + queue2 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3E800>; + snps,low_credit = <0xFFC18000>; + }; + + queue3 { + snps,avb-algorithm; + snps,send_slope = <0x1000>; + snps,idle_slope = <0x1000>; + snps,high_credit = <0x3E800>; + snps,low_credit = <0xFFC18000>; + }; + }; + + ethqos_hw: qcom,ethernet@00020000 { + compatible = "qcom,stmmac-ethqos"; + reg = <0x07A80000 0x10000>, + <0x7A96000 0x100>; + qcom,arm-smmu; + reg-names = "stmmaceth", "rgmii"; + dma-bit-mask = <32>; + emac-core-version = <0x20030000>; + interrupts-extended = <&wakegic 0 56 4>, <&wakegic 0 55 4>, + <&tlmm 61 2>, <&wakegic 0 300 4>, + <&wakegic 0 301 4>, <&wakegic 0 302 4>, + <&wakegic 0 303 4>, <&wakegic 0 304 4>, + <&wakegic 0 305 4>, <&wakegic 0 306 4>, + <&wakegic 0 307 4>, <&wakegic 0 308 4>; + interrupt-names = "macirq", "eth_lpi", + "phy-intr", "tx-ch0-intr", + "tx-ch1-intr", "tx-ch2-intr", + "tx-ch3-intr", "tx-ch4-intr", + "rx-ch0-intr", "rx-ch1-intr", + "rx-ch2-intr", "rx-ch3-intr"; + qcom,msm-bus,name = "emac"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <98 512 0 0>, <1 781 0 0>, /* No vote */ + <98 512 2500 0>, <1 781 0 40000>, /* 10Mbps vote */ + <98 512 25000 0>, <1 781 0 40000>, /* 100Mbps vote */ + <98 512 250000 0>, <1 781 0 40000>; /* 1000Mbps vote */ + qcom,bus-vector-names = "0", "10", "100", "1000"; + snps,tso; + snps,pbl = <32>; + mac-address = [00 55 7B B5 7D f7]; + clocks = <&clock_gcc GCC_ETH_AXI_CLK>, + <&clock_gcc GCC_ETH_SLAVE_AHB_CLK>, + <&clock_gcc GCC_ETH_PTP_CLK>, + <&clock_gcc GCC_ETH_RGMII_CLK>; + clock-names = "stmmaceth", "pclk", "ptp_ref", "rgmii"; + snps,ptp-ref-clk-rate = <230400000>; + snps,ptp-req-clk-rate = <57600000>; + snps,reset-gpio = <&tlmm 60 GPIO_ACTIVE_HIGH>; + qcom,phy-intr-redirect = <&tlmm 61 GPIO_ACTIVE_LOW>; + /*gdsc_emac-supply = <&emac_gdsc>;*/ + rx-fifo-depth = <16384>; + tx-fifo-depth = <20480>; + snps,mtl-rx-config = <&mtl_rx_setup>; + snps,mtl-tx-config = <&mtl_tx_setup>; + + pinctrl-names = "dev-emac-mdc", "dev-emac-mdio", + "dev-emac-rgmii_txd0_state", "dev-emac-rgmii_txd1_state", + "dev-emac-rgmii_txd2_state", "dev-emac-rgmii_txd3_state", + "dev-emac-rgmii_txc_state", "dev-emac-rgmii_tx_ctl_state", + "dev-emac-rgmii_rxd0_state", "dev-emac-rgmii_rxd1_state", + "dev-emac-rgmii_rxd2_state", "dev-emac-rgmii_rxd3_state", + "dev-emac-rgmii_rxc_state", "dev-emac-rgmii_rx_ctl_state", + "dev-emac-phy_intr"; + + pinctrl-0 = <&emac_mdc>; + pinctrl-1 = <&emac_mdio>; + pinctrl-2 = <&emac_rgmii_txd0>; + pinctrl-3 = <&emac_rgmii_txd1>; + pinctrl-4 = <&emac_rgmii_txd2>; + pinctrl-5 = <&emac_rgmii_txd3>; + pinctrl-6 = <&emac_rgmii_txc>; + pinctrl-7 = <&emac_rgmii_tx_ctl>; + pinctrl-8 = <&emac_rgmii_rxd0>; + pinctrl-9 = <&emac_rgmii_rxd1>; + pinctrl-10 = <&emac_rgmii_rxd2>; + pinctrl-11 = <&emac_rgmii_rxd3>; + pinctrl-12 = <&emac_rgmii_rxc>; + pinctrl-13 = <&emac_rgmii_rx_ctl>; + pinctrl-14 = <&emac_phy_intr>; + + snps,reset-active-low; + snps,reset-delays-us = <0 10000 100000>; + phy-mode = "rgmii"; + + io-macro-info { + io-macro-bypass-mode = <0>; + io-interface = "rgmii"; + }; + + ethqos_emb_smmu: ethqos_emb_smmu { + compatible = "qcom,emac-smmu-embedded"; + iommus = <&apps_smmu 0x1400 0x0>; + qcom,iova-mapping = <0x80000000 0x40000000>; + }; + }; + emac_hw: qcom,emac@07A80000 { compatible = "qcom,emac-dwc-eqos"; reg = <0x07A80000 0x10000>, diff --git a/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi b/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi index accae59b393a..304357a3195e 100644 --- a/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi +++ b/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi @@ -192,6 +192,23 @@ extcon = <&usb2_extcon>; }; +ðqos_hw { + status = "okay"; + vreg_emac_phy-supply = <&vreg_emac_phy>; + vreg_rgmii_io_pads-supply = <&vreg_rgmii_io_pads>; + rxc-skew-ps = <0>; + + pinctrl-names = "dev-emac-mdc", "dev-emac-mdio", + "dev-emac-rgmii_txd0_state", "dev-emac-rgmii_txd1_state", + "dev-emac-rgmii_txd2_state", "dev-emac-rgmii_txd3_state", + "dev-emac-rgmii_txc_state", "dev-emac-rgmii_tx_ctl_state", + "dev-emac-rgmii_rxd0_state", "dev-emac-rgmii_rxd1_state", + "dev-emac-rgmii_rxd2_state", "dev-emac-rgmii_rxd3_state", + "dev-emac-rgmii_rxc_state", "dev-emac-rgmii_rx_ctl_state", + "dev-emac-phy_intr", "dev-emac-phy_reset_state"; + pinctrl-15 = <&emac_phy_reset_state>; +}; + &emac_hw { status = "okay"; vreg_emac_phy-supply = <&vreg_emac_phy>; -- GitLab From 968b0dcd3ec09af5e0d4d2ad7d45c9a4febfb29d Mon Sep 17 00:00:00 2001 From: raghavendra ambadas Date: Mon, 9 Mar 2020 18:43:13 +0530 Subject: [PATCH 0853/1055] ARM: DTS: msm: Update DP PLL string for SDM660 Update the dp pll compatible string for SDM660 to allow SDM660 specific PLL changes. Change-Id: I73b2e58eb7eeb70a9c3d8db9317d26aa4e8c1f03 Signed-off-by: Nirmal Abraham Signed-off-by: Raghavendra Ambadas --- arch/arm64/boot/dts/qcom/sdm660-mdss-pll.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm660-mdss-pll.dtsi b/arch/arm64/boot/dts/qcom/sdm660-mdss-pll.dtsi index 82194721a419..959971594e89 100644 --- a/arch/arm64/boot/dts/qcom/sdm660-mdss-pll.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm660-mdss-pll.dtsi @@ -84,7 +84,7 @@ }; mdss_dp_pll: qcom,mdss_dp_pll@c011000 { - compatible = "qcom,mdss_dp_pll_14nm"; + compatible = "qcom,mdss_dp_pll_sdm660"; status = "ok"; label = "MDSS DP PLL"; cell-index = <0>; -- GitLab From 57bc3d667e8f10e0e885e226dfa08e50f01c9780 Mon Sep 17 00:00:00 2001 From: Jasleen Kalsi Date: Sat, 2 May 2020 01:22:55 +0530 Subject: [PATCH 0854/1055] taskstats: extended taskstats2 with acct fields Add basic accounting stats in taskstats2 struct Change-Id: Ieb5aa751381f889628eba143db3988a56ef0f096 Signed-off-by: Jasleen Kalsi --- include/uapi/linux/taskstats.h | 16 +++++++++++++- kernel/taskstats.c | 38 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/taskstats.h b/include/uapi/linux/taskstats.h index 125b5a9488a7..ac1e1881ac89 100644 --- a/include/uapi/linux/taskstats.h +++ b/include/uapi/linux/taskstats.h @@ -35,7 +35,7 @@ #define TASKSTATS_VERSION 9 -#define TASKSTATS2_VERSION 1 +#define TASKSTATS2_VERSION 2 #define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN * in linux/sched.h */ @@ -181,6 +181,20 @@ struct taskstats2 { __u64 shmem_rss; /* KB */ __u64 unreclaimable; /* KB */ /* version 1 ends here */ + + /* version 2 begins here */ + __u64 utime; /* User CPU time [usec] */ + __u64 stime; /* System CPU time [usec] */ + __u64 cutime; /* Cumulative User CPU time [usec] */ + __u64 cstime; /* Cumulative System CPU time [usec] */ + + __u32 uid __attribute__((aligned(8))); + /* User ID */ + __u32 ppid; /* Parent process ID */ + char name[TS_COMM_LEN]; /* Command name */ + char state[TS_COMM_LEN]; /* Process state */ + /* version 2 ends here*/ + }; /* diff --git a/kernel/taskstats.c b/kernel/taskstats.c index 30750014c33b..14460de10a19 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -654,6 +654,13 @@ static int taskstats2_cmd_attr_pid(struct genl_info *info) size_t size; u32 pid; int rc; + u64 utime, stime; + const struct cred *tcred; +#ifdef CONFIG_CPUSETS + struct cgroup_subsys_state *css; +#endif //CONFIG_CPUSETS + unsigned long flags; + struct signal_struct *sig; size = nla_total_size_64bit(sizeof(struct taskstats2)); @@ -695,6 +702,37 @@ static int taskstats2_cmd_attr_pid(struct genl_info *info) #undef K task_unlock(p); } + + /* version 2 fields begin here */ + task_cputime(tsk, &utime, &stime); + stats->utime = div_u64(utime, NSEC_PER_USEC); + stats->stime = div_u64(stime, NSEC_PER_USEC); + + if (lock_task_sighand(tsk, &flags)) { + sig = tsk->signal; + stats->cutime = sig->cutime; + stats->cstime = sig->cstime; + unlock_task_sighand(tsk, &flags); + } + + rcu_read_lock(); + tcred = __task_cred(tsk); + stats->uid = from_kuid_munged(current_user_ns(), tcred->uid); + stats->ppid = pid_alive(tsk) ? + task_tgid_nr_ns(rcu_dereference(tsk->real_parent), + task_active_pid_ns(current)) : 0; + rcu_read_unlock(); + + strlcpy(stats->name, tsk->comm, sizeof(stats->name)); + +#ifdef CONFIG_CPUSETS + css = task_get_css(tsk, cpuset_cgrp_id); + cgroup_path_ns(css->cgroup, stats->state, sizeof(stats->state), + current->nsproxy->cgroup_ns); + css_put(css); +#endif //CONFIG_CPUSETS + /* version 2 fields end here */ + put_task_struct(tsk); return send_reply(rep_skb, info); -- GitLab From 8c48f981f71a0d0c7ba328a16f042e421d01bf39 Mon Sep 17 00:00:00 2001 From: Nitesh Gupta Date: Sun, 14 Jun 2020 16:51:02 +0530 Subject: [PATCH 0855/1055] ARM: dts: msm: Add PCIe reset support for QCS405 BCR reset will do the group or block reset associated to the clock domain. Add PCIe Block reset and PHY reset support for QCS405. Change-Id: I770d3c9cc613c5d452f4bb082c21e955287326a5 Signed-off-by: Nitesh Gupta --- arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi b/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi index f0dcd69670c9..d6d5dde8eaa0 100644 --- a/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405-pcie.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020, 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,8 +116,14 @@ <0>, <0>, <0>, <0>; clock-output-names = "pcie_0_pipe_clk"; - resets = <&clock_gcc GCC_PCIEPHY_0_PHY_BCR>; - reset-names = "pcie_0_phy_reset"; + + resets = <&clock_gcc GCC_PCIEPHY_0_PHY_BCR>, + <&clock_gcc GCC_PCIE_0_BCR>, + <&clock_gcc GCC_PCIE_0_PHY_BCR>; + + reset-names = "pcie_0_phy_reset", + "pcie_0_core_reset", + "pcie_phy_reset"; pcie_rc0: pcie_rc0 { #address-cells = <5>; -- GitLab From 781f8014536510d29b3cfc824f282a1cafbab5a7 Mon Sep 17 00:00:00 2001 From: Nitesh Gupta Date: Wed, 17 Jun 2020 22:23:47 +0530 Subject: [PATCH 0856/1055] ARM: dts: msm: Enable Perst Based PCIe Enumeration for SA515M Add perst_enum property to enable perst based enumeration of PCIe on SA515M. Change-Id: I386c59c7ae1cbdd7ed523a6429f99a41aa970477 Signed-off-by: Nitesh Gupta --- arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts index 076abf9d0d78..bb1f2ae1b5f2 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts +++ b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts @@ -54,6 +54,7 @@ &pcie_ep { status = "ok"; + qcom,pcie-perst-enum; }; &mhi_device { -- GitLab From 44f1453b659595517fa4b0788f3e813d6fba753d Mon Sep 17 00:00:00 2001 From: Manohar Vavilapalli Date: Wed, 17 Jun 2020 11:28:28 +0530 Subject: [PATCH 0857/1055] coresight: perf: Add NULL check before using pointer sink Add NULL check to avoid potential NULL pointer dereference. Change-Id: I6e63a013f599393f9703cd9a493730181f4a68de Signed-off-by: Manohar Vavilapalli --- drivers/hwtracing/coresight/coresight-etm-perf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 3ba6d904ae80..03cb7721e13a 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -145,6 +145,9 @@ static void free_sink_buffer(struct etm_event_data *event_data) cpu = cpumask_first(mask); sink = coresight_get_sink(etm_event_cpu_path(event_data, cpu)); + if (!sink) + return; + sink_ops(sink)->free_buffer(event_data->snk_config); } -- GitLab From ff5ce2f85e356e4b8eada0516bb43453da03d98d Mon Sep 17 00:00:00 2001 From: Manohar Vavilapalli Date: Wed, 17 Jun 2020 11:40:02 +0530 Subject: [PATCH 0858/1055] coresight-tmc: Add NULL check before using pointer 'etr_buf->ops' Add NULL check to avoid potential NULL pointer dereference. Change-Id: Id3e6619a308b2afe2dda54255d5fb89db14b0b87 Signed-off-by: Manohar Vavilapalli --- drivers/hwtracing/coresight/coresight-tmc-etr.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 3baf2c8cf0dc..745fcaad4348 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -883,7 +883,9 @@ static struct etr_buf *tmc_alloc_etr_buf(struct tmc_drvdata *drvdata, static void tmc_free_etr_buf(struct etr_buf *etr_buf) { - WARN_ON(!etr_buf->ops || !etr_buf->ops->free); + if (WARN_ON(!etr_buf->ops || !etr_buf->ops->free)) + return; + etr_buf->ops->free(etr_buf); kfree(etr_buf); } @@ -947,7 +949,8 @@ static void tmc_sync_etr_buf(struct tmc_drvdata *drvdata) etr_buf->full = status & TMC_STS_FULL; - WARN_ON(!etr_buf->ops || !etr_buf->ops->sync); + if (WARN_ON(!etr_buf->ops || !etr_buf->ops->sync)) + return; etr_buf->ops->sync(etr_buf, rrp, rwp); } -- GitLab From c653a9c150d59ab6b060291844e98e636a8d2cde Mon Sep 17 00:00:00 2001 From: Manu Gautam Date: Thu, 28 May 2020 16:03:20 +0530 Subject: [PATCH 0859/1055] mhi: core: add mhi_device_get_sync_atomic() to wait until M0 There is a possibility of client driver's dev_wake request as part mhi_device_get() racing with M1 state transition event processing. This can result in a scenario where client finds MHI state as M0 after mhi_device_get() returns only to be changed later as M1 event processing is still pending on different CPU core. It causes M0 -> M2 -> M0 state transition after mhi_device_get() has already returned. This isn't expected by client and currently treats that as fatal error. Also, as per MHI spec host must allow M1 -> M2 transition for device and it shouldn't abort that. However, clients can ignore that transition as device is expected to immediately move from M2 to M0 without entering deep sleep state. Hence, it must be safe to access their MMIO. To simplify this logic, introduce mhi_device_get_sync_atomic() function that can be used by clients to achieve the same and once it returns success they don't need to have any explicit MHI state checks. Change-Id: I0b4a1ad723a0444ee2402bf171fc5ffc46afcdce Signed-off-by: Manu Gautam --- drivers/bus/mhi/core/mhi_internal.h | 2 + drivers/bus/mhi/core/mhi_pm.c | 108 +++++++++++++++++++++------- include/linux/mhi.h | 24 +++++++ 3 files changed, 109 insertions(+), 25 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_internal.h b/drivers/bus/mhi/core/mhi_internal.h index 1d3261855a81..3efe2ef28298 100644 --- a/drivers/bus/mhi/core/mhi_internal.h +++ b/drivers/bus/mhi/core/mhi_internal.h @@ -752,6 +752,8 @@ struct mhi_bus { /* default MHI timeout */ #define MHI_TIMEOUT_MS (1000) +#define MHI_FORCE_WAKE_DELAY_US (100) + extern struct mhi_bus mhi_bus; struct mhi_controller *find_mhi_controller_by_name(const char *name); diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index 1ae24eba7769..550d0effa98d 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -404,35 +404,42 @@ void mhi_pm_m1_transition(struct mhi_controller *mhi_cntrl) enum MHI_PM_STATE state; write_lock_irq(&mhi_cntrl->pm_lock); + /* Just check if we are racing with device_wake assertion */ + if (atomic_read(&mhi_cntrl->dev_wake)) + MHI_VERB("M2 transition request post dev_wake:%d\n", + atomic_read(&mhi_cntrl->dev_wake)); + /* if it fails, means we transition to M3 */ state = mhi_tryset_pm_state(mhi_cntrl, MHI_PM_M2); - if (state == MHI_PM_M2) { - MHI_VERB("Entered M2 State\n"); - mhi_set_mhi_state(mhi_cntrl, MHI_STATE_M2); - mhi_cntrl->dev_state = MHI_STATE_M2; - mhi_cntrl->M2++; - - write_unlock_irq(&mhi_cntrl->pm_lock); - wake_up_all(&mhi_cntrl->state_event); - - /* transfer pending, exit M2 immediately */ - if (unlikely(atomic_read(&mhi_cntrl->pending_pkts) || - atomic_read(&mhi_cntrl->dev_wake))) { - MHI_VERB( - "Exiting M2 Immediately, pending_pkts:%d dev_wake:%d\n", - atomic_read(&mhi_cntrl->pending_pkts), - atomic_read(&mhi_cntrl->dev_wake)); - read_lock_bh(&mhi_cntrl->pm_lock); - mhi_cntrl->wake_get(mhi_cntrl, true); - mhi_cntrl->wake_put(mhi_cntrl, true); - read_unlock_bh(&mhi_cntrl->pm_lock); - } else { - mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, - MHI_CB_IDLE); - } - } else { + if (state != MHI_PM_M2) { + /* Nothing to be done, handle M3 transition later */ write_unlock_irq(&mhi_cntrl->pm_lock); + return; } + + MHI_VERB("Entered M2 State\n"); + mhi_set_mhi_state(mhi_cntrl, MHI_STATE_M2); + mhi_cntrl->dev_state = MHI_STATE_M2; + mhi_cntrl->M2++; + + write_unlock_irq(&mhi_cntrl->pm_lock); + wake_up_all(&mhi_cntrl->state_event); + + /* transfer pending, exit M2 immediately */ + if (unlikely(atomic_read(&mhi_cntrl->pending_pkts) || + atomic_read(&mhi_cntrl->dev_wake))) { + MHI_VERB( + "Exiting M2 Immediately, pending_pkts:%d dev_wake:%d\n", + atomic_read(&mhi_cntrl->pending_pkts), + atomic_read(&mhi_cntrl->dev_wake)); + read_lock_bh(&mhi_cntrl->pm_lock); + mhi_cntrl->wake_get(mhi_cntrl, true); + mhi_cntrl->wake_put(mhi_cntrl, true); + read_unlock_bh(&mhi_cntrl->pm_lock); + return; + } + + mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, MHI_CB_IDLE); } int mhi_pm_m3_transition(struct mhi_controller *mhi_cntrl) @@ -1580,6 +1587,57 @@ int mhi_device_get_sync(struct mhi_device *mhi_dev, int vote) } EXPORT_SYMBOL(mhi_device_get_sync); +int mhi_device_get_sync_atomic(struct mhi_device *mhi_dev, int timeout_us) +{ + struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; + + read_lock_bh(&mhi_cntrl->pm_lock); + if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { + read_unlock_bh(&mhi_cntrl->pm_lock); + return -EIO; + } + + mhi_cntrl->wake_get(mhi_cntrl, true); + read_unlock_bh(&mhi_cntrl->pm_lock); + + atomic_inc(&mhi_dev->dev_vote); + pm_wakeup_hard_event(&mhi_cntrl->mhi_dev->dev); + mhi_cntrl->runtime_get(mhi_cntrl, mhi_cntrl->priv_data); + + /* Return if client doesn't want us to wait */ + if (!timeout_us) { + if (mhi_cntrl->pm_state != MHI_PM_M0) + MHI_ERR("Return without waiting for M0\n"); + + mhi_cntrl->runtime_put(mhi_cntrl, mhi_cntrl->priv_data); + return 0; + } + + while (mhi_cntrl->pm_state != MHI_PM_M0 && + !MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) && + timeout_us > 0) { + udelay(MHI_FORCE_WAKE_DELAY_US); + timeout_us -= MHI_FORCE_WAKE_DELAY_US; + } + + if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) || timeout_us <= 0) { + MHI_ERR("Did not enter M0 state, cur_state:%s pm_state:%s\n", + TO_MHI_STATE_STR(mhi_cntrl->dev_state), + to_mhi_pm_state_str(mhi_cntrl->pm_state)); + read_lock_bh(&mhi_cntrl->pm_lock); + mhi_cntrl->wake_put(mhi_cntrl, false); + read_unlock_bh(&mhi_cntrl->pm_lock); + atomic_dec(&mhi_dev->dev_vote); + mhi_cntrl->runtime_put(mhi_cntrl, mhi_cntrl->priv_data); + return -ETIMEDOUT; + } + + mhi_cntrl->runtime_put(mhi_cntrl, mhi_cntrl->priv_data); + + return 0; +} +EXPORT_SYMBOL(mhi_device_get_sync_atomic); + void mhi_device_put(struct mhi_device *mhi_dev, int vote) { struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 5460fc206d7e..9c422c96b718 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -610,6 +610,30 @@ void mhi_device_get(struct mhi_device *mhi_dev, int vote); */ int mhi_device_get_sync(struct mhi_device *mhi_dev, int vote); +/** + * mhi_device_get_sync_atomic - Asserts device_wait and moves device to M0 + * @mhi_dev: Device associated with the channels + * @timeout_us: timeout, in micro-seconds + * + * The device_wake is asserted to keep device in M0 or bring it to M0. + * If device is not in M0 state, then this function will wait for device to + * move to M0, until @timeout_us elapses. + * However, if device's M1 state-change event races with this function + * then there is a possiblity of device moving from M0 to M2 and back + * to M0. That can't be avoided as host must transition device from M1 to M2 + * as per the spec. + * Clients can ignore that transition after this function returns as the device + * is expected to immediately move from M2 to M0 as wake is asserted and + * wouldn't enter low power state. + * + * Returns: + * 0 if operation was successful (however, M0 -> M2 -> M0 is possible later) as + * mentioned above. + * -ETIMEDOUT is device faled to move to M0 before @timeout_us elapsed + * -EIO if the MHI state is one of the ERROR states. + */ +int mhi_device_get_sync_atomic(struct mhi_device *mhi_dev, int timeout_us); + /** * mhi_device_put - re-enable low power modes * @mhi_dev: Device associated with the channels -- GitLab From e9c7f831eadbcb4e8938d332f0961ebf34d19289 Mon Sep 17 00:00:00 2001 From: Ping Jiang Date: Wed, 17 Jun 2020 15:46:05 +0800 Subject: [PATCH 0860/1055] char: virtio_fastrpc: Add profile mode support When profile mode is enabled by client, performance statistic will be collected for each invoke call. Time is in nanosecond unit. Change-Id: I0ebd3efd148d671941ee5f59c3083a2f700e9c09 Signed-off-by: Ping Jiang --- drivers/char/virtio_fastrpc.c | 197 ++++++++++++++++++++++++++++++++-- 1 file changed, 191 insertions(+), 6 deletions(-) diff --git a/drivers/char/virtio_fastrpc.c b/drivers/char/virtio_fastrpc.c index 7a6de1fc4592..845acd8c1d6c 100644 --- a/drivers/char/virtio_fastrpc.c +++ b/drivers/char/virtio_fastrpc.c @@ -61,7 +61,6 @@ #define DEBUGFS_SIZE 3072 #define PID_SIZE 10 #define UL_SIZE 25 -#define FASTRPC_STATIC_HANDLE_KERNEL 1 #define VIRTIO_FASTRPC_CMD_OPEN 1 #define VIRTIO_FASTRPC_CMD_CLOSE 2 @@ -98,6 +97,33 @@ memmove((dst), (src), (size));\ } while (0) +#define PERF_KEYS \ + "count:flush:map:copy:rpmsg:getargs:putargs:invalidate:invoke:tid:ptr" +#define FASTRPC_STATIC_HANDLE_KERNEL 1 +#define FASTRPC_STATIC_HANDLE_LISTENER 3 +#define FASTRPC_STATIC_HANDLE_MAX 20 + +#define PERF_END (void)0 + +#define PERF(enb, cnt, ff) \ + {\ + struct timespec startT = {0};\ + int64_t *counter = cnt;\ + if (enb && counter) {\ + getnstimeofday(&startT);\ + } \ + ff ;\ + if (enb && counter) {\ + *counter += getnstimediff(&startT);\ + } \ + } + +#define GET_COUNTER(perf_ptr, offset) \ + (perf_ptr != NULL ?\ + (((offset >= 0) && (offset < PERF_KEY_MAX)) ?\ + (int64_t *)(perf_ptr + offset)\ + : (int64_t *)NULL) : (int64_t *)NULL) + struct virt_msg_hdr { u32 pid; /* GVM pid */ u32 tid; /* GVM tid */ @@ -181,9 +207,37 @@ struct fastrpc_apps { struct virt_fastrpc_msg *msgtable[FASTRPC_MSG_MAX]; }; +enum fastrpc_perfkeys { + PERF_COUNT = 0, + PERF_FLUSH = 1, + PERF_MAP = 2, + PERF_COPY = 3, + PERF_LINK = 4, + PERF_GETARGS = 5, + PERF_PUTARGS = 6, + PERF_INVARGS = 7, + PERF_INVOKE = 8, + PERF_KEY_MAX = 9, +}; + +struct fastrpc_perf { + int64_t count; + int64_t flush; + int64_t map; + int64_t copy; + int64_t link; + int64_t getargs; + int64_t putargs; + int64_t invargs; + int64_t invoke; + int64_t tid; + struct hlist_node hn; +}; + struct fastrpc_file { spinlock_t hlock; struct hlist_head maps; + struct hlist_head perf; struct hlist_head remote_bufs; uint32_t mode; uint32_t profile; @@ -195,6 +249,7 @@ struct fastrpc_file { int dsp_proc_init; struct fastrpc_apps *apps; struct dentry *debugfs_file; + struct mutex perf_mutex; struct mutex map_mutex; /* Identifies the device (MINOR_NUM_DEV / MINOR_NUM_SECURE_DEV) */ int dev_minor; @@ -242,6 +297,45 @@ static inline int64_t getnstimediff(struct timespec *start) return ns; } +static inline int64_t *getperfcounter(struct fastrpc_file *fl, int key) +{ + int err = 0; + int64_t *val = NULL; + struct fastrpc_perf *perf = NULL, *fperf = NULL; + struct hlist_node *n = NULL; + + VERIFY(err, !IS_ERR_OR_NULL(fl)); + if (err) + goto bail; + + mutex_lock(&fl->perf_mutex); + hlist_for_each_entry_safe(perf, n, &fl->perf, hn) { + if (perf->tid == current->pid) { + fperf = perf; + break; + } + } + + if (IS_ERR_OR_NULL(fperf)) { + fperf = kzalloc(sizeof(*fperf), GFP_KERNEL); + + VERIFY(err, !IS_ERR_OR_NULL(fperf)); + if (err) { + mutex_unlock(&fl->perf_mutex); + kfree(fperf); + goto bail; + } + + fperf->tid = current->pid; + hlist_add_head(&fperf->hn, &fl->perf); + } + + val = ((int64_t *)fperf) + key; + mutex_unlock(&fl->perf_mutex); +bail: + return val; +} + static void *get_a_tx_buf(void) { struct fastrpc_apps *me = &gfa; @@ -486,6 +580,11 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, struct fastrpc_mmap **maps; size_t copylen = 0, size = 0; char *payload; + struct timespec invoket = {0}; + int64_t *perf_counter = getperfcounter(fl, PERF_COUNT); + + if (fl->profile) + getnstimeofday(&invoket); bufs = REMOTE_SCALARS_LENGTH(invoke->sc); size = bufs * sizeof(*lpra) + bufs * sizeof(*fds) @@ -508,6 +607,7 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, fds = NULL; } + PERF(fl->profile, GET_COUNTER(perf_counter, PERF_MAP), /* calculate len required for copying */ for (i = 0; i < inbufs + outbufs; i++) { size_t len = lpra[i].buf.len; @@ -530,6 +630,7 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, if (i < inbufs) outbufs_offset += len; } + PERF_END); size = bufs * sizeof(*rpra) + copylen + sizeof(*vmsg); msg = virt_alloc_msg(size); if (!msg) @@ -551,6 +652,7 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, rpra = (struct virt_fastrpc_buf *)vmsg->pra; payload = (char *)&rpra[bufs]; + PERF(fl->profile, GET_COUNTER(perf_counter, PERF_COPY), for (i = 0; i < inbufs + outbufs; i++) { size_t len = lpra[i].buf.len; struct sg_table *table; @@ -582,7 +684,16 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, payload += len; } } + PERF_END); + if (fl->profile) { + int64_t *count = GET_COUNTER(perf_counter, PERF_GETARGS); + + if (count) + *count += getnstimediff(&invoket); + } + + PERF(fl->profile, GET_COUNTER(perf_counter, PERF_LINK), sg_init_one(sg, vmsg, size); mutex_lock(&me->lock); @@ -594,6 +705,7 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, virtqueue_kick(me->svq); mutex_unlock(&me->lock); + PERF_END); wait_for_completion(&msg->work); @@ -605,6 +717,7 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, rpra = (struct virt_fastrpc_buf *)rsp->pra; payload = (char *)&rpra[bufs] + outbufs_offset; + PERF(fl->profile, GET_COUNTER(perf_counter, PERF_PUTARGS), for (i = inbufs; i < inbufs + outbufs; i++) { if (!maps[i]) { K_COPY_TO_USER(err, kernel, lpra[i].buf.pv, @@ -619,6 +732,7 @@ static int virt_fastrpc_invoke(struct fastrpc_file *fl, uint32_t kernel, } payload += rpra[i].len; } + PERF_END); bail: if (rsp) { sg_init_one(sg, rsp, me->buf_size); @@ -651,8 +765,11 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, int domain = fl->domain; int handles, err = 0; struct timespec invoket = {0}; + int64_t *perf_counter = getperfcounter(fl, PERF_COUNT); + + if (fl->profile) + getnstimeofday(&invoket); - getnstimeofday(&invoket); if (!kernel) { VERIFY(err, invoke->handle != FASTRPC_STATIC_HANDLE_KERNEL); if (err) { @@ -679,6 +796,20 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, } err = virt_fastrpc_invoke(fl, kernel, inv); + if (fl->profile) { + if (invoke->handle != FASTRPC_STATIC_HANDLE_LISTENER) { + int64_t *count = GET_COUNTER(perf_counter, PERF_INVOKE); + + if (count) + *count += getnstimediff(&invoket); + } + if (invoke->handle > FASTRPC_STATIC_HANDLE_MAX) { + int64_t *count = GET_COUNTER(perf_counter, PERF_COUNT); + + if (count) + *count = *count + 1; + } + } bail: return err; } @@ -703,6 +834,8 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, if (fl) { len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, "\n%s %d\n", " CHANNEL =", fl->domain); + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %9s %d\n", "profile", ":", fl->profile); } if (len > DEBUGFS_SIZE) @@ -931,6 +1064,7 @@ static int fastrpc_open(struct inode *inode, struct file *filp) spin_lock_init(&fl->hlock); INIT_HLIST_HEAD(&fl->maps); + INIT_HLIST_HEAD(&fl->perf); INIT_HLIST_HEAD(&fl->remote_bufs); fl->tgid = current->tgid; fl->apps = me; @@ -943,12 +1077,14 @@ static int fastrpc_open(struct inode *inode, struct file *filp) fl->dsp_proc_init = 0; filp->private_data = fl; mutex_init(&fl->map_mutex); + mutex_init(&fl->perf_mutex); return 0; } static int fastrpc_file_free(struct fastrpc_file *fl) { struct fastrpc_mmap *map = NULL, *lmap = NULL; + struct fastrpc_perf *perf = NULL, *fperf = NULL; if (!fl) return 0; @@ -975,6 +1111,21 @@ static int fastrpc_file_free(struct fastrpc_file *fl) } while (lmap); mutex_unlock(&fl->map_mutex); + mutex_lock(&fl->perf_mutex); + do { + struct hlist_node *pn = NULL; + + fperf = NULL; + hlist_for_each_entry_safe(perf, pn, &fl->perf, hn) { + hlist_del_init(&perf->hn); + fperf = perf; + break; + } + kfree(fperf); + } while (fperf); + mutex_unlock(&fl->perf_mutex); + mutex_destroy(&fl->perf_mutex); + fastrpc_remote_buf_list_free(fl); mutex_destroy(&fl->map_mutex); kfree(fl); @@ -1736,8 +1887,7 @@ static long fastrpc_ioctl(struct file *file, unsigned int ioctl_num, fl->mode = (uint32_t)ioctl_param; break; case FASTRPC_MODE_PROFILE: - err = -ENOTTY; - dev_err(me->dev, "profile mode is not supported\n"); + fl->profile = (uint32_t)ioctl_param; break; case FASTRPC_MODE_SESSION: err = -ENOTTY; @@ -1749,8 +1899,43 @@ static long fastrpc_ioctl(struct file *file, unsigned int ioctl_num, } break; case FASTRPC_IOCTL_GETPERF: - err = -ENOTTY; - dev_err(me->dev, "get perf is not supported\n"); + K_COPY_FROM_USER(err, 0, &p.perf, + param, sizeof(p.perf)); + if (err) + goto bail; + p.perf.numkeys = sizeof(struct fastrpc_perf)/sizeof(int64_t); + if (p.perf.keys) { + char *keys = PERF_KEYS; + + K_COPY_TO_USER(err, 0, (void *)p.perf.keys, + keys, strlen(keys)+1); + if (err) + goto bail; + } + if (p.perf.data) { + struct fastrpc_perf *perf = NULL, *fperf = NULL; + struct hlist_node *n = NULL; + + mutex_lock(&fl->perf_mutex); + hlist_for_each_entry_safe(perf, n, &fl->perf, hn) { + if (perf->tid == current->pid) { + fperf = perf; + break; + } + } + + mutex_unlock(&fl->perf_mutex); + + if (fperf) { + K_COPY_TO_USER(err, 0, + (void *)p.perf.data, fperf, + sizeof(*fperf) - + sizeof(struct hlist_node)); + } + } + K_COPY_TO_USER(err, 0, param, &p.perf, sizeof(p.perf)); + if (err) + goto bail; break; case FASTRPC_IOCTL_CONTROL: K_COPY_FROM_USER(err, 0, &p.cp, param, -- GitLab From cfddd39f1a0fabe98e59fc291db8baab3b0b9433 Mon Sep 17 00:00:00 2001 From: Cong Tang Date: Thu, 18 Jun 2020 15:10:31 +0800 Subject: [PATCH 0861/1055] Documentation: Add documentation for audio drivers Updated for GPR,Gecko core, Gecko platform, Audio packet. PRM and Automotive machine drivers. Change-Id: Id10c02c36b6f79cef784fa7a314e69fc1fec4b5a Signed-off-by: Cong Tang --- .../bindings/sound/qcom-audio-dev.txt | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 715855b3fa5a..e7fef3bdc4fa 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -349,6 +349,49 @@ Optional properties: This child device is added after lpass is up to invoke deferred probe devices. +* gpr + +Required properties: + + - compatible : "qcom,gpr" + This device is added to represent GPR module. + + - qcom,glink-channels: Indicates glink channel to be used. + - qcom,intents: Indicates the number of intents to be allocated. + - reg: This value provides the subsytem ID to be communicated with. + +* gecko-core-platform + +Required properties: + + - compatible : "qcom,gecko-core-platform" + This device is added to represent Gecko platform driver module. + +* gecko_core + +Required properties: + + - compatible : "qcom,gecko_core" + This device is added to represent Gecko core driver module. + - reg: Represents the service to be communicated with. + +* audio-pkt + +Required properties: + + - compatible : "qcom,audio-pkt" + This device is added to represent Audio packet driver module. + - qcom,audiopkt-ch-name: Glink channel name to be used. + - reg: Represents the service to be communicated with. + +* q6prm + +Required properties: + + - compatible : "qcom,q6prm" + This device is added to represent Q6 PRM driver module. + - reg: Represents the service to be communicated with. + * msm-ocmem-audio Required properties: @@ -1880,6 +1923,124 @@ Example: qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>; }; +* SA8155 Gecko ASoC Machine driver + +Required properties: +- compatible : "qcom,sa8155-gecko-asoc-snd-adp-star" for auto machine driver. +- qcom,model : The user-visible name of this sound card. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given + in "asoc-cpu". The cpu names are in the form of "%s.%d" form, + where the id (%d) field represents the back-end AFE port id that + this CPU dai is associated with. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +Optional properties: +- qcom,mi2s-audio-intf : Property to specify if MI2S interface is used for the target +- qcom,auxpcm-audio-intf : Property to specify if AUX PCM interface is used for the target +- qcom,msm-mi2s-master : List of master/slave configuration for MI2S interfaces +- qcom,msm_audio_ssr_devs: List the snd event framework clients + +Example: + + sound-adp-star { + compatible = "qcom,sa8155-gecko-asoc-snd-adp-star"; + qcom,model = "sa8155-gecko-adp-star-snd-card"; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>, <&loopback1>, <&pcm_dtmf>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq", "msm-pcm-loopback.1", + "msm-pcm-dtmf"; + asoc-cpu = <&dai_hdmi>, <&dai_dp>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, + <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, + <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, + <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_rx_1>, + <&dai_sec_tdm_rx_2>, <&dai_sec_tdm_rx_3>, + <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>, + <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>, + <&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>, + <&dai_tert_tdm_rx_4>, <&dai_tert_tdm_tx_0>, + <&dai_tert_tdm_tx_1>, <&dai_tert_tdm_tx_2>, + <&dai_tert_tdm_tx_3>, <&dai_quat_tdm_rx_0>, + <&dai_quat_tdm_rx_1>, <&dai_quat_tdm_rx_2>, + <&dai_quat_tdm_rx_3>, <&dai_quat_tdm_tx_0>, + <&dai_quat_tdm_tx_1>, <&dai_quat_tdm_tx_2>, + <&dai_quat_tdm_tx_3>, <&dai_quin_tdm_rx_0>, + <&dai_quin_tdm_rx_1>, <&dai_quin_tdm_rx_2>, + <&dai_quin_tdm_rx_3>, <&dai_quin_tdm_tx_0>, + <&dai_quin_tdm_tx_1>, <&dai_quin_tdm_tx_2>, + <&dai_quin_tdm_tx_3>; + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", + "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", + "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36882", + "msm-dai-q6-tdm.36884", "msm-dai-q6-tdm.36886", + "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883", + "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898", + "msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902", + "msm-dai-q6-tdm.36904", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36899", "msm-dai-q6-tdm.36901", + "msm-dai-q6-tdm.36903", "msm-dai-q6-tdm.36912", + "msm-dai-q6-tdm.36914", "msm-dai-q6-tdm.36916", + "msm-dai-q6-tdm.36918", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36915", "msm-dai-q6-tdm.36917", + "msm-dai-q6-tdm.36919", "msm-dai-q6-tdm.36928", + "msm-dai-q6-tdm.36930", "msm-dai-q6-tdm.36932", + "msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36929", + "msm-dai-q6-tdm.36931", "msm-dai-q6-tdm.36933", + "msm-dai-q6-tdm.36935"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + qcom,msm_audio_ssr_devs = <&audio_apr>, <&q6core>; + }; + * SDX ASoC Machine driver Required properties: -- GitLab From bd2f8c3ba9ca20659233cd46f09f622bf4f2877a Mon Sep 17 00:00:00 2001 From: Harsh Agarwal Date: Thu, 4 Jun 2020 21:59:38 +0530 Subject: [PATCH 0862/1055] usb: gadget: f_ipc: Fix race between ipc_free_inst and ipc_close There is a possibility of race condition when we unregister the gadget f_ipc.As part of this, ipc_free_inst and ipc_close gets executed in parallel threads. The race condition may arise depending on when the ipc_dev is freed in ipc_free_inst, which in turn could lead to use-after-free in ipc_close. Fix this by moving the allocation and de-allocation of ipc_dev in ipc_init and ipc_exit. Change-Id: I30bf28258a8da6d2c9cd2f4eae7f38025b49ee0d Signed-off-by: Harsh Agarwal --- drivers/usb/gadget/function/f_ipc.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/function/f_ipc.c b/drivers/usb/gadget/function/f_ipc.c index 1b99e9962305..1e6a1b4ac822 100644 --- a/drivers/usb/gadget/function/f_ipc.c +++ b/drivers/usb/gadget/function/f_ipc.c @@ -794,10 +794,6 @@ static int ipc_set_inst_name(struct usb_function_instance *fi, if (name_len > MAX_INST_NAME_LEN) return -ENAMETOOLONG; - ipc_dev = kzalloc(sizeof(*ipc_dev), GFP_KERNEL); - if (!ipc_dev) - return -ENOMEM; - spin_lock_init(&ipc_dev->lock); init_waitqueue_head(&ipc_dev->state_wq); init_completion(&ipc_dev->read_done); @@ -813,7 +809,6 @@ static void ipc_free_inst(struct usb_function_instance *f) { struct ipc_opts *opts = container_of(f, struct ipc_opts, func_inst); - kfree(opts->ctxt); kfree(opts); } @@ -844,9 +839,17 @@ static int __init ipc_init(void) { int ret; + ipc_dev = kzalloc(sizeof(*ipc_dev), GFP_KERNEL); + if (!ipc_dev) + return -ENOMEM; + ret = usb_function_register(&ipcusb_func); - if (ret) + if (ret) { + kfree(ipc_dev); + ipc_dev = NULL; pr_err("%s: failed to register ipc %d\n", __func__, ret); + return ret; + } fipc_debugfs_init(); @@ -857,6 +860,8 @@ static void __exit ipc_exit(void) { fipc_debugfs_remove(); usb_function_unregister(&ipcusb_func); + kfree(ipc_dev); + ipc_dev = NULL; } module_init(ipc_init); -- GitLab From ef7e4d4cb6f760815886c599ff21893a441f62da Mon Sep 17 00:00:00 2001 From: Manohar Vavilapalli Date: Thu, 18 Jun 2020 17:47:53 +0530 Subject: [PATCH 0863/1055] ARM: dts: msm: correct the filenames in Makefile Add correct dtbo and dtb names for sa6155p and sa8155p ADP star and ADP air Lpass boards. Change-Id: Ia3c1017dbe4dcdd3391f998ba6d06ea94bd31e58 Signed-off-by: Manohar Vavilapalli --- arch/arm64/boot/dts/qcom/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index c9af9a76daca..952dafb9f2ff 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -8,7 +8,7 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sa8155p-adp-star-lpass-overlay.dtbo \ sa8155-v2-adp-air-overlay.dtbo \ sa8155p-v2-adp-air-overlay.dtbo \ - sa8155p-v2-adp-air-lpass-overlay.dts + sa8155p-v2-adp-air-lpass-overlay.dtbo sm8150-cdp-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb sa8155-adp-star-overlay.dtbo-base := sa8155.dtb sa8155-v2.dtb @@ -21,7 +21,7 @@ else dtb-$(CONFIG_ARCH_SM8150) += sm8150-cdp.dtb \ sa8155-adp-star.dtb \ sa8155p-adp-star.dtb \ - sa8155p-adp-star-lpass \ + sa8155p-adp-star-lpass.dtb \ sa8155-v2-adp-star.dtb \ sa8155p-v2-adp-star.dtb \ sa8155-v2-adp-air.dtb \ @@ -48,12 +48,12 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) dtbo-$(CONFIG_ARCH_SM6150) += \ sa6155-adp-star-overlay.dtbo \ sa6155p-adp-star-overlay.dtbo \ - sa6155p-adp-star-lpass-overlay.dts \ + sa6155p-adp-star-lpass-overlay.dtbo \ sa6155-adp-air-overlay.dtbo \ sa6155p-adp-air-overlay.dtbo \ sa6155p-v2-adp-star-overlay.dtbo \ sa6155p-v2-adp-air-overlay.dtbo \ - sa6155p-v2-adp-air-lpass-overlay.dts + sa6155p-v2-adp-air-lpass-overlay.dtbo sa6155-adp-star-overlay.dtbo-base := sa6155.dtb sa6155p-adp-star-overlay.dtbo-base := sa6155p.dtb -- GitLab From b4f54e8e4aa56bef87b409ac3396c52add0460da Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Thu, 18 Jun 2020 19:05:53 +0530 Subject: [PATCH 0864/1055] ARM: dts: qcom: Correct adsp_smsm node interrupt number Correct adsp_smsm dtsi node interrupt number. Change-Id: I26d061a73effb4d076e903155f4816600d1d2ed9 Signed-off-by: Prudhvi Yarlagadda --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index e41a1c3e5c35..9dc5c8d28a32 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -712,7 +712,7 @@ adsp_smsm: adsp@2 { reg = <2>; - interrupts = <0 289 IRQ_TYPE_EDGE_RISING>; + interrupts = <0 290 IRQ_TYPE_EDGE_RISING>; interrupt-controller; #interrupt-cells = <2>; }; -- GitLab From 8cb52e630a13f1334c7d6933ce6e65f286f99d1e Mon Sep 17 00:00:00 2001 From: Om Parkash Date: Thu, 18 Jun 2020 19:56:37 +0530 Subject: [PATCH 0865/1055] msm: camera: isp: Fix race condition b/w add and apply req There is a chance that CRM shows request as ready while request is not passed in isp pending list. Change-Id: If20ef7671c06a1d3bde7adc5a05a6a489b2622e2 Signed-off-by: Om Parkash --- .../msm/camera/cam_isp/cam_isp_context.c | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index d96a23da3bb8..c5dd8819d6a5 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -340,6 +340,23 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp, } } +static void __cam_isp_ctx_dequeue_request(struct cam_context *ctx, + struct cam_ctx_request *req) +{ + struct cam_ctx_request *req_current; + struct cam_ctx_request *req_prev; + + spin_lock_bh(&ctx->lock); + list_for_each_entry_safe_reverse(req_current, req_prev, + &ctx->pending_req_list, list) { + if (req->request_id == req_current->request_id) { + list_del_init(&req_current->list); + break; + } + } + spin_unlock_bh(&ctx->lock); +} + static int __cam_isp_ctx_enqueue_request_in_order( struct cam_context *ctx, struct cam_ctx_request *req) { @@ -3367,13 +3384,12 @@ static int __cam_isp_ctx_config_dev_in_top_state( add_req.dev_hdl = ctx->dev_hdl; add_req.req_id = req->request_id; add_req.skip_before_applying = 0; + __cam_isp_ctx_enqueue_request_in_order(ctx, req); rc = ctx->ctx_crm_intf->add_req(&add_req); if (rc) { CAM_ERR(CAM_ISP, "Add req failed: req id=%llu", req->request_id); - } else { - __cam_isp_ctx_enqueue_request_in_order( - ctx, req); + __cam_isp_ctx_dequeue_request(ctx, req); } } else { rc = -EINVAL; -- GitLab From c2e4091f816fc46c12839755565f43c351b92fab Mon Sep 17 00:00:00 2001 From: Sivasri Kumar Vanka Date: Thu, 18 Jun 2020 18:16:05 +0530 Subject: [PATCH 0866/1055] rpmsg: qcom_smd: Add SET signal support Added support to SET the transport signals by the clients This fix works for back to back Dial-Up-Network net browsing without reboot the device. Change-Id: I9c2bcb65abee9d59acb1739a9144f97dd52a7d35 Signed-off-by: Sivasri Kumar Vanka --- drivers/rpmsg/qcom_smd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index f8b4b24fe736..190a72a5e68f 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -289,7 +289,9 @@ struct smd_channel_info_word_pair { (GET_RX_CHANNEL_FLAG(channel, fDSR) ? TIOCM_DSR : 0) | \ (GET_RX_CHANNEL_FLAG(channel, fCTS) ? TIOCM_CTS : 0) | \ (GET_RX_CHANNEL_FLAG(channel, fCD) ? TIOCM_CD : 0) | \ - (GET_RX_CHANNEL_FLAG(channel, fRI) ? TIOCM_RI : 0); \ + (GET_RX_CHANNEL_FLAG(channel, fRI) ? TIOCM_RI : 0) | \ + (GET_TX_CHANNEL_FLAG(channel, fDSR) ? TIOCM_DTR : 0) | \ + (GET_TX_CHANNEL_FLAG(channel, fCTS) ? TIOCM_RTS : 0); \ }) #define SET_RX_CHANNEL_FLAG(channel, param, value) \ -- GitLab From 480c3a4e1fe7f5a92452a5b9e3592a2afec1144b Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Sun, 7 Jun 2020 18:56:05 +0530 Subject: [PATCH 0867/1055] ARM: dts: msm: add link clk rcg entry on sm8150 During suspend to disk we need to set link clk parent to xo during disable. This changes adds an link_clk_rcg entry to DP device tree node. Change-Id: I0ff6e6ee5d8380107e5e19fe3540d56ccb36ec9a Acked-by: Poojashree Masthi Signed-off-by: Rahul Sharma --- arch/arm64/boot/dts/qcom/sm8150-sde.dtsi | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index fd3cd5e26b42..5bd15f44aebf 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020, 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 @@ -622,13 +622,15 @@ <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK_SRC>, <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, - <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>; + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>; clock-names = "core_aux_clk", "core_usb_ref_clk_src", "core_usb_ref_clk", "core_usb_pipe_clk", "link_clk", "link_iface_clk", "crypto_clk", "pixel_clk_rcg", "pixel_parent", "pixel1_clk_rcg", "pixel1_parent", - "strm0_pixel_clk", "strm1_pixel_clk"; + "strm0_pixel_clk", "strm1_pixel_clk", + "link_clk_rcg"; qcom,phy-version = <0x420>; qcom,aux-cfg0-settings = [20 00]; -- GitLab From e845f1e586d63a101167b30d1dae56e83c53a1d8 Mon Sep 17 00:00:00 2001 From: Rahul Sharma Date: Fri, 5 Jun 2020 11:00:53 +0530 Subject: [PATCH 0868/1055] ARM: dts: msm: add xo_clk for DP display on sm8150 During suspend to disk we need to set DP PCLK to xo during disable. This changes adds an xo_clk entry to DP device tree node. Change-Id: Id9dd3cf04e273484be4484d20fedd618c9e119a8 Acked-by: Poojashree Masthi Signed-off-by: Rahul Sharma --- arch/arm64/boot/dts/qcom/sm8150-sde.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi index 5bd15f44aebf..172fc111907f 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde.dtsi @@ -623,14 +623,15 @@ <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>, <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, <&clock_dispcc DISP_CC_MDSS_DP_PIXEL1_CLK>, - <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>; + <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, + <&clock_rpmh RPMH_CXO_CLK>; clock-names = "core_aux_clk", "core_usb_ref_clk_src", "core_usb_ref_clk", "core_usb_pipe_clk", "link_clk", "link_iface_clk", "crypto_clk", "pixel_clk_rcg", "pixel_parent", "pixel1_clk_rcg", "pixel1_parent", "strm0_pixel_clk", "strm1_pixel_clk", - "link_clk_rcg"; + "link_clk_rcg", "xo_clk"; qcom,phy-version = <0x420>; qcom,aux-cfg0-settings = [20 00]; -- GitLab From 5898eaccf34f3c5b58b7e66f18589c64654d741a Mon Sep 17 00:00:00 2001 From: "Thomas (Wonyoung) Yun" Date: Wed, 17 Jun 2020 12:46:38 -0400 Subject: [PATCH 0869/1055] soc: qcom: hgsl: Update hfi command data structure Sync the data structure with kgsl/gmu. Change-Id: I9820f6dab0d5dde1aede7ef22e1b22af7d9b4284 Signed-off-by: Thomas (Wonyoung) Yun --- drivers/soc/qcom/hgsl/hgsl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/qcom/hgsl/hgsl.c b/drivers/soc/qcom/hgsl/hgsl.c index 60070a4c6f01..80f9b7436ca5 100644 --- a/drivers/soc/qcom/hgsl/hgsl.c +++ b/drivers/soc/qcom/hgsl/hgsl.c @@ -226,7 +226,9 @@ struct hgsl_db_cmds { uint32_t ctx_id; uint32_t cmd_flags; uint32_t timestamp; + uint64_t user_profile_gpuaddr; uint32_t num_ibs; + uint32_t ib_desc_gmuaddr; struct hgsl_fw_ib_desc ib_descs[]; } __packed; -- GitLab From c73ad82a0af5fd7cdc28d8d315631bfa4edd0479 Mon Sep 17 00:00:00 2001 From: Saurabh Sahu Date: Tue, 26 May 2020 11:29:54 +0530 Subject: [PATCH 0870/1055] clk: qcom: sdm429w: Update the gcc/debugcc for sdm429w Update the bi_tcxo_ao name, remove hw_ctrl and CLK_SET_ RATE_PARENT flag for camss_gp clocks, use enable_regs for votable branch clocks and update debugcc blsp2_uart2 clk offset for sdm429w. Change-Id: I692348b6e7adbda5a343ebcb5e5b84f3e99d0f25 Signed-off-by: Saurabh Sahu --- drivers/clk/qcom/debugcc-sdm429w.c | 6 +- drivers/clk/qcom/gcc-sdm429w.c | 96 +++-- include/dt-bindings/clock/qcom,gcc-sdm429w.h | 353 ++++++++++--------- 3 files changed, 239 insertions(+), 216 deletions(-) diff --git a/drivers/clk/qcom/debugcc-sdm429w.c b/drivers/clk/qcom/debugcc-sdm429w.c index f733209fdcba..52d560dde927 100644 --- a/drivers/clk/qcom/debugcc-sdm429w.c +++ b/drivers/clk/qcom/debugcc-sdm429w.c @@ -223,7 +223,7 @@ static struct clk_debug_mux gcc_debug_mux = { 1, 0x74000, 0x74000, 0x74000 }, { "gcc_blsp2_uart1_apps_clk", 0x9C, 1, GCC, 0x9C, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, - { "gcc_blsp2_uart2_apps_clk", 0x9A, 1, GCC, 0x9A, 0x1FF, 0, 0xF, + { "gcc_blsp2_uart2_apps_clk", 0xA1, 1, GCC, 0xA1, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_boot_rom_ahb_clk", 0xF8, 1, GCC, 0xF8, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, @@ -333,9 +333,9 @@ static struct clk_debug_mux gcc_debug_mux = { 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_byte1_clk", 0x1FC, 1, GCC, 0x1FC, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, - { "gcc_mdss_esc0_clk", 0x1E5, 1, GCC, 0x1E5, 0x1FF, 0, 0xF, 12, + { "gcc_mdss_esc0_clk", 0x1FD, 1, GCC, 0x1FD, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, - { "gcc_mdss_esc1_clk", 0x1FD, 1, GCC, 0x1FD, 0x1FF, 0, 0xF, 12, + { "gcc_mdss_esc1_clk", 0x1E5, 1, GCC, 0x1E5, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, { "gcc_mdss_mdp_clk", 0x1F9, 1, GCC, 0x1F9, 0x1FF, 0, 0xF, 12, 1, 0x74000, 0x74000, 0x74000 }, diff --git a/drivers/clk/qcom/gcc-sdm429w.c b/drivers/clk/qcom/gcc-sdm429w.c index d49b5c4e5762..61239022ab85 100644 --- a/drivers/clk/qcom/gcc-sdm429w.c +++ b/drivers/clk/qcom/gcc-sdm429w.c @@ -65,7 +65,7 @@ static const char * const gcc_parent_names_0[] = { }; static const char * const gcc_parent_names_ao_0[] = { - "bi_tcxo_a", + "bi_tcxo_ao", "gpll0_ao_out_main", "core_bi_pll_test_se", }; @@ -415,7 +415,7 @@ static struct clk_alpha_pll gpll0_ao_out_main = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gpll0_ao_out_main", - .parent_names = (const char *[]){ "bi_tcxo_a" }, + .parent_names = (const char *[]){ "bi_tcxo_ao" }, .num_parents = 1, .ops = &clk_alpha_pll_ops, }, @@ -455,6 +455,7 @@ static struct clk_alpha_pll gpll3_out_main = { .vdd_class = &vdd_cx, .num_rate_max = VDD_NUM, .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW_L1] = 800000000, [VDD_NOMINAL] = 1400000000}, }, }, @@ -478,7 +479,7 @@ static struct clk_alpha_pll gpll4_out_main = { }, }; -static struct clk_pll gpll6_out_main = { +static struct clk_pll gpll6 = { .l_reg = 0x37004, .m_reg = 0x37008, .n_reg = 0x3700C, @@ -487,10 +488,21 @@ static struct clk_pll gpll6_out_main = { .status_reg = 0x3701C, .status_bit = 17, .clkr.hw.init = &(struct clk_init_data){ - .name = "gpll6", - .parent_names = (const char *[]){ "bi_tcxo" }, + .name = "gpll6", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + +static struct clk_regmap gpll6_out_main = { + .enable_reg = 0x45000, + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "gpll6_out_main", + .parent_names = (const char *[]){ "gpll6" }, .num_parents = 1, - .ops = &clk_pll_ops, + .ops = &clk_pll_vote_ops, }, }; @@ -499,7 +511,7 @@ static struct clk_regmap gpll6_out_aux = { .enable_mask = BIT(7), .hw.init = &(struct clk_init_data){ .name = "gpll6_out_aux", - .parent_names = (const char *[]){ "gpll6_out_main" }, + .parent_names = (const char *[]){ "gpll6" }, .num_parents = 1, .ops = &clk_pll_vote_ops, }, @@ -960,7 +972,7 @@ static const struct freq_tbl ftbl_cpp_clk_src[] = { F(133333333, P_GPLL0_OUT_MAIN, 6, 0, 0), F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0), - F(308570000, P_GPLL6_OUT_MAIN, 3.5, 0, 0), + F(308571428, P_GPLL6_OUT_MAIN, 3.5, 0, 0), F(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), F(360000000, P_GPLL6_OUT_MAIN, 3, 0, 0), { } @@ -1086,7 +1098,7 @@ static const struct freq_tbl ftbl_jpeg0_clk_src[] = { F(133333333, P_GPLL0_OUT_MAIN, 6, 0, 0), F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0), - F(308570000, P_GPLL6_OUT_AUX, 3.5, 0, 0), + F(308571428, P_GPLL6_OUT_AUX, 3.5, 0, 0), F(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), { } }; @@ -1267,7 +1279,7 @@ static const struct freq_tbl ftbl_vfe0_clk_src[] = { F(177777778, P_GPLL0_OUT_MAIN, 4.5, 0, 0), F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0), F(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0), - F(308570000, P_GPLL6_OUT_MAIN, 3.5, 0, 0), + F(308571428, P_GPLL6_OUT_MAIN, 3.5, 0, 0), F(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0), F(360000000, P_GPLL6_OUT_MAIN, 3, 0, 0), F(400000000, P_GPLL0_OUT_MAIN, 2, 0, 0), @@ -1371,12 +1383,10 @@ static struct clk_rcg2 camss_gp0_clk_src = { .parent_map = gcc_parent_map_20, .freq_tbl = ftbl_camss_gp0_clk_src, .enable_safe_config = true, - .flags = HW_CLK_CTRL_MODE, .clkr.hw.init = &(struct clk_init_data){ .name = "camss_gp0_clk_src", .parent_names = gcc_parent_names_20, .num_parents = 5, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, .vdd_class = &vdd_cx, .num_rate_max = VDD_NUM, @@ -1394,12 +1404,10 @@ static struct clk_rcg2 camss_gp1_clk_src = { .parent_map = gcc_parent_map_20, .freq_tbl = ftbl_camss_gp0_clk_src, .enable_safe_config = true, - .flags = HW_CLK_CTRL_MODE, .clkr.hw.init = &(struct clk_init_data){ .name = "camss_gp1_clk_src", .parent_names = gcc_parent_names_20, .num_parents = 5, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, .vdd_class = &vdd_cx, .num_rate_max = VDD_NUM, @@ -1648,7 +1656,6 @@ static const struct freq_tbl ftbl_gfx3d_clk_src[] = { F_SLEW(216000000, P_GPLL6_OUT_AUX, 5, 0, 0, FIXED_FREQ_SRC), F_SLEW(228571429, P_GPLL0_OUT_MAIN, 3.5, 0, 0, FIXED_FREQ_SRC), F_SLEW(240000000, P_GPLL6_OUT_AUX, 4.5, 0, 0, FIXED_FREQ_SRC), - F_SLEW(259200000, P_GPLL3_OUT_MAIN, 2.5, 0, 0, 1296000000), F_SLEW(266666667, P_GPLL0_OUT_MAIN, 3, 0, 0, FIXED_FREQ_SRC), F_SLEW(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0, FIXED_FREQ_SRC), F_SLEW(355200000, P_GPLL3_OUT_MAIN, 1, 0, 0, 710400000), @@ -1673,7 +1680,6 @@ static struct clk_rcg2 gfx3d_clk_src = { .name = "gfx3d_clk_src", .parent_names = gcc_parent_names_14, .num_parents = 6, - .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, }, }; @@ -1931,10 +1937,10 @@ static struct clk_branch gcc_mss_q6_bimc_axi_clk = { static struct clk_branch gcc_blsp1_ahb_clk = { .halt_reg = 0x1008, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_VOTED, .clkr = { - .enable_reg = 0x1008, - .enable_mask = BIT(0), + .enable_reg = 0x45004, + .enable_mask = BIT(10), .hw.init = &(struct clk_init_data){ .name = "gcc_blsp1_ahb_clk", .ops = &clk_branch2_ops, @@ -2196,10 +2202,10 @@ static struct clk_branch gcc_blsp2_qup2_spi_apps_clk = { static struct clk_branch gcc_blsp2_ahb_clk = { .halt_reg = 0xb008, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_VOTED, .clkr = { - .enable_reg = 0xb008, - .enable_mask = BIT(0), + .enable_reg = 0x45004, + .enable_mask = BIT(20), .hw.init = &(struct clk_init_data){ .name = "gcc_blsp2_ahb_clk", .ops = &clk_branch2_ops, @@ -2317,10 +2323,10 @@ static struct clk_branch gcc_blsp2_uart2_apps_clk = { static struct clk_branch gcc_boot_rom_ahb_clk = { .halt_reg = 0x1300c, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_VOTED, .clkr = { - .enable_reg = 0x1300c, - .enable_mask = BIT(0), + .enable_reg = 0x45004, + .enable_mask = BIT(7), .hw.init = &(struct clk_init_data){ .name = "gcc_boot_rom_ahb_clk", .ops = &clk_branch2_ops, @@ -2330,9 +2336,9 @@ static struct clk_branch gcc_boot_rom_ahb_clk = { static struct clk_branch gcc_crypto_ahb_clk = { .halt_reg = 0x16024, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_VOTED, .clkr = { - .enable_reg = 0x16024, + .enable_reg = 0x45004, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_crypto_ahb_clk", @@ -2343,10 +2349,10 @@ static struct clk_branch gcc_crypto_ahb_clk = { static struct clk_branch gcc_crypto_axi_clk = { .halt_reg = 0x16020, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_VOTED, .clkr = { - .enable_reg = 0x16020, - .enable_mask = BIT(0), + .enable_reg = 0x45004, + .enable_mask = BIT(1), .hw.init = &(struct clk_init_data){ .name = "gcc_crypto_axi_clk", .ops = &clk_branch2_ops, @@ -2356,10 +2362,10 @@ static struct clk_branch gcc_crypto_axi_clk = { static struct clk_branch gcc_crypto_clk = { .halt_reg = 0x1601c, - .halt_check = BRANCH_HALT, + .halt_check = BRANCH_HALT_VOTED, .clkr = { - .enable_reg = 0x1601c, - .enable_mask = BIT(0), + .enable_reg = 0x45004, + .enable_mask = BIT(2), .hw.init = &(struct clk_init_data){ .name = "gcc_crypto_clk", .parent_names = (const char *[]){ @@ -2461,8 +2467,8 @@ static struct clk_branch gcc_prng_ahb_clk = { .halt_reg = 0x13004, .halt_check = BRANCH_HALT, .clkr = { - .enable_reg = 0x13004, - .enable_mask = BIT(0), + .enable_reg = 0x45004, + .enable_mask = BIT(8), .hw.init = &(struct clk_init_data){ .name = "gcc_prng_ahb_clk", .ops = &clk_branch2_ops, @@ -2558,7 +2564,6 @@ static struct clk_branch gcc_usb2a_phy_sleep_clk = { .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_usb2a_phy_sleep_clk", - .num_parents = 1, .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, @@ -3540,6 +3545,14 @@ static struct clk_branch gcc_oxili_aon_clk = { .num_parents = 1, .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 320000000, + [VDD_LOW_L1] = 400000000, + [VDD_NOMINAL] = 510000000, + [VDD_NOMINAL_L1] = 560000000, + [VDD_HIGH] = 650000000}, }, }, }; @@ -3558,6 +3571,14 @@ static struct clk_branch gcc_oxili_gfx3d_clk = { .num_parents = 1, .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, + .vdd_class = &vdd_cx, + .num_rate_max = VDD_NUM, + .rate_max = (unsigned long[VDD_NUM]) { + [VDD_LOW] = 320000000, + [VDD_LOW_L1] = 400000000, + [VDD_NOMINAL] = 510000000, + [VDD_NOMINAL_L1] = 560000000, + [VDD_HIGH] = 650000000}, }, }, }; @@ -3845,7 +3866,8 @@ static struct clk_regmap *gcc_sdm429w_clocks[] = { [GPLL0_SLEEP_CLK_SRC] = &gpll0_sleep_clk_src.clkr, [GPLL3_OUT_MAIN] = &gpll3_out_main.clkr, [GPLL4_OUT_MAIN] = &gpll4_out_main.clkr, - [GPLL6_OUT_MAIN] = &gpll6_out_main.clkr, + [GPLL6_OUT_MAIN] = &gpll6_out_main, + [GPLL6] = &gpll6.clkr, [GPLL6_OUT_AUX] = &gpll6_out_aux, [JPEG0_CLK_SRC] = &jpeg0_clk_src.clkr, [PDM2_CLK_SRC] = &pdm2_clk_src.clkr, diff --git a/include/dt-bindings/clock/qcom,gcc-sdm429w.h b/include/dt-bindings/clock/qcom,gcc-sdm429w.h index 5aaf5e814279..6df9141c80c3 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdm429w.h +++ b/include/dt-bindings/clock/qcom,gcc-sdm429w.h @@ -23,182 +23,183 @@ #define GPLL4_OUT_MAIN 5 #define GPLL0_AO_OUT_MAIN 6 #define GPLL0_SLEEP_CLK_SRC 7 -#define GPLL6_OUT_MAIN 8 -#define GPLL6_OUT_AUX 9 -#define APSS_AHB_CLK_SRC 10 -#define BLSP1_QUP1_I2C_APPS_CLK_SRC 11 -#define BLSP1_QUP1_SPI_APPS_CLK_SRC 12 -#define BLSP1_QUP2_I2C_APPS_CLK_SRC 13 -#define BLSP1_QUP2_SPI_APPS_CLK_SRC 14 -#define BLSP1_QUP3_I2C_APPS_CLK_SRC 15 -#define BLSP1_QUP3_SPI_APPS_CLK_SRC 16 -#define BLSP1_QUP4_I2C_APPS_CLK_SRC 17 -#define BLSP1_QUP4_SPI_APPS_CLK_SRC 18 -#define BLSP1_UART1_APPS_CLK_SRC 19 -#define BLSP1_UART2_APPS_CLK_SRC 20 -#define BLSP2_QUP1_I2C_APPS_CLK_SRC 21 -#define BLSP2_QUP1_SPI_APPS_CLK_SRC 22 -#define BLSP2_QUP2_I2C_APPS_CLK_SRC 23 -#define BLSP2_QUP2_SPI_APPS_CLK_SRC 24 -#define BLSP2_QUP3_I2C_APPS_CLK_SRC 25 -#define BLSP2_QUP3_SPI_APPS_CLK_SRC 26 -#define BLSP2_QUP4_I2C_APPS_CLK_SRC 27 -#define BLSP2_QUP4_SPI_APPS_CLK_SRC 28 -#define BLSP2_UART1_APPS_CLK_SRC 29 -#define BLSP2_UART2_APPS_CLK_SRC 30 -#define BYTE0_CLK_SRC 31 -#define BYTE1_CLK_SRC 32 -#define CAMSS_TOP_AHB_CLK_SRC 33 -#define CCI_CLK_SRC 34 -#define CPP_CLK_SRC 35 -#define CRYPTO_CLK_SRC 36 -#define CSI0_CLK_SRC 37 -#define CSI0PHYTIMER_CLK_SRC 38 -#define CSI1_CLK_SRC 39 -#define CSI1PHYTIMER_CLK_SRC 40 -#define CSI2_CLK_SRC 41 -#define ESC0_CLK_SRC 42 -#define ESC1_CLK_SRC 43 -#define GCC_BIMC_GFX_CLK 44 -#define GCC_BIMC_GPU_CLK 45 -#define GCC_BLSP1_AHB_CLK 46 -#define GCC_BLSP1_QUP1_I2C_APPS_CLK 47 -#define GCC_BLSP1_QUP1_SPI_APPS_CLK 48 -#define GCC_BLSP1_QUP2_I2C_APPS_CLK 49 -#define GCC_BLSP1_QUP2_SPI_APPS_CLK 50 -#define GCC_BLSP1_QUP3_I2C_APPS_CLK 51 -#define GCC_BLSP1_QUP3_SPI_APPS_CLK 52 -#define GCC_BLSP1_QUP4_I2C_APPS_CLK 53 -#define GCC_BLSP1_QUP4_SPI_APPS_CLK 54 -#define GCC_BLSP1_UART1_APPS_CLK 55 -#define GCC_BLSP1_UART2_APPS_CLK 56 -#define GCC_BLSP2_QUP1_I2C_APPS_CLK 57 -#define GCC_BLSP2_QUP1_SPI_APPS_CLK 58 -#define GCC_BLSP2_QUP2_I2C_APPS_CLK 59 -#define GCC_BLSP2_QUP2_SPI_APPS_CLK 60 -#define GCC_BLSP2_QUP3_I2C_APPS_CLK 61 -#define GCC_BLSP2_QUP3_SPI_APPS_CLK 62 -#define GCC_BLSP2_QUP4_I2C_APPS_CLK 63 -#define GCC_BLSP2_QUP4_SPI_APPS_CLK 64 -#define GCC_BLSP2_UART1_APPS_CLK 65 -#define GCC_BLSP2_UART2_APPS_CLK 66 -#define GCC_BLSP2_AHB_CLK 67 -#define GCC_BOOT_ROM_AHB_CLK 68 -#define GCC_CAMSS_AHB_CLK 69 -#define GCC_CAMSS_CCI_AHB_CLK 70 -#define GCC_CAMSS_CCI_CLK 71 -#define GCC_CAMSS_CPP_AHB_CLK 72 -#define GCC_CAMSS_CPP_AXI_CLK 73 -#define GCC_CAMSS_CPP_CLK 74 -#define GCC_CAMSS_CSI0_AHB_CLK 75 -#define GCC_CAMSS_CSI0_CLK 76 -#define GCC_CAMSS_CSI0PHY_CLK 77 -#define GCC_CAMSS_CSI0PIX_CLK 78 -#define GCC_CAMSS_CSI0RDI_CLK 79 -#define GCC_CAMSS_CSI1_AHB_CLK 80 -#define GCC_CAMSS_CSI1_CLK 81 -#define GCC_CAMSS_CSI1PHY_CLK 82 -#define GCC_CAMSS_CSI1PIX_CLK 83 -#define GCC_CAMSS_CSI1RDI_CLK 84 -#define GCC_CAMSS_CSI2_AHB_CLK 85 -#define GCC_CAMSS_CSI2_CLK 86 -#define GCC_CAMSS_CSI2PHY_CLK 87 -#define GCC_CAMSS_CSI2PIX_CLK 88 -#define GCC_CAMSS_CSI2RDI_CLK 89 -#define GCC_CAMSS_CSI_VFE0_CLK 90 -#define GCC_CAMSS_GP0_CLK_SRC 91 -#define GCC_CAMSS_GP1_CLK_SRC 92 -#define GCC_CAMSS_CSI_VFE1_CLK 93 -#define GCC_CAMSS_CSI0PHYTIMER_CLK 94 -#define GCC_CAMSS_CSI1PHYTIMER_CLK 95 -#define GCC_CAMSS_GP0_CLK 96 -#define GCC_CAMSS_GP1_CLK 97 -#define GCC_CAMSS_ISPIF_AHB_CLK 98 -#define GCC_CAMSS_JPEG0_CLK 99 -#define GCC_CAMSS_JPEG_AHB_CLK 100 -#define GCC_CAMSS_JPEG_AXI_CLK 101 -#define GCC_CAMSS_MCLK0_CLK 102 -#define GCC_CAMSS_MCLK1_CLK 103 -#define GCC_CAMSS_MCLK2_CLK 104 -#define GCC_CAMSS_MICRO_AHB_CLK 105 -#define GCC_CAMSS_TOP_AHB_CLK 106 -#define GCC_CAMSS_VFE0_CLK 107 -#define GCC_CAMSS_VFE1_AHB_CLK 108 -#define GCC_CAMSS_VFE1_AXI_CLK 109 -#define GCC_CAMSS_VFE1_CLK 110 -#define GCC_CAMSS_VFE_AHB_CLK 111 -#define GCC_CAMSS_VFE_AXI_CLK 112 -#define GCC_CRYPTO_AHB_CLK 113 -#define GCC_CRYPTO_AXI_CLK 114 -#define GCC_CRYPTO_CLK 115 -#define GCC_DCC_CLK 116 -#define GCC_GP1_CLK 117 -#define GCC_GP2_CLK 118 -#define GCC_GP3_CLK 119 -#define GCC_MDSS_AHB_CLK 120 -#define GCC_MDSS_AXI_CLK 121 -#define GCC_MDSS_BYTE0_CLK 122 -#define GCC_MDSS_BYTE1_CLK 123 -#define GCC_MDSS_ESC0_CLK 124 -#define GCC_MDSS_ESC1_CLK 125 -#define GCC_MDSS_MDP_CLK 126 -#define GCC_MDSS_PCLK0_CLK 127 -#define GCC_MDSS_PCLK1_CLK 128 -#define GCC_MDSS_VSYNC_CLK 129 -#define GCC_MSS_CFG_AHB_CLK 130 -#define GCC_MSS_Q6_BIMC_AXI_CLK 131 -#define GCC_OXILI_AHB_CLK 132 -#define GCC_OXILI_AON_CLK 133 -#define GCC_OXILI_GFX3D_CLK 134 -#define GCC_OXILI_TIMER_CLK 135 -#define GCC_PDM2_CLK 136 -#define GCC_PDM_AHB_CLK 137 -#define GCC_PRNG_AHB_CLK 138 -#define GCC_SDCC1_AHB_CLK 139 -#define GCC_SDCC1_APPS_CLK 140 -#define GCC_SDCC1_ICE_CORE_CLK 141 -#define GCC_SDCC2_AHB_CLK 142 -#define GCC_SDCC2_APPS_CLK 143 -#define GCC_USB2A_PHY_SLEEP_CLK 144 -#define GCC_USB_HS_AHB_CLK 145 -#define GCC_USB_HS_PHY_CFG_AHB_CLK 146 -#define GCC_USB_HS_SYSTEM_CLK 147 -#define GCC_VENUS0_AHB_CLK 148 -#define GCC_VENUS0_AXI_CLK 149 -#define GCC_VENUS0_CORE0_VCODEC0_CLK 150 -#define GCC_VENUS0_VCODEC0_CLK 151 -#define GCC_XO_CLK_SRC 152 -#define GFX3D_CLK_SRC 153 -#define GP1_CLK_SRC 154 -#define GP2_CLK_SRC 155 -#define GP3_CLK_SRC 156 -#define JPEG0_CLK_SRC 157 -#define MCLK0_CLK_SRC 158 -#define MCLK1_CLK_SRC 159 -#define MCLK2_CLK_SRC 160 -#define MDP_CLK_SRC 161 -#define MDSS_MDP_VOTE_CLK 162 -#define MDSS_ROTATOR_VOTE_CLK 163 -#define PCLK0_CLK_SRC 164 -#define PCLK1_CLK_SRC 165 -#define PDM2_CLK_SRC 166 -#define SDCC1_APPS_CLK_SRC 167 -#define SDCC1_ICE_CORE_CLK_SRC 168 -#define SDCC2_APPS_CLK_SRC 169 -#define USB_HS_SYSTEM_CLK_SRC 170 -#define VCODEC0_CLK_SRC 171 -#define VFE0_CLK_SRC 172 -#define VFE1_CLK_SRC 173 -#define VSYNC_CLK_SRC 174 -#define GCC_APSS_TCU_CLK 175 -#define GCC_CPP_TBU_CLK 176 -#define GCC_JPEG_TBU_CLK 177 -#define GCC_MDP_TBU_CLK 178 -#define GCC_SMMU_CFG_CLK 179 -#define GCC_VENUS_TBU_CLK 180 -#define GCC_VFE_TBU_CLK 181 -#define GCC_VFE1_TBU_CLK 182 -#define GCC_QDSS_DAP_CLK 183 +#define GPLL6 8 +#define GPLL6_OUT_MAIN 9 +#define GPLL6_OUT_AUX 10 +#define APSS_AHB_CLK_SRC 11 +#define BLSP1_QUP1_I2C_APPS_CLK_SRC 12 +#define BLSP1_QUP1_SPI_APPS_CLK_SRC 13 +#define BLSP1_QUP2_I2C_APPS_CLK_SRC 14 +#define BLSP1_QUP2_SPI_APPS_CLK_SRC 15 +#define BLSP1_QUP3_I2C_APPS_CLK_SRC 16 +#define BLSP1_QUP3_SPI_APPS_CLK_SRC 17 +#define BLSP1_QUP4_I2C_APPS_CLK_SRC 18 +#define BLSP1_QUP4_SPI_APPS_CLK_SRC 19 +#define BLSP1_UART1_APPS_CLK_SRC 20 +#define BLSP1_UART2_APPS_CLK_SRC 21 +#define BLSP2_QUP1_I2C_APPS_CLK_SRC 22 +#define BLSP2_QUP1_SPI_APPS_CLK_SRC 23 +#define BLSP2_QUP2_I2C_APPS_CLK_SRC 24 +#define BLSP2_QUP2_SPI_APPS_CLK_SRC 25 +#define BLSP2_QUP3_I2C_APPS_CLK_SRC 26 +#define BLSP2_QUP3_SPI_APPS_CLK_SRC 27 +#define BLSP2_QUP4_I2C_APPS_CLK_SRC 28 +#define BLSP2_QUP4_SPI_APPS_CLK_SRC 29 +#define BLSP2_UART1_APPS_CLK_SRC 30 +#define BLSP2_UART2_APPS_CLK_SRC 31 +#define BYTE0_CLK_SRC 32 +#define BYTE1_CLK_SRC 33 +#define CAMSS_TOP_AHB_CLK_SRC 34 +#define CCI_CLK_SRC 35 +#define CPP_CLK_SRC 36 +#define CRYPTO_CLK_SRC 37 +#define CSI0_CLK_SRC 38 +#define CSI0PHYTIMER_CLK_SRC 39 +#define CSI1_CLK_SRC 40 +#define CSI1PHYTIMER_CLK_SRC 41 +#define CSI2_CLK_SRC 42 +#define ESC0_CLK_SRC 43 +#define ESC1_CLK_SRC 44 +#define GCC_BIMC_GFX_CLK 45 +#define GCC_BIMC_GPU_CLK 46 +#define GCC_BLSP1_AHB_CLK 47 +#define GCC_BLSP1_QUP1_I2C_APPS_CLK 48 +#define GCC_BLSP1_QUP1_SPI_APPS_CLK 49 +#define GCC_BLSP1_QUP2_I2C_APPS_CLK 50 +#define GCC_BLSP1_QUP2_SPI_APPS_CLK 51 +#define GCC_BLSP1_QUP3_I2C_APPS_CLK 52 +#define GCC_BLSP1_QUP3_SPI_APPS_CLK 53 +#define GCC_BLSP1_QUP4_I2C_APPS_CLK 54 +#define GCC_BLSP1_QUP4_SPI_APPS_CLK 55 +#define GCC_BLSP1_UART1_APPS_CLK 56 +#define GCC_BLSP1_UART2_APPS_CLK 57 +#define GCC_BLSP2_QUP1_I2C_APPS_CLK 58 +#define GCC_BLSP2_QUP1_SPI_APPS_CLK 59 +#define GCC_BLSP2_QUP2_I2C_APPS_CLK 60 +#define GCC_BLSP2_QUP2_SPI_APPS_CLK 61 +#define GCC_BLSP2_QUP3_I2C_APPS_CLK 62 +#define GCC_BLSP2_QUP3_SPI_APPS_CLK 63 +#define GCC_BLSP2_QUP4_I2C_APPS_CLK 64 +#define GCC_BLSP2_QUP4_SPI_APPS_CLK 65 +#define GCC_BLSP2_UART1_APPS_CLK 66 +#define GCC_BLSP2_UART2_APPS_CLK 67 +#define GCC_BLSP2_AHB_CLK 68 +#define GCC_BOOT_ROM_AHB_CLK 69 +#define GCC_CAMSS_AHB_CLK 70 +#define GCC_CAMSS_CCI_AHB_CLK 71 +#define GCC_CAMSS_CCI_CLK 72 +#define GCC_CAMSS_CPP_AHB_CLK 73 +#define GCC_CAMSS_CPP_AXI_CLK 74 +#define GCC_CAMSS_CPP_CLK 75 +#define GCC_CAMSS_CSI0_AHB_CLK 76 +#define GCC_CAMSS_CSI0_CLK 77 +#define GCC_CAMSS_CSI0PHY_CLK 78 +#define GCC_CAMSS_CSI0PIX_CLK 79 +#define GCC_CAMSS_CSI0RDI_CLK 80 +#define GCC_CAMSS_CSI1_AHB_CLK 81 +#define GCC_CAMSS_CSI1_CLK 82 +#define GCC_CAMSS_CSI1PHY_CLK 83 +#define GCC_CAMSS_CSI1PIX_CLK 84 +#define GCC_CAMSS_CSI1RDI_CLK 85 +#define GCC_CAMSS_CSI2_AHB_CLK 86 +#define GCC_CAMSS_CSI2_CLK 87 +#define GCC_CAMSS_CSI2PHY_CLK 88 +#define GCC_CAMSS_CSI2PIX_CLK 89 +#define GCC_CAMSS_CSI2RDI_CLK 90 +#define GCC_CAMSS_CSI_VFE0_CLK 91 +#define GCC_CAMSS_GP0_CLK_SRC 92 +#define GCC_CAMSS_GP1_CLK_SRC 93 +#define GCC_CAMSS_CSI_VFE1_CLK 94 +#define GCC_CAMSS_CSI0PHYTIMER_CLK 95 +#define GCC_CAMSS_CSI1PHYTIMER_CLK 96 +#define GCC_CAMSS_GP0_CLK 97 +#define GCC_CAMSS_GP1_CLK 98 +#define GCC_CAMSS_ISPIF_AHB_CLK 99 +#define GCC_CAMSS_JPEG0_CLK 100 +#define GCC_CAMSS_JPEG_AHB_CLK 101 +#define GCC_CAMSS_JPEG_AXI_CLK 102 +#define GCC_CAMSS_MCLK0_CLK 103 +#define GCC_CAMSS_MCLK1_CLK 104 +#define GCC_CAMSS_MCLK2_CLK 105 +#define GCC_CAMSS_MICRO_AHB_CLK 106 +#define GCC_CAMSS_TOP_AHB_CLK 107 +#define GCC_CAMSS_VFE0_CLK 108 +#define GCC_CAMSS_VFE1_AHB_CLK 109 +#define GCC_CAMSS_VFE1_AXI_CLK 110 +#define GCC_CAMSS_VFE1_CLK 111 +#define GCC_CAMSS_VFE_AHB_CLK 112 +#define GCC_CAMSS_VFE_AXI_CLK 113 +#define GCC_CRYPTO_AHB_CLK 114 +#define GCC_CRYPTO_AXI_CLK 115 +#define GCC_CRYPTO_CLK 116 +#define GCC_DCC_CLK 117 +#define GCC_GP1_CLK 118 +#define GCC_GP2_CLK 119 +#define GCC_GP3_CLK 120 +#define GCC_MDSS_AHB_CLK 121 +#define GCC_MDSS_AXI_CLK 122 +#define GCC_MDSS_BYTE0_CLK 123 +#define GCC_MDSS_BYTE1_CLK 124 +#define GCC_MDSS_ESC0_CLK 125 +#define GCC_MDSS_ESC1_CLK 126 +#define GCC_MDSS_MDP_CLK 127 +#define GCC_MDSS_PCLK0_CLK 128 +#define GCC_MDSS_PCLK1_CLK 129 +#define GCC_MDSS_VSYNC_CLK 130 +#define GCC_MSS_CFG_AHB_CLK 131 +#define GCC_MSS_Q6_BIMC_AXI_CLK 132 +#define GCC_OXILI_AHB_CLK 133 +#define GCC_OXILI_AON_CLK 134 +#define GCC_OXILI_GFX3D_CLK 135 +#define GCC_OXILI_TIMER_CLK 136 +#define GCC_PDM2_CLK 137 +#define GCC_PDM_AHB_CLK 138 +#define GCC_PRNG_AHB_CLK 139 +#define GCC_SDCC1_AHB_CLK 140 +#define GCC_SDCC1_APPS_CLK 141 +#define GCC_SDCC1_ICE_CORE_CLK 142 +#define GCC_SDCC2_AHB_CLK 143 +#define GCC_SDCC2_APPS_CLK 144 +#define GCC_USB2A_PHY_SLEEP_CLK 145 +#define GCC_USB_HS_AHB_CLK 146 +#define GCC_USB_HS_PHY_CFG_AHB_CLK 147 +#define GCC_USB_HS_SYSTEM_CLK 148 +#define GCC_VENUS0_AHB_CLK 149 +#define GCC_VENUS0_AXI_CLK 150 +#define GCC_VENUS0_CORE0_VCODEC0_CLK 151 +#define GCC_VENUS0_VCODEC0_CLK 152 +#define GCC_XO_CLK_SRC 153 +#define GFX3D_CLK_SRC 154 +#define GP1_CLK_SRC 155 +#define GP2_CLK_SRC 156 +#define GP3_CLK_SRC 157 +#define JPEG0_CLK_SRC 158 +#define MCLK0_CLK_SRC 159 +#define MCLK1_CLK_SRC 160 +#define MCLK2_CLK_SRC 161 +#define MDP_CLK_SRC 162 +#define MDSS_MDP_VOTE_CLK 163 +#define MDSS_ROTATOR_VOTE_CLK 164 +#define PCLK0_CLK_SRC 165 +#define PCLK1_CLK_SRC 166 +#define PDM2_CLK_SRC 167 +#define SDCC1_APPS_CLK_SRC 168 +#define SDCC1_ICE_CORE_CLK_SRC 169 +#define SDCC2_APPS_CLK_SRC 170 +#define USB_HS_SYSTEM_CLK_SRC 171 +#define VCODEC0_CLK_SRC 172 +#define VFE0_CLK_SRC 173 +#define VFE1_CLK_SRC 174 +#define VSYNC_CLK_SRC 175 +#define GCC_APSS_TCU_CLK 176 +#define GCC_CPP_TBU_CLK 177 +#define GCC_JPEG_TBU_CLK 178 +#define GCC_MDP_TBU_CLK 179 +#define GCC_SMMU_CFG_CLK 180 +#define GCC_VENUS_TBU_CLK 181 +#define GCC_VFE_TBU_CLK 182 +#define GCC_VFE1_TBU_CLK 183 +#define GCC_QDSS_DAP_CLK 184 /* GCC resets */ #define GCC_CAMSS_MICRO_BCR 0 -- GitLab From 2c649e2a4cd29c28d0abe1fe5d81ca6172352890 Mon Sep 17 00:00:00 2001 From: Elson Roy Serrao Date: Thu, 16 Apr 2020 12:01:46 -0700 Subject: [PATCH 0871/1055] usb: dwc3: Add boundary check while traversing the TRB ring buffer During the dequeue operation of an usb request we traverse through the TRBs and reset the HWO bit. Without a boundary check we might iterate past the TRB ring which results in a page fault. Fix this by adding a link TRB boundary check while traversing the ring buffer. Change-Id: I7ae63ed7cc829a8105f2e81b12216af910aa253a Signed-off-by: Elson Roy Serrao --- drivers/usb/dwc3/gadget.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 9052518ff925..c6f0ce788048 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1684,17 +1684,18 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, goto out0; if (r->num_pending_sgs) { - struct dwc3_trb *trb; + struct dwc3_trb *trb = r->trb; int i = 0; for (i = 0; i < r->num_pending_sgs; i++) { - trb = r->trb + i; trb->ctrl &= ~DWC3_TRB_CTRL_HWO; dwc3_ep_inc_deq(dep); + trb++; + if (trb->ctrl & DWC3_TRBCTL_LINK_TRB) + trb = dep->trb_pool; } if (r->unaligned || r->zero) { - trb = r->trb + r->num_pending_sgs + 1; trb->ctrl &= ~DWC3_TRB_CTRL_HWO; dwc3_ep_inc_deq(dep); } @@ -1705,7 +1706,9 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, dwc3_ep_inc_deq(dep); if (r->unaligned || r->zero) { - trb = r->trb + 1; + trb++; + if (trb->ctrl & DWC3_TRBCTL_LINK_TRB) + trb = dep->trb_pool; trb->ctrl &= ~DWC3_TRB_CTRL_HWO; dwc3_ep_inc_deq(dep); } -- GitLab From c66f2b041b40f29295c5bfa16d252f6e2d4732b8 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Fri, 19 Jun 2020 11:22:21 +0530 Subject: [PATCH 0872/1055] ARM: msm: dts: Set usb dvdd voltage range to [0.8v 0.8v] for sdm429 Currently usb dvdd voltage is set to [928000 928000] for sdm429. This is leading to driver probe failure due different client vote for 0.8v. Hence fix the issue by setting voltage range for DVDD to [800000 800000] for sdm429 to avoid probe failure. Change-Id: If0abba01bf1623f5706d0fd2ae3283dd82d65b57 Signed-off-by: Vijayavardhan Vennapusa --- arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi b/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi index d70a7943140a..1cf4c8ad62a0 100644 --- a/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429w-pm660.dtsi @@ -250,4 +250,5 @@ &usb_otg { extcon = <&pm660_charger>; vbus_otg-supply = <&smb2_vbus>; + qcom,vdd-voltage-level = <0 800000 800000>; }; -- GitLab From bb37b06197e72dc8d78a51e5a20e19f58a695125 Mon Sep 17 00:00:00 2001 From: Vishwanath Raju K Date: Fri, 19 Jun 2020 11:31:00 +0530 Subject: [PATCH 0873/1055] iommu/arm-smmu: Add MSM_TZ_SMMU support on SDM429W SDM429W not having hypervisor, enaled MSM_TZ_SMMU to support slave side protection mechanism is used to provide buffer protection and additional functionality to make calls into TZ for mapping/unmapping of buffers. Change-Id: I0e37c67199ba4a58957ff5f7e42bac56b708e247 Signed-off-by: Vishwanath Raju K --- drivers/soc/qcom/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index dbd5759e94de..060e4c998400 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -673,7 +673,7 @@ config MSM_SPCOM or server is allowed per logical channel. config MSM_TZ_SMMU - depends on ARCH_MSM8953 || ARCH_QCS405 || ARCH_QCS403 + depends on ARCH_MSM8953 || ARCH_QCS405 || ARCH_QCS403 || ARCH_SDM429W bool "Helper functions for SMMU configuration through TZ" help Say 'Y' here for targets that need to call into TZ to configure -- GitLab From a0d505bb9ff4ea4b7e64f07c869b6194bfcf4e95 Mon Sep 17 00:00:00 2001 From: Shilpa Suresh Date: Fri, 12 Jun 2020 17:32:06 +0530 Subject: [PATCH 0874/1055] power: smb2: Enable read/writing of Type-C Rp value Enable the reading and writing of the Rp value used exclusively in Type-C Source mode operation. Change-Id: Ic1895282799326da09fc94c9f432b985b8a5794f Signed-off-by: Shilpa Suresh --- drivers/power/supply/qcom/qpnp-smb2.c | 7 +++ drivers/power/supply/qcom/smb-lib.c | 74 +++++++++++++++++++++++++++ drivers/power/supply/qcom/smb-lib.h | 4 ++ drivers/power/supply/qcom/smb-reg.h | 9 +++- 4 files changed, 93 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 660fda70f07f..b54c20d8c04e 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -366,6 +366,7 @@ static enum power_supply_property smb2_usb_props[] = { POWER_SUPPLY_PROP_TYPEC_MODE, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION, + POWER_SUPPLY_PROP_TYPEC_SRC_RP, POWER_SUPPLY_PROP_PD_ALLOWED, POWER_SUPPLY_PROP_PD_ACTIVE, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, @@ -456,6 +457,9 @@ static int smb2_usb_get_prop(struct power_supply *psy, else rc = smblib_get_prop_typec_cc_orientation(chg, val); break; + case POWER_SUPPLY_PROP_TYPEC_SRC_RP: + rc = smblib_get_prop_typec_select_rp(chg, val); + break; case POWER_SUPPLY_PROP_PD_ALLOWED: rc = smblib_get_prop_pd_allowed(chg, val); break; @@ -548,6 +552,9 @@ static int smb2_usb_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE: rc = smblib_set_prop_typec_power_role(chg, val); break; + case POWER_SUPPLY_PROP_TYPEC_SRC_RP: + rc = smblib_set_prop_typec_select_rp(chg, val); + break; case POWER_SUPPLY_PROP_PD_ACTIVE: rc = smblib_set_prop_pd_active(chg, val); break; diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index a704ef254e48..ffec1bf46b0d 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -1148,6 +1148,44 @@ static int __smblib_set_prop_typec_power_role(struct smb_charger *chg, return rc; } +static inline bool typec_in_src_mode(struct smb_charger *chg) +{ + return (chg->typec_mode > POWER_SUPPLY_TYPEC_NONE && + chg->typec_mode < POWER_SUPPLY_TYPEC_SOURCE_DEFAULT); +} + +int smblib_get_prop_typec_select_rp(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc, rp; + u8 stat; + + if (!typec_in_src_mode(chg)) + return -ENODATA; + + rc = smblib_read(chg, TYPE_C_CFG_2_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_CURRSRC_CFG_REG rc=%d\n", + rc); + return rc; + } + + switch (stat & EN_80UA_180UA_CUR_SOURCE_BIT) { + case TYPEC_SRC_RP_STD: + rp = POWER_SUPPLY_TYPEC_SRC_RP_STD; + break; + case TYPEC_SRC_RP_1P5A: + rp = POWER_SUPPLY_TYPEC_SRC_RP_1P5A; + break; + default: + return -EINVAL; + } + + val->intval = rp; + + return 0; +} + int smblib_toggle_stat(struct smb_charger *chg, int reset) { int rc = 0; @@ -2861,6 +2899,42 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, return 0; } +int smblib_set_prop_typec_select_rp(struct smb_charger *chg, + const union power_supply_propval *val) +{ + int rc = 0; + + if (!typec_in_src_mode(chg)) { + smblib_err(chg, "Couldn't set curr src: not in SRC mode\n"); + return -EINVAL; + } + + if (val->intval < 0 || val->intval >= TYPEC_SRC_RP_MAX_ELEMENTS) + return -EINVAL; + + switch (val->intval) { + case TYPEC_SRC_RP_STD: + rc = smblib_masked_write(chg, TYPE_C_CFG_2_REG, + EN_80UA_180UA_CUR_SOURCE_BIT, + TYPEC_SRC_RP_STD); + break; + case TYPEC_SRC_RP_1P5A: + case TYPEC_SRC_RP_3A: + case TYPEC_SRC_RP_3A_DUPLICATE: + rc = smblib_masked_write(chg, TYPE_C_CFG_2_REG, + EN_80UA_180UA_CUR_SOURCE_BIT, + TYPEC_SRC_RP_1P5A); + break; + default: + return -EINVAL; + } + + if (rc < 0) + smblib_err(chg, "Couldn't write to TYPE_C_CURRSRC_CFG rc=%d\n", + rc); + return rc; +} + int smblib_set_prop_pd_voltage_min(struct smb_charger *chg, const union power_supply_propval *val) { diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index de20612202c6..984a935edfdf 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -488,6 +488,8 @@ int smblib_get_prop_usb_current_now(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_typec_select_rp(struct smb_charger *chg, + union power_supply_propval *val); int smblib_get_prop_typec_power_role(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_pd_allowed(struct smb_charger *chg, @@ -520,6 +522,8 @@ int smblib_set_prop_boost_current(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_typec_power_role(struct smb_charger *chg, const union power_supply_propval *val); +int smblib_set_prop_typec_select_rp(struct smb_charger *chg, + const union power_supply_propval *val); int smblib_set_prop_pd_active(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg, diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h index f0af55d1cc69..a0858a735d0c 100644 --- a/drivers/power/supply/qcom/smb-reg.h +++ b/drivers/power/supply/qcom/smb-reg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020 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 @@ -576,6 +576,13 @@ enum { #define USB_FACTORY_MODE_ENABLE_BIT BIT(2) #define TYPE_C_UFP_MODE_BIT BIT(1) #define EN_80UA_180UA_CUR_SOURCE_BIT BIT(0) +enum { + TYPEC_SRC_RP_STD, + TYPEC_SRC_RP_1P5A, + TYPEC_SRC_RP_3A, + TYPEC_SRC_RP_3A_DUPLICATE, + TYPEC_SRC_RP_MAX_ELEMENTS +}; #define TYPE_C_CFG_3_REG (USBIN_BASE + 0x5A) #define TVBUS_DEBOUNCE_BIT BIT(7) -- GitLab From b839e783d71f67fdc5c6d54ac88231cfc5e993fc Mon Sep 17 00:00:00 2001 From: Vishwanath Raju K Date: Fri, 19 Jun 2020 14:00:51 +0530 Subject: [PATCH 0875/1055] defconfig: sdm429: Add CONFIG_MSM_TZ_SMMU defconfig for sdm429 Add CONFIG_MSM_TZ_SMMU defconfig to support secure smmu on sdm429. Change-Id: I56c8e5b2ed8d9fffcac80685b7281327937c3b6a Signed-off-by: Vishwanath Raju K --- arch/arm/configs/vendor/sdm429-bg-perf_defconfig | 1 + arch/arm/configs/vendor/sdm429-bg_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig index 9f9ae39a6056..18a0e70c09de 100644 --- a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig @@ -548,6 +548,7 @@ CONFIG_QCOM_EUD=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_TZ_SMMU=y CONFIG_QSEE_IPC_IRQ=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y diff --git a/arch/arm/configs/vendor/sdm429-bg_defconfig b/arch/arm/configs/vendor/sdm429-bg_defconfig index d8a9b3b30704..21840c116047 100644 --- a/arch/arm/configs/vendor/sdm429-bg_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg_defconfig @@ -572,6 +572,7 @@ CONFIG_QCOM_EUD=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_TZ_SMMU=y CONFIG_QSEE_IPC_IRQ=y # CONFIG_MSM_JTAGV8 is not set CONFIG_QTI_RPM_STATS_LOG=y -- GitLab From a72da71aeed8d3ccbf0dc2849c9fb6c306c00aa3 Mon Sep 17 00:00:00 2001 From: Chetan C R Date: Mon, 23 Mar 2020 19:32:51 +0530 Subject: [PATCH 0876/1055] ARM: dts: msm: Add debugcc support for SDM660 Add the Debug Clock Controller for measuring the clocks on SDM660. Change-Id: I4f4bd6e7f9fa1fe7913423cdfa4da17eb0d8e9bc Signed-off-by: Chetan C R Signed-off-by: Ashok Raj D --- arch/arm64/boot/dts/qcom/sdm660.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm660.dtsi b/arch/arm64/boot/dts/qcom/sdm660.dtsi index 25e48f860f97..22175bcdfa2f 100644 --- a/arch/arm64/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm660.dtsi @@ -1016,6 +1016,20 @@ reg = <0xc8c0900 0x4>; }; + clock_debug: qcom,cc-debug@62000 { + compatible = "qcom,gcc-debug-sdm660"; + reg = <0x62000 0x4>; + reg-names = "dbg_offset"; + clocks = <&clock_rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "xo_clk_src"; + qcom,cc-count = <8>; + qcom,gcc = <&clock_gcc>; + qcom,cpu = <&cpu_debug>; + qcom,mmss = <&mmss_debug>; + qcom,gpu = <&gpu_debug>; + #clock-cells = <1>; + }; + generic_bw_opp_table: generic-bw-opp-table { compatible = "operating-points-v2"; BW_OPP_ENTRY( 100, 4); /* 381 MB/s */ -- GitLab From ea416b8116fff16bec432df41651a408cad73b3f Mon Sep 17 00:00:00 2001 From: Lin Bai Date: Fri, 5 Jun 2020 12:15:54 +0800 Subject: [PATCH 0877/1055] cnss2: Add synchronized force wake support Device is still possible to enter low power state with current unsync force wake method, and it may cause later failure when accessing SoC register. Introduce sync force wake API and expose it to WLAN host driver, which will ensure device won't enter low power state after device_wake is asserted. Change-Id: Iaa7a7bdac910c162600bbf03ac97af83b2f68f3f Signed-off-by: Lin Bai --- drivers/net/wireless/cnss2/pci.c | 49 +++++++++++++++++++++++--------- include/net/cnss2.h | 1 + 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 315cb9e310ae..70f6376afd14 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -851,26 +851,22 @@ static int cnss_qca6174_ramdump(struct cnss_pci_data *pci_priv) static int cnss_pci_force_wake_get(struct cnss_pci_data *pci_priv) { struct device *dev = &pci_priv->pci_dev->dev; - u32 timeout = 0; int ret; - ret = cnss_pci_force_wake_request(dev); + ret = cnss_pci_force_wake_request_sync(dev, + FORCE_WAKE_DELAY_TIMEOUT_US); if (ret) { - cnss_pr_err("Failed to request force wake\n"); + if (ret != -EAGAIN) + cnss_pr_err("Failed to request force wake\n"); return ret; } - while (!cnss_pci_is_device_awake(dev) && - timeout <= FORCE_WAKE_DELAY_TIMEOUT_US) { - usleep_range(FORCE_WAKE_DELAY_MIN_US, FORCE_WAKE_DELAY_MAX_US); - timeout += FORCE_WAKE_DELAY_MAX_US; - } - - if (cnss_pci_is_device_awake(dev) != true) { - cnss_pr_err("Timed out to request force wake\n"); - cnss_pci_force_wake_release(dev); - return -ETIMEDOUT; - } + /* If device's M1 state-change event races here, it can be ignored, + * as the device is expected to immediately move from M2 to M0 + * without entering low power state. + */ + if (cnss_pci_is_device_awake(dev) != true) + cnss_pr_warn("MHI not in M0, while reg still accessible\n"); return 0; } @@ -1972,6 +1968,31 @@ int cnss_pm_request_resume(struct cnss_pci_data *pci_priv) return pm_request_resume(&pci_dev->dev); } +int cnss_pci_force_wake_request_sync(struct device *dev, int timeout_us) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev); + struct cnss_plat_data *plat_priv; + struct mhi_controller *mhi_ctrl; + + if (pci_priv->device_id != QCA6390_DEVICE_ID) + return 0; + + mhi_ctrl = pci_priv->mhi_ctrl; + if (!mhi_ctrl) + return -EINVAL; + + plat_priv = pci_priv->plat_priv; + if (!plat_priv) + return -ENODEV; + + if (test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state)) + return -EAGAIN; + + return mhi_device_get_sync_atomic(mhi_ctrl->mhi_dev, timeout_us); +} +EXPORT_SYMBOL(cnss_pci_force_wake_request_sync); + int cnss_pci_force_wake_request(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); diff --git a/include/net/cnss2.h b/include/net/cnss2.h index 0c47377c5586..5ad24a146570 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -225,6 +225,7 @@ extern int cnss_wlan_pm_control(struct device *dev, bool vote); 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); +extern int cnss_pci_force_wake_request_sync(struct device *dev, int timeout); extern int cnss_pci_force_wake_request(struct device *dev); extern int cnss_pci_is_device_awake(struct device *dev); extern int cnss_pci_force_wake_release(struct device *dev); -- GitLab From 98ddb935eaa2b64bc25d130782b928fda1898523 Mon Sep 17 00:00:00 2001 From: Pooja Kumari Date: Tue, 20 Aug 2019 20:05:27 +0530 Subject: [PATCH 0878/1055] msm: ipa3: Send actual DL flt rule to Q6 Currently max length size of DL flt rule is sent to Q6. But 64K memory allocation is always not guranteed. Send actual size of DL flt rule to Q6 to avoid memory error and install flt rule. Change-Id: Id5f7bbb616c23feb6efbacd288f790432156630b Signed-off-by: Pooja Kumari --- .../platform/msm/ipa/ipa_v3/ipa_qmi_service.c | 43 ++++++++++++++++++- .../msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c | 43 ++++++++++--------- 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index c91ba21e7cb7..266734f4ba9f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -790,6 +790,44 @@ int ipa3_qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) resp.resp.error, "ipa_install_filter"); } +static int ipa3_qmi_filter_request_ex_calc_length( + struct ipa_install_fltr_rule_req_ex_msg_v01 *req) +{ + int len = 0; + + /* caller should validate and send the req */ + /* instead of sending max length,the approximate length is calculated */ + len += ((sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01)) - + (QMI_IPA_MAX_FILTERS_EX_V01 * + sizeof(struct ipa_filter_spec_ex_type_v01) - + QMI_IPA_MAX_FILTERS_EX_V01 * sizeof(uint32_t)) - + (QMI_IPA_MAX_FILTERS_V01 * + sizeof(struct ipa_filter_spec_ex2_type_v01))); + + if (req->filter_spec_ex_list_valid && + req->filter_spec_ex_list_len > 0) { + len += sizeof(struct ipa_filter_spec_ex_type_v01)* + req->filter_spec_ex_list_len; + } + if (req->xlat_filter_indices_list_valid && + req->xlat_filter_indices_list_len > 0) { + len += sizeof(uint32_t)*req->xlat_filter_indices_list_len; + } + + if (req->filter_spec_ex2_list_valid && + req->filter_spec_ex2_list_len > 0) { + len += sizeof(struct ipa_filter_spec_ex2_type_v01)* + req->filter_spec_ex2_list_len; + } + + if (req->ul_firewall_indices_list_valid && + req->ul_firewall_indices_list_len > 0) { + len += sizeof(uint32_t)*req->ul_firewall_indices_list_len; + } + + return len; +} + /* sending filter-install-request to modem*/ int ipa3_qmi_filter_request_ex_send( struct ipa_install_fltr_rule_req_ex_msg_v01 *req) @@ -855,8 +893,9 @@ int ipa3_qmi_filter_request_ex_send( } mutex_unlock(&ipa3_qmi_lock); - req_desc.max_msg_len = - QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_MAX_MSG_LEN_V01; + req_desc.max_msg_len = ipa3_qmi_filter_request_ex_calc_length(req); + IPAWANDBG("QMI send request length = %d\n", req_desc.max_msg_len); + req_desc.msg_id = QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_V01; req_desc.ei_array = ipa3_install_fltr_rule_req_ex_msg_data_v01_ei; diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c index 8c53d5df1e6f..688197e26109 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2020, 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 @@ -103,7 +103,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG("device %s got WAN_IOC_ADD_FLT_RULE :>>>\n", DRIVER_NAME); pyld_sz = sizeof(struct ipa_install_fltr_rule_req_msg_v01); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -128,7 +128,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG("device %s got WAN_IOC_ADD_FLT_RULE_EX :>>>\n", DRIVER_NAME); pyld_sz = sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -153,7 +153,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG("device %s got WAN_IOC_ADD_OFFLOAD_CONNECTION :>>>\n", DRIVER_NAME); pyld_sz = sizeof(struct ipa_add_offload_connection_req_msg_v01); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -180,7 +180,7 @@ static long ipa3_wan_ioctl(struct file *filp, DRIVER_NAME); pyld_sz = rmv_offload_req__msg_size; - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -207,7 +207,7 @@ static long ipa3_wan_ioctl(struct file *filp, DRIVER_NAME); pyld_sz = sizeof(struct ipa_configure_ul_firewall_rules_req_msg_v01); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -233,7 +233,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG("device %s got WAN_IOC_ADD_FLT_RULE_INDEX :>>>\n", DRIVER_NAME); pyld_sz = sizeof(struct ipa_fltr_installed_notif_req_msg_v01); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -258,7 +258,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG("device %s got WAN_IOC_VOTE_FOR_BW_MBPS :>>>\n", DRIVER_NAME); pyld_sz = sizeof(uint32_t); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -281,7 +281,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_POLL_TETHERING_STATS: IPAWANDBG_LOW("got WAN_IOCTL_POLL_TETHERING_STATS :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_poll_tethering_stats); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -305,7 +305,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_SET_DATA_QUOTA: IPAWANDBG_LOW("got WAN_IOCTL_SET_DATA_QUOTA :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_set_data_quota); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -333,7 +333,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_SET_TETHER_CLIENT_PIPE: IPAWANDBG_LOW("got WAN_IOC_SET_TETHER_CLIENT_PIPE :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_set_tether_client_pipe); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -353,7 +353,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_QUERY_TETHER_STATS: IPAWANDBG_LOW("got WAN_IOC_QUERY_TETHER_STATS :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_query_tether_stats); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -379,7 +379,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_QUERY_TETHER_STATS_ALL: IPAWANDBG_LOW("got WAN_IOC_QUERY_TETHER_STATS_ALL :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_query_tether_stats_all); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -406,7 +406,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG_LOW("device %s got WAN_IOC_RESET_TETHER_STATS :>>>\n", DRIVER_NAME); pyld_sz = sizeof(struct wan_ioctl_reset_tether_stats); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -428,7 +428,7 @@ static long ipa3_wan_ioctl(struct file *filp, IPAWANDBG_LOW("device %s got WAN_IOC_NOTIFY_WAN_STATE :>>>\n", DRIVER_NAME); pyld_sz = sizeof(struct wan_ioctl_notify_wan_state); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -454,7 +454,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_ENABLE_PER_CLIENT_STATS: IPAWANDBG_LOW("got WAN_IOC_ENABLE_PER_CLIENT_STATS :>>>\n"); pyld_sz = sizeof(bool); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -473,7 +473,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_QUERY_PER_CLIENT_STATS: IPAWANDBG_LOW("got WAN_IOC_QUERY_PER_CLIENT_STATS :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_query_per_client_stats); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -502,7 +502,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_SET_LAN_CLIENT_INFO: IPAWANDBG_LOW("got WAN_IOC_SET_LAN_CLIENT_INFO :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_lan_client_info); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -522,7 +522,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_CLEAR_LAN_CLIENT_INFO: IPAWANDBG_LOW("got WAN_IOC_CLEAR_LAN_CLIENT_INFO :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_lan_client_info); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -543,7 +543,7 @@ static long ipa3_wan_ioctl(struct file *filp, case WAN_IOC_SEND_LAN_CLIENT_MSG: IPAWANDBG_LOW("got WAN_IOC_SEND_LAN_CLIENT_MSG :>>>\n"); pyld_sz = sizeof(struct wan_ioctl_send_lan_client_msg); - param = kzalloc(pyld_sz, GFP_KERNEL); + param = vzalloc(pyld_sz); if (!param) { retval = -ENOMEM; break; @@ -564,7 +564,8 @@ static long ipa3_wan_ioctl(struct file *filp, default: retval = -ENOTTY; } - kfree(param); + if (param) + vfree(param); return retval; } -- GitLab From 19ac881426e70f42bd5eb7fce5083dd900404a7d Mon Sep 17 00:00:00 2001 From: Chetan C R Date: Mon, 23 Mar 2020 19:39:06 +0530 Subject: [PATCH 0879/1055] clk: qcom: Add debug clk support for SDM660 Update MUX_SRC_LIST array values according to clk_src. Fix post_div_offset, cbcr_offset and post_div_shift values. Change-Id: Ia5713f2c5950199e74ddd86d70ccfb55538c99f3 Signed-off-by: Chetan C R Signed-off-by: Ashok Raj D --- drivers/clk/qcom/gcc-sdm660.c | 624 +++++++++++++++++++--------------- 1 file changed, 352 insertions(+), 272 deletions(-) diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c index b922842328db..ecc5b248350e 100644 --- a/drivers/clk/qcom/gcc-sdm660.c +++ b/drivers/clk/qcom/gcc-sdm660.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, 2019-2020, 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 @@ -2974,281 +2974,361 @@ static struct clk_debug_mux gcc_debug_mux = { .priv = &debug_mux_priv, .en_mask = BIT(16), .debug_offset = 0x62000, - .post_div_offset = 0x62004, - .cbcr_offset = 0x62008, + .post_div_offset = 0x62000, + .cbcr_offset = 0x62000, .src_sel_mask = 0x3FF, .src_sel_shift = 0, .post_div_mask = 0xF, - .post_div_shift = 0, - .period_offset = 0x50, + .post_div_shift = 12, MUX_SRC_LIST( - { "snoc_clk", 0x000 }, - { "cnoc_clk", 0x00E }, - { "cnoc_periph_clk", 0x198 }, - { "bimc_clk", 0x19D }, - { "ce1_clk", 0x097 }, - { "ipa_clk", 0x11b }, - { "gcc_aggre2_ufs_axi_clk", 0x10B }, - { "gcc_aggre2_usb3_axi_clk", 0x10A }, - { "gcc_bimc_gfx_clk", 0x0AC }, - { "gcc_bimc_hmss_axi_clk", 0x0BB }, - { "gcc_bimc_mss_q6_axi_clk", 0x0A3 }, - { "gcc_blsp1_ahb_clk", 0x04A }, - { "gcc_blsp1_qup1_i2c_apps_clk", 0x04D }, - { "gcc_blsp1_qup1_spi_apps_clk", 0x04C }, - { "gcc_blsp1_qup2_i2c_apps_clk", 0x051 }, - { "gcc_blsp1_qup2_spi_apps_clk", 0x050 }, - { "gcc_blsp1_qup3_i2c_apps_clk", 0x055 }, - { "gcc_blsp1_qup3_spi_apps_clk", 0x054 }, - { "gcc_blsp1_qup4_i2c_apps_clk", 0x059 }, - { "gcc_blsp1_qup4_spi_apps_clk", 0x058 }, - { "gcc_blsp1_uart1_apps_clk", 0x04E }, - { "gcc_blsp1_uart2_apps_clk", 0x052 }, - { "gcc_blsp2_ahb_clk", 0x05E }, - { "gcc_blsp2_qup1_i2c_apps_clk", 0x061 }, - { "gcc_blsp2_qup1_spi_apps_clk", 0x060 }, - { "gcc_blsp2_qup2_i2c_apps_clk", 0x065 }, - { "gcc_blsp2_qup2_spi_apps_clk", 0x064 }, - { "gcc_blsp2_qup3_i2c_apps_clk", 0x069 }, - { "gcc_blsp2_qup3_spi_apps_clk", 0x068 }, - { "gcc_blsp2_qup4_i2c_apps_clk", 0x06D }, - { "gcc_blsp2_qup4_spi_apps_clk", 0x06C }, - { "gcc_blsp2_uart1_apps_clk", 0x062 }, - { "gcc_blsp2_uart2_apps_clk", 0x066 }, - { "gcc_boot_rom_ahb_clk", 0x07A }, - { "gcc_ce1_ahb_m_clk", 0x099 }, - { "gcc_ce1_axi_m_clk", 0x098 }, - { "gcc_cfg_noc_usb2_axi_clk", 0x168 }, - { "gcc_cfg_noc_usb3_axi_clk", 0x014 }, - { "gcc_dcc_ahb_clk", 0x119 }, - { "gcc_gp1_clk", 0x0DF }, - { "gcc_gp2_clk", 0x0E0 }, - { "gcc_gp3_clk", 0x0E1 }, - { "gcc_gpu_bimc_gfx_clk", 0x13F }, - { "gcc_gpu_cfg_ahb_clk", 0x13B }, - { "gcc_hmss_dvm_bus_clk", 0x0BF }, - { "gcc_hmss_rbcpr_clk", 0x0BC }, - { "gcc_mmss_noc_cfg_ahb_clk", 0x020 }, - { "gcc_mmss_sys_noc_axi_clk", 0x01F }, - { "gcc_mss_cfg_ahb_clk", 0x11F }, - { "gcc_mss_mnoc_bimc_axi_clk", 0x120 }, - { "gcc_mss_q6_bimc_axi_clk", 0x124 }, - { "gcc_mss_snoc_axi_clk", 0x123 }, - { "gcc_pdm2_clk", 0x074 }, - { "gcc_pdm_ahb_clk", 0x072 }, - { "gcc_prng_ahb_clk", 0x075 }, - { "gcc_qspi_ahb_clk", 0x172 }, - { "gcc_qspi_ser_clk", 0x173 }, - { "gcc_sdcc1_ahb_clk", 0x16E }, - { "gcc_sdcc1_apps_clk", 0x16D }, - { "gcc_sdcc1_ice_core_clk", 0x16F }, - { "gcc_sdcc2_ahb_clk", 0x047 }, - { "gcc_sdcc2_apps_clk", 0x046 }, - { "gcc_ufs_ahb_clk", 0x0EB }, - { "gcc_ufs_axi_clk", 0x0EA }, - { "gcc_ufs_ice_core_clk", 0x0F1 }, - { "gcc_ufs_phy_aux_clk", 0x0F2 }, - { "gcc_ufs_unipro_core_clk", 0x0F0 }, - { "gcc_usb20_master_clk", 0x169 }, - { "gcc_usb20_mock_utmi_clk", 0x16B }, - { "gcc_usb20_sleep_clk", 0x16A }, - { "gcc_usb30_master_clk", 0x03C }, - { "gcc_usb30_mock_utmi_clk", 0x03E }, - { "gcc_usb30_sleep_clk", 0x03D }, - { "gcc_usb3_phy_aux_clk", 0x03F }, - { "gcc_usb_phy_cfg_ahb2phy_clk", 0x045 }, - { "gcc_ufs_rx_symbol_0_clk", 0x0ED }, - { "gcc_ufs_rx_symbol_1_clk", 0x162 }, - { "gcc_ufs_tx_symbol_0_clk", 0x0EC }, - { "gcc_usb3_phy_pipe_clk", 0x040 }, - { "mmssnoc_axi_clk", 0x22, CAM_CC, - 0x004, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_bimc_smmu_ahb_clk", 0x22, CAM_CC, - 0x00C, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_bimc_smmu_axi_clk", 0x22, CAM_CC, - 0x00D, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_ahb_clk", 0x22, CAM_CC, - 0x037, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cci_ahb_clk", 0x22, CAM_CC, - 0x02E, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cci_clk", 0x22, CAM_CC, - 0x02D, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cphy_csid0_clk", 0x22, CAM_CC, - 0x08D, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cphy_csid1_clk", 0x22, CAM_CC, - 0x08E, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cphy_csid2_clk", 0x22, CAM_CC, - 0x08F, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cphy_csid3_clk", 0x22, CAM_CC, - 0x090, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cpp_ahb_clk", 0x22, CAM_CC, - 0x03B, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cpp_axi_clk", 0x22, CAM_CC, - 0x07A, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cpp_clk", 0x22, CAM_CC, - 0x03A, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_cpp_vbif_ahb_clk", 0x22, CAM_CC, - 0x073, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi0_ahb_clk", 0x22, CAM_CC, - 0x042, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi0_clk", 0x22, CAM_CC, - 0x041, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi0phytimer_clk", 0x22, CAM_CC, - 0x02F, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi0pix_clk", 0x22, CAM_CC, - 0x045, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi0rdi_clk", 0x22, CAM_CC, - 0x044, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi1_ahb_clk", 0x22, CAM_CC, - 0x047, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi1_clk", 0x22, CAM_CC, - 0x046, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi1phytimer_clk", 0x22, CAM_CC, - 0x030, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi1pix_clk", 0x22, CAM_CC, - 0x04A, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi1rdi_clk", 0x22, CAM_CC, - 0x049, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi2_ahb_clk", 0x22, CAM_CC, - 0x04C, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi2_clk", 0x22, CAM_CC, - 0x04B, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi2phytimer_clk", 0x22, CAM_CC, - 0x031, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi2pix_clk", 0x22, CAM_CC, - 0x04F, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi2rdi_clk", 0x22, CAM_CC, - 0x04E, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi3_ahb_clk", 0x22, CAM_CC, - 0x051, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi3_clk", 0x22, CAM_CC, - 0x050, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi3pix_clk", 0x22, CAM_CC, - 0x054, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi3rdi_clk", 0x22, CAM_CC, - 0x053, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi_vfe0_clk", 0x22, CAM_CC, - 0x03F, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csi_vfe1_clk", 0x22, CAM_CC, - 0x040, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csiphy0_clk", 0x22, CAM_CC, - 0x043, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csiphy1_clk", 0x22, CAM_CC, - 0x085, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_csiphy2_clk", 0x22, CAM_CC, - 0x088, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_gp0_clk", 0x22, CAM_CC, - 0x027, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_gp1_clk", 0x22, CAM_CC, - 0x028, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_ispif_ahb_clk", 0x22, CAM_CC, - 0x033, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_jpeg0_clk", 0x22, CAM_CC, - 0x032, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_jpeg_ahb_clk", 0x22, CAM_CC, - 0x035, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_jpeg_axi_clk", 0x22, CAM_CC, - 0x036, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_mclk0_clk", 0x22, CAM_CC, - 0x029, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_mclk1_clk", 0x22, CAM_CC, - 0x02A, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_mclk2_clk", 0x22, CAM_CC, - 0x02B, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_mclk3_clk", 0x22, CAM_CC, - 0x02C, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_micro_ahb_clk", 0x22, CAM_CC, - 0x026, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_top_ahb_clk", 0x22, CAM_CC, - 0x025, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe0_ahb_clk", 0x22, CAM_CC, - 0x086, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe0_clk", 0x22, CAM_CC, - 0x038, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe0_stream_clk", 0x22, CAM_CC, - 0x071, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe1_ahb_clk", 0x22, CAM_CC, - 0x087, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe1_clk", 0x22, CAM_CC, - 0x039, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe1_stream_clk", 0x22, CAM_CC, - 0x072, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe_vbif_ahb_clk", 0x22, CAM_CC, - 0x03C, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_camss_vfe_vbif_axi_clk", 0x22, CAM_CC, - 0x03D, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_csiphy_ahb2crif_clk", 0x22, CAM_CC, - 0x0B8, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_ahb_clk", 0x22, CAM_CC, - 0x022, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_axi_clk", 0x22, CAM_CC, - 0x024, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_byte0_clk", 0x22, CAM_CC, - 0x01E, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_byte0_intf_clk", 0x22, CAM_CC, - 0x0AD, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_byte1_clk", 0x22, CAM_CC, - 0x01F, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_byte1_intf_clk", 0x22, CAM_CC, - 0x0B6, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_dp_aux_clk", 0x22, CAM_CC, - 0x09C, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_dp_crypto_clk", 0x22, CAM_CC, - 0x09A, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_dp_gtc_clk", 0x22, CAM_CC, - 0x09D, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_dp_link_clk", 0x22, CAM_CC, - 0x098, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_dp_link_intf_clk", 0x22, CAM_CC, - 0x099, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_dp_pixel_clk", 0x22, CAM_CC, - 0x09B, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_esc0_clk", 0x22, CAM_CC, - 0x020, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_esc1_clk", 0x22, CAM_CC, - 0x021, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_hdmi_dp_ahb_clk", 0x22, CAM_CC, - 0x023, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_mdp_clk", 0x22, CAM_CC, - 0x014, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_pclk0_clk", 0x22, CAM_CC, - 0x016, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_pclk1_clk", 0x22, CAM_CC, - 0x017, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_rot_clk", 0x22, CAM_CC, - 0x012, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mdss_vsync_clk", 0x22, CAM_CC, - 0x01C, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_misc_ahb_clk", 0x22, CAM_CC, - 0x003, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_misc_cxo_clk", 0x22, CAM_CC, - 0x077, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_mnoc_ahb_clk", 0x22, CAM_CC, - 0x001, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_snoc_dvm_axi_clk", 0x22, CAM_CC, - 0x013, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_video_ahb_clk", 0x22, CAM_CC, - 0x011, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_video_axi_clk", 0x22, CAM_CC, - 0x00F, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_video_core_clk", 0x22, CAM_CC, - 0x00E, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_video_subcore0_clk", 0x22, CAM_CC, - 0x01A, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_throttle_camss_axi_clk", 0x22, CAM_CC, - 0x0AA, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_throttle_mdss_axi_clk", 0x22, CAM_CC, - 0x0AB, 0, 0, 0x1000, BM(14, 13) }, - { "mmss_throttle_video_axi_clk", 0x22, CAM_CC, - 0x0AC, 0, 0, 0x1000, BM(14, 13) }, - { "gpucc_gfx3d_clk", 0x13d, GPU_CC, - 0x008, 0, 0, 0, BM(18, 17) }, - { "gpucc_rbbmtimer_clk", 0x13d, GPU_CC, - 0x005, 0, 0, 0, BM(18, 17) }, - { "gpucc_rbcpr_clk", 0x13d, GPU_CC, - 0x003, 0, 0, 0, BM(18, 17) }, - { "pwrcl_clk", 0x0c0, CPU_CC, 0x000, 0x3, 8, 0x0FF }, - { "perfcl_clk", 0x0c0, CPU_CC, 0x100, 0x3, 8, 0x0FF }, + { "snoc_clk", 0x000, 1, GCC, 0x000, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "cnoc_clk", 0x00E, 1, GCC, 0x00E, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "cnoc_periph_clk", 0x198, 1, GCC, 0x198, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "bimc_clk", 0x19D, 1, GCC, 0x19D, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "ce1_clk", 0x097, 1, GCC, 0x097, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "ipa_clk", 0x11b, 1, GCC, 0x11b, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_aggre2_ufs_axi_clk", 0x10B, 1, GCC, 0x10B, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_aggre2_usb3_axi_clk", 0x10A, 1, GCC, 0x10A, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_bimc_gfx_clk", 0x0AC, 1, GCC, 0x0AC, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_bimc_hmss_axi_clk", 0x0BB, 1, GCC, 0x0BB, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_bimc_mss_q6_axi_clk", 0x0A3, 1, GCC, 0x0A3, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_ahb_clk", 0x04A, 1, GCC, 0x04A, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup1_i2c_apps_clk", 0x04D, 1, GCC, 0x04D, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup1_spi_apps_clk", 0x04C, 1, GCC, 0x04C, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup2_i2c_apps_clk", 0x051, 1, GCC, 0x051, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup2_spi_apps_clk", 0x050, 1, GCC, 0x050, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup3_i2c_apps_clk", 0x055, 1, GCC, 0x055, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup3_spi_apps_clk", 0x054, 1, GCC, 0x054, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup4_i2c_apps_clk", 0x059, 1, GCC, 0x059, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_qup4_spi_apps_clk", 0x058, 1, GCC, 0x058, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_uart1_apps_clk", 0x04E, 1, GCC, 0x04E, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp1_uart2_apps_clk", 0x052, 1, GCC, 0x052, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_ahb_clk", 0x05E, 1, GCC, 0x05E, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup1_i2c_apps_clk", 0x061, 1, GCC, 0x061, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup1_spi_apps_clk", 0x060, 1, GCC, 0x060, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup2_i2c_apps_clk", 0x065, 1, GCC, 0x065, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup2_spi_apps_clk", 0x064, 1, GCC, 0x064, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup3_i2c_apps_clk", 0x069, 1, GCC, 0x069, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup3_spi_apps_clk", 0x068, 1, GCC, 0x068, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup4_i2c_apps_clk", 0x06D, 1, GCC, 0x06D, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_qup4_spi_apps_clk", 0x06C, 1, GCC, 0x06C, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_uart1_apps_clk", 0x062, 1, GCC, 0x062, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_blsp2_uart2_apps_clk", 0x066, 1, GCC, 0x066, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_boot_rom_ahb_clk", 0x07A, 1, GCC, 0x07A, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ce1_ahb_m_clk", 0x099, 1, GCC, 0x099, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ce1_axi_m_clk", 0x098, 1, GCC, 0x098, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_cfg_noc_usb2_axi_clk", 0x168, 1, GCC, 0x168, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_cfg_noc_usb3_axi_clk", 0x014, 1, GCC, 0x014, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_dcc_ahb_clk", 0x119, 1, GCC, 0x119, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_gp1_clk", 0x0DF, 1, GCC, 0x0DF, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_gp2_clk", 0x0E0, 1, GCC, 0x0E0, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_gp3_clk", 0x0E1, 1, GCC, 0x0E1, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_gpu_bimc_gfx_clk", 0x13F, 1, GCC, 0x13F, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_gpu_cfg_ahb_clk", 0x13B, 1, GCC, 0x13B, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_hmss_dvm_bus_clk", 0x0BF, 1, GCC, 0x0BF, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_hmss_rbcpr_clk", 0x0BC, 1, GCC, 0x0BC, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_mmss_noc_cfg_ahb_clk", 0x020, 1, GCC, 0x020, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_mmss_sys_noc_axi_clk", 0x01F, 1, GCC, 0x01F, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_mss_cfg_ahb_clk", 0x11F, 1, GCC, 0x11F, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_mss_mnoc_bimc_axi_clk", 0x120, 1, GCC, 0x120, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_mss_q6_bimc_axi_clk", 0x124, 1, GCC, 0x124, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_mss_snoc_axi_clk", 0x123, 1, GCC, 0x123, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_pdm2_clk", 0x074, 1, GCC, 0x074, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_pdm_ahb_clk", 0x072, 1, GCC, 0x072, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_prng_ahb_clk", 0x075, 1, GCC, 0x075, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_qspi_ahb_clk", 0x172, 1, GCC, 0x172, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_qspi_ser_clk", 0x173, 1, GCC, 0x173, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_sdcc1_ahb_clk", 0x16E, 1, GCC, 0x16E, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_sdcc1_apps_clk", 0x16D, 1, GCC, 0x16D, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_sdcc1_ice_core_clk", 0x16F, 1, GCC, 0x16F, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_sdcc2_ahb_clk", 0x047, 1, GCC, 0x047, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_sdcc2_apps_clk", 0x046, 1, GCC, 0x046, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_ahb_clk", 0x0EB, 1, GCC, 0x0EB, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_axi_clk", 0x0EA, 1, GCC, 0x0EA, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_ice_core_clk", 0x0F1, 1, GCC, 0x0F1, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_phy_aux_clk", 0x0F2, 1, GCC, 0x0F2, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_unipro_core_clk", 0x0F0, 1, GCC, 0x0F0, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb20_master_clk", 0x169, 1, GCC, 0x169, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb20_mock_utmi_clk", 0x16B, 1, GCC, 0x16B, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb20_sleep_clk", 0x16A, 1, GCC, 0x16A, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb30_master_clk", 0x03C, 1, GCC, 0x03C, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb30_mock_utmi_clk", 0x03E, 1, GCC, 0x03E, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb30_sleep_clk", 0x03D, 1, GCC, 0x03D, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb3_phy_aux_clk", 0x03F, 1, GCC, 0x03F, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb_phy_cfg_ahb2phy_clk", 0x045, 1, GCC, 0x045, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_rx_symbol_0_clk", 0x0ED, 1, GCC, 0x0ED, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_rx_symbol_1_clk", 0x162, 1, GCC, 0x162, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_ufs_tx_symbol_0_clk", 0x0EC, 1, GCC, 0x0EC, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "gcc_usb3_phy_pipe_clk", 0x040, 1, GCC, 0x040, + 0x3FF, 0, 0xF, 12, 1, 0x62000, 0x62000, 0x62000 }, + { "mmssnoc_axi_clk", 0x22, 1, CAM_CC, 0x004, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_bimc_smmu_ahb_clk", 0x22, 1, CAM_CC, 0x00C, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_bimc_smmu_axi_clk", 0x22, 1, CAM_CC, 0x00D, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_ahb_clk", 0x22, 1, CAM_CC, 0x037, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cci_ahb_clk", 0x22, 1, CAM_CC, 0x02E, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cci_clk", 0x22, 1, CAM_CC, 0x02D, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cphy_csid0_clk", 0x22, 1, CAM_CC, 0x08D, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cphy_csid1_clk", 0x22, 1, CAM_CC, 0x08E, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cphy_csid2_clk", 0x22, 1, CAM_CC, 0x08F, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cphy_csid3_clk", 0x22, 1, CAM_CC, 0x090, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cpp_ahb_clk", 0x22, 1, CAM_CC, 0x03B, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cpp_axi_clk", 0x22, 1, CAM_CC, 0x07A, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cpp_clk", 0x22, 1, CAM_CC, 0x03A, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_cpp_vbif_ahb_clk", 0x22, 1, CAM_CC, 0x073, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi0_ahb_clk", 0x22, 1, CAM_CC, 0x042, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi0_clk", 0x22, 1, CAM_CC, 0x041, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi0phytimer_clk", 0x22, 1, CAM_CC, 0x02F, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi0pix_clk", 0x22, 1, CAM_CC, 0x045, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi0rdi_clk", 0x22, 1, CAM_CC, 0x044, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi1_ahb_clk", 0x22, 1, CAM_CC, 0x047, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi1_clk", 0x22, 1, CAM_CC, 0x046, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi1phytimer_clk", 0x22, 1, CAM_CC, 0x030, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi1pix_clk", 0x22, 1, CAM_CC, 0x04A, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi1rdi_clk", 0x22, 1, CAM_CC, 0x049, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi2_ahb_clk", 0x22, 1, CAM_CC, 0x04C, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi2_clk", 0x22, 1, CAM_CC, 0x04B, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi2phytimer_clk", 0x22, 1, CAM_CC, 0x031, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi2pix_clk", 0x22, 1, CAM_CC, 0x04F, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi2rdi_clk", 0x22, 1, CAM_CC, 0x04E, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi3_ahb_clk", 0x22, 1, CAM_CC, 0x051, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi3_clk", 0x22, 1, CAM_CC, 0x050, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi3pix_clk", 0x22, 1, CAM_CC, 0x054, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi3rdi_clk", 0x22, 1, CAM_CC, 0x053, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi_vfe0_clk", 0x22, 1, CAM_CC, 0x03F, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csi_vfe1_clk", 0x22, 1, CAM_CC, 0x040, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csiphy0_clk", 0x22, 1, CAM_CC, 0x043, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csiphy1_clk", 0x22, 1, CAM_CC, 0x085, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_csiphy2_clk", 0x22, 1, CAM_CC, 0x088, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_gp0_clk", 0x22, 1, CAM_CC, 0x027, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_gp1_clk", 0x22, 1, CAM_CC, 0x028, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_ispif_ahb_clk", 0x22, 1, CAM_CC, 0x033, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_jpeg0_clk", 0x22, 1, CAM_CC, 0x032, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_jpeg_ahb_clk", 0x22, 1, CAM_CC, 0x035, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_jpeg_axi_clk", 0x22, 1, CAM_CC, 0x036, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_mclk0_clk", 0x22, 1, CAM_CC, 0x029, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_mclk1_clk", 0x22, 1, CAM_CC, 0x02A, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_mclk2_clk", 0x22, 1, CAM_CC, 0x02B, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_mclk3_clk", 0x22, 1, CAM_CC, 0x02C, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_micro_ahb_clk", 0x22, 1, CAM_CC, 0x026, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_top_ahb_clk", 0x22, 1, CAM_CC, 0x025, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe0_ahb_clk", 0x22, 1, CAM_CC, 0x086, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe0_clk", 0x22, 1, CAM_CC, 0x038, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe0_stream_clk", 0x22, 1, CAM_CC, 0x071, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe1_ahb_clk", 0x22, 1, CAM_CC, 0x087, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe1_clk", 0x22, 1, CAM_CC, 0x039, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe1_stream_clk", 0x22, 1, CAM_CC, 0x072, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe_vbif_ahb_clk", 0x22, 1, CAM_CC, 0x03C, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_camss_vfe_vbif_axi_clk", 0x22, 1, CAM_CC, 0x03D, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_csiphy_ahb2crif_clk", 0x22, 1, CAM_CC, 0x0B8, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_ahb_clk", 0x22, 1, CAM_CC, 0x022, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_axi_clk", 0x22, 1, CAM_CC, 0x024, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_byte0_clk", 0x22, 1, CAM_CC, 0x01E, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_byte0_intf_clk", 0x22, 1, CAM_CC, 0x0AD, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_byte1_clk", 0x22, 1, CAM_CC, 0x01F, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_byte1_intf_clk", 0x22, 1, CAM_CC, 0x0B6, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_dp_aux_clk", 0x22, 1, CAM_CC, 0x09C, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_dp_crypto_clk", 0x22, 1, CAM_CC, 0x09A, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_dp_gtc_clk", 0x22, 1, CAM_CC, 0x09D, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_dp_link_clk", 0x22, 1, CAM_CC, 0x098, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_dp_link_intf_clk", 0x22, 1, CAM_CC, 0x099, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_dp_pixel_clk", 0x22, 1, CAM_CC, 0x09B, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_esc0_clk", 0x22, 1, CAM_CC, 0x020, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_esc1_clk", 0x22, 1, CAM_CC, 0x021, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_hdmi_dp_ahb_clk", 0x22, 1, CAM_CC, 0x023, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_mdp_clk", 0x22, 1, CAM_CC, 0x014, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_pclk0_clk", 0x22, 1, CAM_CC, 0x016, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_pclk1_clk", 0x22, 1, CAM_CC, 0x017, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_rot_clk", 0x22, 1, CAM_CC, 0x012, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mdss_vsync_clk", 0x22, 1, CAM_CC, 0x01C, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_misc_ahb_clk", 0x22, 1, CAM_CC, 0x003, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_misc_cxo_clk", 0x22, 1, CAM_CC, 0x077, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_mnoc_ahb_clk", 0x22, 1, CAM_CC, 0x001, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_snoc_dvm_axi_clk", 0x22, 1, CAM_CC, 0x013, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_video_ahb_clk", 0x22, 1, CAM_CC, 0x011, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_video_axi_clk", 0x22, 1, CAM_CC, 0x00F, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_video_core_clk", 0x22, 1, CAM_CC, 0x00E, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_video_subcore0_clk", 0x22, 1, CAM_CC, 0x01A, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_throttle_camss_axi_clk", 0x22, 1, CAM_CC, 0x0AA, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_throttle_mdss_axi_clk", 0x22, 1, CAM_CC, 0x0AB, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "mmss_throttle_video_axi_clk", 0x22, 1, CAM_CC, 0x0AC, + 0x1FF, 0, 0, 0, 0, 0, 0, U32_MAX, 1 }, + { "gpucc_gfx3d_clk", 0x13d, 1, GPU_CC, 0x008, + 0xF, 0, 0, 0, 0, 0, 0, 0x10000, 1 }, + { "gpucc_rbbmtimer_clk", 0x13d, 1, GPU_CC, 0x005, + 0xF, 0, 0, 0, 0, 0, 0, 0x10000, 1 }, + { "gpucc_rbcpr_clk", 0x13d, 1, GPU_CC, 0x003, + 0xF, 0, 0, 0, 0, 0, 0, 0x10000, 1 }, + { "pwrcl_clk", 0x0c0, 1, CPU_CC, 0x000, + 0x3, 8, 0xF, 11, 1, 0, 0, U32_MAX, 1 }, + { "perfcl_clk", 0x0c0, 1, CPU_CC, 0x001, + 0x3, 8, 0xF, 11, 1, 0, 0, U32_MAX, 1 }, ), .hw.init = &(struct clk_init_data){ .name = "gcc_debug_mux", -- GitLab From f1741950ebfddaf1b097b66c79cf5a12a75c56c1 Mon Sep 17 00:00:00 2001 From: Rahul Shahare Date: Thu, 30 Apr 2020 09:57:02 +0530 Subject: [PATCH 0880/1055] defconfig: trinket: Enable dm-snapshot To support virtual A/B feature, set CONFIG_DM_SNAPSHOT to enable dm-snapshot. Change-Id: I2f285a6059ad9e1c1992d1ed182d85d90f8fdbd4 Signed-off-by: Rahul Shahare --- arch/arm64/configs/vendor/trinket-perf_defconfig | 1 + arch/arm64/configs/vendor/trinket_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/trinket-perf_defconfig b/arch/arm64/configs/vendor/trinket-perf_defconfig index 4ec93eb1019a..74a054f6473d 100644 --- a/arch/arm64/configs/vendor/trinket-perf_defconfig +++ b/arch/arm64/configs/vendor/trinket-perf_defconfig @@ -283,6 +283,7 @@ CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y CONFIG_DM_DEFAULT_KEY=y +CONFIG_DM_SNAPSHOT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y diff --git a/arch/arm64/configs/vendor/trinket_defconfig b/arch/arm64/configs/vendor/trinket_defconfig index 54a087e1c4bb..0e05ff519201 100644 --- a/arch/arm64/configs/vendor/trinket_defconfig +++ b/arch/arm64/configs/vendor/trinket_defconfig @@ -294,6 +294,7 @@ CONFIG_MD=y CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y CONFIG_DM_DEFAULT_KEY=y +CONFIG_DM_SNAPSHOT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y CONFIG_DM_VERITY_FEC=y -- GitLab From c889450c443471f95f2052ec551f4deafc59ca3a Mon Sep 17 00:00:00 2001 From: Ajay Prathi Date: Thu, 9 Apr 2020 11:01:45 +0530 Subject: [PATCH 0881/1055] msm: sps: SPS driver changes for dummy BAM connect Added a flag (SPS_O_DUMMY_PEER) set by client, based on the flag , passed destination and destination pipe index values as peer bam values and bypassed checks related to destination bam as IPA bam is not present in this use case, to support dummy bam connection from QDSS to IPA. Change-Id: I459b89cacc76c6f9443a9a1dbe9540d78bd948fa Signed-off-by: Ajay Prathi --- drivers/platform/msm/sps/bam.c | 11 ++++++++--- drivers/platform/msm/sps/bam.h | 3 ++- drivers/platform/msm/sps/sps_bam.c | 28 ++++++++++++++++++++-------- drivers/platform/msm/sps/sps_rm.c | 25 +++++++++++++++---------- include/linux/msm-sps.h | 4 +++- 5 files changed, 48 insertions(+), 23 deletions(-) diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c index c9c52f76b9fb..c2b2137185b8 100644 --- a/drivers/platform/msm/sps/bam.c +++ b/drivers/platform/msm/sps/bam.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, 2020, 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 @@ -1388,8 +1388,13 @@ int bam_pipe_init(void *base, u32 pipe, struct bam_pipe_parameters *param, bam_write_reg_field(base, P_FIFO_SIZES, pipe, P_DATA_FIFO_SIZE, param->data_size); - bam_write_reg(base, P_EVNT_DEST_ADDR, pipe, peer_dest_addr); - + if (!(param->dummy_peer)) { + bam_write_reg(base, P_EVNT_DEST_ADDR, pipe, + peer_dest_addr); + } else { + bam_write_reg(base, P_EVNT_DEST_ADDR, pipe, + param->peer_phys_addr); + } SPS_DBG2(dev, "sps:bam=0x%pK(va).pipe=%d.peer_bam=0x%x.peer_pipe=%d.\n", dev->base, pipe, diff --git a/drivers/platform/msm/sps/bam.h b/drivers/platform/msm/sps/bam.h index c0e4cde35cba..60fdbff37901 100644 --- a/drivers/platform/msm/sps/bam.h +++ b/drivers/platform/msm/sps/bam.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, 2020, 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 @@ -83,6 +83,7 @@ struct bam_pipe_parameters { u32 peer_pipe; phys_addr_t data_base; /* Physical address of data FIFO */ u32 data_size; /* Size (bytes) of data FIFO */ + bool dummy_peer; }; /** diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c index 92359c202102..68f4e3e91c90 100644 --- a/drivers/platform/msm/sps/sps_bam.c +++ b/drivers/platform/msm/sps/sps_bam.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, 2019-2020, 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 @@ -875,13 +875,15 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, } /* Determine operational mode */ - if (other_pipe->bam != NULL) { + if ((bam_pipe->connect.options & SPS_O_DUMMY_PEER) || + other_pipe->bam != NULL) { unsigned long iova; - struct sps_bam *peer_bam = (struct sps_bam *)(other_pipe->bam); + struct sps_bam *peer_bam; /* BAM-to-BAM mode */ bam_pipe->state |= BAM_STATE_BAM2BAM; hw_params.mode = BAM_PIPE_MODE_BAM2BAM; - + if (!(bam_pipe->connect.options & SPS_O_DUMMY_PEER)) + peer_bam = (struct sps_bam *)(other_pipe->bam); if (dev->props.options & SPS_BAM_SMMU_EN) { if (bam_pipe->mode == SPS_MODE_SRC) iova = bam_pipe->connect.dest_iova; @@ -892,11 +894,21 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, BAM_ID(dev), pipe_index, (void *)iova); hw_params.peer_phys_addr = (u32)iova; } else { - hw_params.peer_phys_addr = peer_bam->props.phys_addr; + if (!(bam_pipe->connect.options & SPS_O_DUMMY_PEER)) + hw_params.peer_phys_addr = + peer_bam->props.phys_addr; + } + if (!(bam_pipe->connect.options & SPS_O_DUMMY_PEER)) { + hw_params.peer_phys_addr = + bam_pipe->connect.destination; + hw_params.peer_pipe = + bam_pipe->connect.dest_pipe_index; + } else { + hw_params.peer_phys_addr = + bam_pipe->connect.destination; + hw_params.peer_pipe = other_pipe->pipe_index; + hw_params.dummy_peer = true; } - - hw_params.peer_pipe = other_pipe->pipe_index; - /* Verify FIFO buffers are allocated for BAM-to-BAM pipes */ if (map->desc.phys_base == SPS_ADDR_INVALID || map->data.phys_base == SPS_ADDR_INVALID || diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c index 593fbc1def4b..3ee057a5b7b9 100644 --- a/drivers/platform/msm/sps/sps_rm.c +++ b/drivers/platform/msm/sps/sps_rm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, 2017-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, 2017-2020, 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 @@ -402,16 +402,20 @@ static struct sps_connection *sps_rm_create(struct sps_pipe *pipe) (void *)(&map->src.dev)); goto exit_err; } - map->src.pipe_index = SPS_BAM_PIPE_INVALID; + map->src.pipe_index = SPS_BAM_PIPE_INVALID; } - map->dest.bam = sps_h2bam(map->dest.dev); - if (map->dest.bam == NULL) { - if (map->dest.dev != SPS_DEV_HANDLE_MEM) { - SPS_ERR(sps, "sps:Invalid BAM handle: %pK", - (void *)(&map->dest.dev)); - goto exit_err; - } + + if (!(pipe->connect.options & SPS_O_DUMMY_PEER)) { + map->dest.bam = sps_h2bam(map->dest.dev); + if (map->dest.bam == NULL) { + if (map->dest.dev != SPS_DEV_HANDLE_MEM) { + SPS_ERR(sps, + "sps:Invalid BAM handle: %pK", + (void *)(&map->dest.dev)); + goto exit_err; + } map->dest.pipe_index = SPS_BAM_PIPE_INVALID; + } } /* Check the BAM device for the pipe */ @@ -504,7 +508,8 @@ static struct sps_connection *sps_rm_create(struct sps_pipe *pipe) if (map->data.size == SPSRM_CLEAR) map->data.size = data_size; } else { - map->data.size = 0; + if (!(pipe->connect.options & SPS_O_DUMMY_PEER)) + map->data.size = 0; } if (map->desc.size > SPSRM_MAX_DESC_FIFO_SIZE) { SPS_ERR(sps, "sps:Invalid desc FIFO size: 0x%x", diff --git a/include/linux/msm-sps.h b/include/linux/msm-sps.h index 719f79d50252..5002cbd00d21 100644 --- a/include/linux/msm-sps.h +++ b/include/linux/msm-sps.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2017, 2020, 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 @@ -211,6 +211,8 @@ enum sps_option { SPS_O_NO_EP_SYNC = 0x40000000, /* Allow partial polling duing IRQ mode */ SPS_O_HYBRID = 0x80000000, + /* Allow dummy BAM connection */ + SPS_O_DUMMY_PEER = 0x00000400, }; /** -- GitLab From 72b25c6555008928559661c60b8ed637bc4d97f7 Mon Sep 17 00:00:00 2001 From: Santosh Dronamraju Date: Fri, 19 Jun 2020 14:38:35 +0530 Subject: [PATCH 0882/1055] firmware: qcom: Reinitialize the ring buffer log pointer restore callback function will reinitialize the ring buffer log pointer during restoration from hibernation. Change-Id: I74b4892a9214b74fc70e561982d2f6df17191492 Signed-off-by: Santosh Dronamraju --- drivers/firmware/qcom/tz_log.c | 42 ++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/qcom/tz_log.c b/drivers/firmware/qcom/tz_log.c index f8d3dd338506..f0887b823b84 100644 --- a/drivers/firmware/qcom/tz_log.c +++ b/drivers/firmware/qcom/tz_log.c @@ -328,6 +328,7 @@ static struct tzdbg tzdbg = { static struct tzdbg_log_t *g_qsee_log; static dma_addr_t coh_pmem; static uint32_t debug_rw_buf_size; +static bool restore_from_hibernation; /* * Debugfs data structure and functions @@ -718,6 +719,15 @@ static int _disp_tz_log_stats(size_t count) { static struct tzdbg_log_pos_t log_start = {0}; struct tzdbg_log_t *log_ptr; + /* wrap and offset are initialized to zero since tz is coldboot + * during restoration from hibernation.the reason to initialise + * the wrap and offset to zero since it contains previous boot + * values and which are invalid now. + */ + if (restore_from_hibernation) { + log_start.wrap = log_start.offset = 0; + return 0; + } log_ptr = (struct tzdbg_log_t *)((unsigned char *)tzdbg.diag_buf + tzdbg.diag_buf->ring_off - @@ -743,6 +753,16 @@ static int _disp_qsee_log_stats(size_t count) { static struct tzdbg_log_pos_t log_start = {0}; + /* wrap and offset are initialized to zero since tz is coldboot + * during restoration from hibernation. The reason to initialise + * the wrap and offset to zero since it contains previous values + * and which are invalid now. + */ + if (restore_from_hibernation) { + log_start.wrap = log_start.offset = 0; + return 0; + } + return _disp_log_stats(g_qsee_log, &log_start, QSEE_LOG_BUF_SIZE - sizeof(struct tzdbg_log_pos_t), count, TZDBG_QSEE_LOG); @@ -1144,20 +1164,34 @@ static int tz_log_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int tz_log_freeze(struct device *dev) { - dma_free_coherent(dev, QSEE_LOG_BUF_SIZE, (void *)g_qsee_log, - coh_pmem); - + /* This Boolean variable is maintained to initialise the ring buffer + * log pointer to zero during restoration from hibernation + */ + restore_from_hibernation = 1; + if (g_qsee_log) + dma_free_coherent(dev, QSEE_LOG_BUF_SIZE, (void *)g_qsee_log, + coh_pmem); return 0; } static int tz_log_restore(struct device *dev) { + /* ring buffer log pointer needs to be re initialized + * during restoration from hibernation. + */ + if (restore_from_hibernation) { + _disp_tz_log_stats(0); + _disp_qsee_log_stats(0); + } /* Register the log bugger at TZ during hibernation resume. * After hibernation the log buffer is with HLOS as TZ encountered * a coldboot sequence. */ tzdbg_register_qsee_log_buf(to_platform_device(dev)); - + /* This is set back to zero after successful restoration + * from hibernation. + */ + restore_from_hibernation = 0; return 0; } -- GitLab From 6a8aa76d87611da58caf9bb634398688bc96ea6a Mon Sep 17 00:00:00 2001 From: Vikram Sharma Date: Thu, 21 May 2020 21:43:42 +0530 Subject: [PATCH 0883/1055] msm: camera: isp: Flush Pending list after stop HW to avoid race If pending list is flushed before IFE/CSID HW stop there might be a scenario where on buf done for bubble request comes and req moves back to pending list. This race will result in req stuck in pending list This change takes care of that race by flushing pending list after hw stop. CRs-Fixed: 2691467 Change-Id: Ice09b9d044acc19ef5143c96fd7e262dc41bb58a Signed-off-by: Vikram Sharma --- .../platform/msm/camera/cam_isp/cam_isp_context.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index f855ad1b498e..e575495a1635 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -2527,13 +2527,20 @@ static int __cam_isp_ctx_flush_req_in_top_state( if (rc) goto end; + /* + * As HW is stopped already No request will move from + * one list to other good time to flush reqs. + */ spin_lock_bh(&ctx->lock); + CAM_DBG(CAM_ISP, "try to flush pending list"); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, + flush_req); CAM_DBG(CAM_ISP, "try to flush wait list"); rc = __cam_isp_ctx_flush_req(ctx, &ctx->wait_req_list, - flush_req); + flush_req); CAM_DBG(CAM_ISP, "try to flush active list"); rc = __cam_isp_ctx_flush_req(ctx, &ctx->active_req_list, - flush_req); + flush_req); ctx_isp->active_req_cnt = 0; spin_unlock_bh(&ctx->lock); -- GitLab From ea9eaadb9f0ff830742b347df1af6f26d94e4e39 Mon Sep 17 00:00:00 2001 From: Om Parkash Date: Thu, 18 Jun 2020 19:39:15 +0530 Subject: [PATCH 0884/1055] msm: camera: Remove frame id and timestamp checks for spurious SOF Remove frame id and timestamp checks for spurious SOF for recovering once spurious SOF is received. Change-Id: Iff4510fa5af4ae2e6b4c9f38a44b1f98000bf66d Signed-off-by: Om Parkash --- .../msm/camera/cam_req_mgr/cam_req_mgr_core.c | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index 35790fd06405..dfbc9b07e4a4 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c @@ -2494,7 +2494,6 @@ static int cam_req_mgr_cb_notify_trigger( struct crm_task_payload *task_data; bool send_sof = true; int i = 0; - int64_t sof_time_diff = 0; if (!trigger_data) { CAM_ERR(CAM_CRM, "sof_data is NULL"); @@ -2514,10 +2513,6 @@ static int cam_req_mgr_cb_notify_trigger( if (link->dev_sof_evt[i].dev_hdl == trigger_data->dev_hdl) { if (link->dev_sof_evt[i].sof_done == false) { link->dev_sof_evt[i].sof_done = true; - link->dev_sof_evt[i].frame_id = - trigger_data->frame_id; - link->dev_sof_evt[i].timestamp = - trigger_data->sof_timestamp_val; } else CAM_INFO(CAM_CRM, "Received Spurious SOF"); } else if (link->dev_sof_evt[i].sof_done == false) { @@ -2527,23 +2522,6 @@ static int cam_req_mgr_cb_notify_trigger( if (!send_sof) return 0; - if (link->num_sof_src > 1) { - for (i = 0; i < (link->num_sof_src - 1); i++) { - if (link->dev_sof_evt[i].timestamp >= - link->dev_sof_evt[i+1].timestamp) { - sof_time_diff = link->dev_sof_evt[i].timestamp - - link->dev_sof_evt[i+1].timestamp; - } else { - sof_time_diff = - link->dev_sof_evt[i+1].timestamp - - link->dev_sof_evt[i].timestamp; - } - if ((link->dev_sof_evt[i].frame_id != - link->dev_sof_evt[i+1].frame_id) || - sof_time_diff > TIMESTAMP_DIFF_THRESHOLD) - return 0; - } - } for (i = 0; i < link->num_sof_src; i++) link->dev_sof_evt[i].sof_done = false; -- GitLab From d069041cc36ca1efeb4dcaaaf500ca3fe967a696 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Fri, 19 Jun 2020 11:20:07 -0700 Subject: [PATCH 0885/1055] soc: qcom: Remove WQ_MEM_RECLAIM from rmnet_ps_wq Previously wq was designated as WQ_MEM_RECLAIM. Remove this as it is unnessesary and will result in all notifier work to also be designated as WQ_MEM_RECLAIM. Change-Id: I3248e3aef1594b93c16a1ab8c7c6740d53f68886 Acked-by: Raul Martinez Signed-off-by: Subash Abhinov Kasiviswanathan --- drivers/soc/qcom/qmi_rmnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/qmi_rmnet.c b/drivers/soc/qcom/qmi_rmnet.c index 4a2c7449f46f..963bec244260 100644 --- a/drivers/soc/qcom/qmi_rmnet.c +++ b/drivers/soc/qcom/qmi_rmnet.c @@ -1162,7 +1162,7 @@ void qmi_rmnet_work_init(void *port) return; rmnet_ps_wq = alloc_workqueue("rmnet_powersave_work", - WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1); + WQ_CPU_INTENSIVE, 1); if (!rmnet_ps_wq) return; -- GitLab From 1f5bb23350dfd3ebd5a6a65ed1782ec5602ce7e8 Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Thu, 18 Jun 2020 13:19:34 -0700 Subject: [PATCH 0886/1055] pci: switch: Add PCIe switch driver The driver supports switches connected to the PCIe root port controller. The driver can be used to run any erratas specific to the switch for the corresponding bus, device and function for a specific vendor and device ID of the switch. Change-Id: I2e2fa1d92e0292102716e978c303d9a64e9cd861 Signed-off-by: Siddartha Mohanadoss --- .../devicetree/bindings/pci/msm_pcie.txt | 3 + drivers/pci/switch/Kconfig | 8 + drivers/pci/switch/Makefile | 1 + drivers/pci/switch/switch-qcom.c | 222 ++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 drivers/pci/switch/switch-qcom.c diff --git a/Documentation/devicetree/bindings/pci/msm_pcie.txt b/Documentation/devicetree/bindings/pci/msm_pcie.txt index 52f9e5ade3ff..8b29bd5c91c7 100644 --- a/Documentation/devicetree/bindings/pci/msm_pcie.txt +++ b/Documentation/devicetree/bindings/pci/msm_pcie.txt @@ -130,6 +130,9 @@ Optional Properties: property. - clock-output-names: name of the outgoing clock signal from the PHY PLL. - qcom,keep-powerdown-phy: If present, power down phy in probe to avoid leakage. + - errata: Selects the list of erratas to configure for the + corresponding switch port. This could be a third party switch connected to + the root port. ================= Root Complex node diff --git a/drivers/pci/switch/Kconfig b/drivers/pci/switch/Kconfig index 4c49648e0646..0dcf34d7f8f4 100644 --- a/drivers/pci/switch/Kconfig +++ b/drivers/pci/switch/Kconfig @@ -10,4 +10,12 @@ config PCI_SW_SWITCHTEC devices. See for more information. +config PCI_SW_QCOM_SWITCH + depends on ARCH_QCOM + tristate "Qualcomm Technologies, Inc. PCIe Switch Management Driver" + help + Enables support for switches connected to Qualcomm Technologies, Inc. + PCIe Rootport. Switches that require erratas can bind with this driver + and run errata for the corresponding port. + endmenu diff --git a/drivers/pci/switch/Makefile b/drivers/pci/switch/Makefile index 37d8cfb03f3f..da9126f13778 100644 --- a/drivers/pci/switch/Makefile +++ b/drivers/pci/switch/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_PCI_SW_SWITCHTEC) += switchtec.o +obj-$(CONFIG_PCI_SW_QCOM_SWITCH) += switch-qcom.o diff --git a/drivers/pci/switch/switch-qcom.c b/drivers/pci/switch/switch-qcom.c new file mode 100644 index 000000000000..ebe40fd6cfb1 --- /dev/null +++ b/drivers/pci/switch/switch-qcom.c @@ -0,0 +1,222 @@ +/* Copyright (c) 2020, 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. + */ + +/* + * MSM PCIe switch controller + */ + +#include +#include +#include +#include +#include +#include + +#define DIODE_VENDOR_ID 0x12d8 +#define DIODE_DEVICE_ID 0xb304 + +/* + * @DIODE_ERRATA_0: Apply errata specific to the upstream port (USP). + * @DIODE_ERRATA_1: Apply errata configuration to downstream port1 (DSP1). + * @DIODE_ERRATA_2: Common errata applied to (DSP2) port in the switch. + */ +enum { + DIODE_ERRATA_0, + DIODE_ERRATA_1, + DIODE_ERRATA_2, + SWITCH_MAX, +}; + +struct pci_qcom_switch_errata { + int (*config_errata)(struct device *dev, void *data); +}; + +static int config_common_port_diode(struct device *dev, void *data) +{ + struct pci_dev *pcidev = to_pci_dev(dev); + int ret = 0; + u32 addr, val; + + if (!pcidev) { + pr_err("%s: port not found\n", __func__); + return -ENODEV; + } + + addr = 0x3c; + ret = pci_read_config_dword(pcidev, addr, &val); + if (ret) { + pr_err("read fail: port %s read cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + val |= 1 << 17; + ret = pci_write_config_dword(pcidev, addr, val); + if (ret) { + pr_err("write fail: port %s read cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + return 0; +} + +static int config_upstream_port_diode(struct device *dev, void *data) +{ + struct pci_dev *pcidev = to_pci_dev(dev); + u32 addr, val; + int ret; + + if (!pcidev) { + pr_err("%s: port not found\n", __func__); + return -ENODEV; + } + + /* write cfg offset 74h.bit[7] = 1 */ + addr = 0x74; + ret = pci_read_config_dword(pcidev, addr, &val); + if (ret) { + pr_err("read fail: port %s read cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + val |= 1 << 7; + ret = pci_write_config_dword(pcidev, addr, val); + if (ret) { + pr_err("write fail: port %s write cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + ret = config_common_port_diode(dev, NULL); + if (ret) { + pr_err("%s: Applying common configuration failed\n", __func__); + return ret; + } + + return 0; +} + +static int config_downstream_port_1_diode(struct device *dev, void *data) +{ + struct pci_dev *pcidev = to_pci_dev(dev); + int ret; + u32 addr, val; + + if (!pcidev) { + pr_err("%s: port not found\n", __func__); + return -ENODEV; + } + + /* write cfg offset 6ch.bit[25] = 1 */ + addr = 0x6c; + ret = pci_read_config_dword(pcidev, addr, &val); + if (ret) { + pr_err("read fail: port %s read cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + val |= 1 << 25; + ret = pci_write_config_dword(pcidev, addr, val); + if (ret) { + pr_err("write fail: port %s write cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + /* write cfg offset 33ch.bit[2] = 1 */ + addr = 0x33c; + ret = pci_read_config_dword(pcidev, addr, &val); + if (ret) { + pr_err("read fail: port %s read cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + val |= 1 << 2; + ret = pci_write_config_dword(pcidev, addr, val); + if (ret) { + pr_err("write fail: port %s write cfg addr:%x val:%x ret:%d\n", + dev_name(&pcidev->dev), addr, val, ret); + return ret; + } + + ret = config_common_port_diode(dev, NULL); + if (ret) { + pr_err("%s: Applying common configuration failed\n", __func__); + return ret; + } + + return 0; +} + +struct pci_qcom_switch_errata errata[] = { + [DIODE_ERRATA_0] = {config_upstream_port_diode}, + [DIODE_ERRATA_1] = {config_downstream_port_1_diode}, + [DIODE_ERRATA_2] = {config_common_port_diode}, +}; + +static struct pci_device_id switch_qcom_pci_tbl[] = { + { + PCI_DEVICE(DIODE_VENDOR_ID, DIODE_DEVICE_ID), + }, + {0}, +}; +MODULE_DEVICE_TABLE(pci, switch_qcom_pci_tbl); + +static int switch_qcom_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int ret = 0, errata_num = 0; + + ret = of_property_read_u32((&pdev->dev)->of_node, "errata", + &errata_num); + if (ret) { + pr_info("No erratas needed\n"); + return 0; + } + + pr_info("Errata being requested: %d\n", errata_num); + + if (errata_num >= SWITCH_MAX) { + pr_err("Invalid errata num:%d\n", errata_num); + return -EINVAL; + } + + ret = errata[errata_num].config_errata(&pdev->dev, NULL); + if (ret) { + pr_err("Error applying errata\n"); + return ret; + } + + return 0; +} + +static struct pci_driver switch_qcom_pci_driver = { + .name = "pcie-qcom-switch", + .id_table = switch_qcom_pci_tbl, + .probe = switch_qcom_pci_probe, +}; + +static int __init switch_qcom_pci_init(void) +{ + return pci_register_driver(&switch_qcom_pci_driver); +} +module_init(switch_qcom_pci_init); + +static void __exit switch_qcom_pci_exit(void) +{ + return pci_unregister_driver(&switch_qcom_pci_driver); +} +module_exit(switch_qcom_pci_exit); -- GitLab From 51c534ae4ded68ae3810596d79c915e7a9a36981 Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Thu, 18 Jun 2020 13:26:51 -0700 Subject: [PATCH 0887/1055] ARM: dts: msm: Add PCIe switch driver for sdxprairie Use the errata property to pass the corresponding configuration to be run on the diode switch connected to the PCIe root port. The errata programs the corresponding port based on the bus, device and function of the switch port. Update the IOMMU SID to reflect the change in ordering due to the addition of the switch. The end point devices have their own PCIe IOMMU SID group to avoid conflicts with each other. Change-Id: Iac6bc0f351dbac9f26a859a382f27ad407a0cf8d Signed-off-by: Siddartha Mohanadoss --- arch/arm64/boot/dts/qcom/sdxprairie-pcie.dtsi | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-pcie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-pcie.dtsi index 8c020724a1d4..75e75921902a 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-pcie.dtsi @@ -209,7 +209,9 @@ <0x100 &apps_smmu 0x0201 0x1>, <0x200 &apps_smmu 0x0202 0x1>, <0x300 &apps_smmu 0x0203 0x1>, - <0x400 &apps_smmu 0x0204 0x1>; + <0x400 &apps_smmu 0x0204 0x1>, + <0x208 &apps_smmu 0x0205 0x1>, + <0x210 &apps_smmu 0x0206 0x1>; qcom,msm-bus,name = "pcie0"; qcom,msm-bus,num-cases = <2>; @@ -252,17 +254,20 @@ pcie0_bus1_dev0_fn0: pcie0_bus1_dev0_fn0 { reg = <0 0 0 0 0>; pci-ids = "12d8:b304"; + errata = <0>; /* BDF 2.1.0 */ pcie0_bus2_dev1_fn0: pcie0_bus2_dev1_fn0 { reg = <0x800 0 0 0 0>; pci-ids = "12d8:b304"; + errata = <1>; }; /* BDF 2.2.0 */ pcie0_bus2_dev2_fn0: pcie0_bus2_dev2_fn0 { reg = <0x1000 0 0 0 0>; pci-ids = "12d8:b304"; + errata = <2>; }; }; }; -- GitLab From ff01822a64a76c65d4550b0cce1056407441f944 Mon Sep 17 00:00:00 2001 From: Siddartha Mohanadoss Date: Thu, 18 Jun 2020 15:10:50 -0700 Subject: [PATCH 0888/1055] defconfig: msm: Add PCIe driver for sdxprarie Add PCIe switch driver that can be used to configure erratas for diode switch. Change-Id: I684a80de5dd95302c580624386dbbb3ec772031a Signed-off-by: Siddartha Mohanadoss --- arch/arm/configs/vendor/sdxprairie-perf_defconfig | 1 + arch/arm/configs/vendor/sdxprairie_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/vendor/sdxprairie-perf_defconfig b/arch/arm/configs/vendor/sdxprairie-perf_defconfig index 548d0dae0430..1804cc7911ad 100644 --- a/arch/arm/configs/vendor/sdxprairie-perf_defconfig +++ b/arch/arm/configs/vendor/sdxprairie-perf_defconfig @@ -34,6 +34,7 @@ CONFIG_ARCH_SDXPRAIRIE=y # CONFIG_VDSO is not set CONFIG_PCI_MSM=y CONFIG_PCI_MSM_MSI=y +CONFIG_PCI_SW_QCOM_SWITCH=y CONFIG_PREEMPT=y CONFIG_HIGHMEM=y CONFIG_ARM_MODULE_PLTS=y diff --git a/arch/arm/configs/vendor/sdxprairie_defconfig b/arch/arm/configs/vendor/sdxprairie_defconfig index 50fa20b02e8a..3612bfb8ffb9 100644 --- a/arch/arm/configs/vendor/sdxprairie_defconfig +++ b/arch/arm/configs/vendor/sdxprairie_defconfig @@ -34,6 +34,7 @@ CONFIG_ARCH_SDXPRAIRIE=y # CONFIG_VDSO is not set CONFIG_PCI_MSM=y CONFIG_PCI_MSM_MSI=y +CONFIG_PCI_SW_QCOM_SWITCH=y CONFIG_PREEMPT=y CONFIG_HIGHMEM=y CONFIG_ARM_MODULE_PLTS=y -- GitLab From c31d8f4e65f3f40683d06b9d0a45553d275aa74c Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Sun, 7 Jun 2020 22:57:55 +0530 Subject: [PATCH 0889/1055] ARM: dts: msm: Remove low temperature monitor thermal zones for SA8195P Remove low temperature monitor thermal zones for SA8195P as per latest recommendation. Change-Id: I04f62c54482714cd3c54f1e503c473b4aa7bbb40 Signed-off-by: Manaf Meethalavalappu Pallikunhi --- .../boot/dts/qcom/sa8195p-regulator.dtsi | 29 ------------------- arch/arm64/boot/dts/qcom/sa8195p.dtsi | 25 ++++------------ 2 files changed, 5 insertions(+), 49 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa8195p-regulator.dtsi b/arch/arm64/boot/dts/qcom/sa8195p-regulator.dtsi index 1ca9f004c58c..9d3ff0740904 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p-regulator.dtsi @@ -41,13 +41,6 @@ qcom,init-voltage-level = ; }; - - ebi_cdev: regulator-cdev { - compatible = "qcom,rpmh-reg-cdev"; - mboxes = <&qmp_aop 0>; - qcom,reg-resource-name = "ebi"; - #cooling-cells = <2>; - }; }; /* PM8195_1 S2 = VDDCX_MM supply */ @@ -79,14 +72,6 @@ qcom,init-voltage-level = ; }; - - mm_cx_cdev: mm-cx-cdev-lvl { - compatible = "qcom,regulator-cooling-device"; - regulator-cdev-supply = <&VDD_MMCX_LEVEL_AO>; - regulator-levels = ; - #cooling-cells = <2>; - }; }; rpmh-regulator-smpa3 { @@ -188,14 +173,6 @@ qcom,init-voltage-level = ; }; - - mx_cdev: mx-cdev-lvl { - compatible = "qcom,regulator-cooling-device"; - regulator-cdev-supply = <&VDD_MX_LEVEL>; - regulator-levels = ; - #cooling-cells = <2>; - }; }; rpmh-regulator-ldoa2 { @@ -647,12 +624,6 @@ = ; qcom,min-dropout-voltage-level = <(-1)>; }; - cx_cdev: regulator-cdev { - compatible = "qcom,rpmh-reg-cdev"; - mboxes = <&qmp_aop 0>; - qcom,reg-resource-name = "cx"; - #cooling-cells = <2>; - }; }; rpmh-regulator-smpe4 { diff --git a/arch/arm64/boot/dts/qcom/sa8195p.dtsi b/arch/arm64/boot/dts/qcom/sa8195p.dtsi index 7b728de681fe..a3e491fe4102 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p.dtsi @@ -425,26 +425,11 @@ }; &thermal_zones { - cpu-1-7-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; - gpuss-0-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; - camera-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; - mdm-scl-lowf { - cooling-maps { - /delete-node/ mmcx_vdd_cdev; - }; - }; + /delete-node/ cpu-1-7-lowf; + /delete-node/ gpuss-0-lowf; + /delete-node/ camera-lowf; + /delete-node/ mdm-scl-lowf; + /delete-node/ pcie-lowf; lmh-dcvs-01 { trips { -- GitLab From d3769d8a35ad38ce93a42e0791213db390300219 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Mon, 8 Jun 2020 00:07:19 +0530 Subject: [PATCH 0890/1055] ARM: dts: msm: update gpu thermal zone threshold for auto Gen 3 platforms Update gpu thermal zone threshold for sa8155 and sa8195p based on latest recommendation. Change-Id: I585ae564c14385badd99e742ae442feb6a65b5bf Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm64/boot/dts/qcom/sa8155.dtsi | 2 +- arch/arm64/boot/dts/qcom/sa8195p.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa8155.dtsi b/arch/arm64/boot/dts/qcom/sa8155.dtsi index c41c5e788f1a..a078eee6690a 100644 --- a/arch/arm64/boot/dts/qcom/sa8155.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155.dtsi @@ -263,7 +263,7 @@ gpuss-max-step { trips { gpu-trip0 { - temperature = <100000>; + temperature = <105000>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sa8195p.dtsi b/arch/arm64/boot/dts/qcom/sa8195p.dtsi index a3e491fe4102..863c5330d7e5 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p.dtsi @@ -452,7 +452,7 @@ quad-gpuss-max-step { trips { gpu-trip0 { - temperature = <100000>; + temperature = <105000>; }; }; }; -- GitLab From d029cea4a59c6f377450215da42717a5e72e095e Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Thu, 4 Jun 2020 00:19:33 +0530 Subject: [PATCH 0891/1055] ARM: dts: msm: enable pmic alarm thermal zone mitigation for Gen3 platform Enable pmic temperature alarm sensor thermal zone mitigation for Gen3 platform targets. It monitors level 1 alarm and does cpu mitigation. Change-Id: Ia223962ea0b9aa066e7c27ebac82fd5ffb2485b3 Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm64/boot/dts/qcom/pm6155.dtsi | 32 +++- arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi | 60 ++++++ .../boot/dts/qcom/sa8155-pmic-overlay.dtsi | 120 ++++++++++++ arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi | 174 ++++++++++++++++++ 4 files changed, 385 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/pm6155.dtsi b/arch/arm64/boot/dts/qcom/pm6155.dtsi index e96b5638ff3d..c5714d8a93a0 100644 --- a/arch/arm64/boot/dts/qcom/pm6155.dtsi +++ b/arch/arm64/boot/dts/qcom/pm6155.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018, 2020, 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 @@ -173,3 +173,33 @@ #size-cells = <1>; }; }; + +&thermal_zones { + pm6155-1-tz { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm6155_1_tz>; + wake-capable-sensor; + + trips { + pm6155_trip0: trip0 { + temperature = <95000>; + hysteresis = <0>; + type = "passive"; + }; + + pm6155_trip1: trip1 { + temperature = <115000>; + hysteresis = <0>; + type = "passive"; + }; + + trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi b/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi index fb96af75665d..ccef59f575bc 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-pmic.dtsi @@ -335,4 +335,64 @@ }; }; }; + + pm6155-1-tz { + cooling-maps { + trip1_cpu0 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_cpu1 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu2 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu3 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu4 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu5 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu6 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu7 { + trip = <&pm6155_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sa8155-pmic-overlay.dtsi index fd0725339f20..41df55dbe659 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-pmic-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-pmic-overlay.dtsi @@ -164,6 +164,8 @@ pm8150_1_gpios: &pm8150_gpios { }; }; +#include + &thermal_zones { pm8150_2_temp_alarm: pm8150_2_tz { polling-delay-passive = <100>; @@ -189,5 +191,123 @@ pm8150_1_gpios: &pm8150_gpios { type = "passive"; }; }; + + cooling-maps { + trip1_cpu0 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_cpu1 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu2 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu3 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu4 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu5 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu6 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu7 { + trip = <&pm8150_2_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pm8150_tz { + cooling-maps { + trip1_cpu0 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_cpu1 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu2 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu3 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu4 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu5 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu6 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu7 { + trip = <&pm8150_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi b/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi index 5236ff4aa086..ebeac6853f38 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-pmic.dtsi @@ -120,6 +120,64 @@ type = "passive"; }; }; + + cooling-maps { + trip1_cpu0 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_cpu1 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu2 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu3 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu4 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu5 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu6 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu7 { + trip = <&pm8195_1_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; }; pm8195_2_temp_alarm: pm8195_2_tz { @@ -146,6 +204,64 @@ type = "passive"; }; }; + + cooling-maps { + trip1_cpu0 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_cpu1 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu2 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu3 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu4 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu5 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu6 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu7 { + trip = <&pm8195_2_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; }; pm8195_3_temp_alarm: pm8195_3_tz { @@ -172,5 +288,63 @@ type = "passive"; }; }; + + cooling-maps { + trip1_cpu0 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + + trip1_cpu1 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu2 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu3 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu4 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu5 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu6 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + + trip1_cpu7 { + trip = <&pm8195_3_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; }; }; -- GitLab From ce1ec1a93c152bc3c03c035ae73a5fc8536238dd Mon Sep 17 00:00:00 2001 From: Lei wang Date: Wed, 26 Feb 2020 13:39:42 +0800 Subject: [PATCH 0892/1055] profiler: Add a communication interface between userspace and tz services Add snapshot of profiler driver from msm-4.4. This snapshot is taken as of msm-4.4 commit bf01369440c0 (profiler: Add a communication interface between userspace and tz services) Refine code for llcc support. Change-Id: I37db17202fbd09feb36a118e6e9c3e3aa00bec9d Signed-off-by: Lei wang --- drivers/misc/Kconfig | 8 + drivers/misc/Makefile | 1 + drivers/misc/profiler.c | 454 ++++++++++++++++++++++++++++++++++++ include/soc/qcom/profiler.h | 107 +++++++++ include/soc/qcom/scm.h | 1 + 5 files changed, 571 insertions(+) create mode 100644 drivers/misc/profiler.c create mode 100644 include/soc/qcom/profiler.h diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 08c320494725..2d4c9718efc8 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -490,6 +490,14 @@ config QSEECOM Manager (SCM) interface. It exposes APIs for both userspace and kernel clients. +config PROFILER + tristate "Qualcomm Technologies, Inc. trustzone Communicator driver" + help + Provides a communication interface between userspace and + trustzone using Secure Channel Manager (SCM) interface. + It exposes APIs for userspace to get system profiling + information. + config VEXPRESS_SYSCFG bool "Versatile Express System Configuration driver" depends on VEXPRESS_CONFIG diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 63dbe5f03e1e..553ddb0d58e7 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_GENWQE) += genwqe/ obj-$(CONFIG_HDCP_QSEECOM) += hdcp_qseecom.o obj-$(CONFIG_HDCP_QSEECOM) += msm_hdcp.o obj-$(CONFIG_QSEECOM) += qseecom.o +obj-$(CONFIG_PROFILER) += profiler.o obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o obj-$(CONFIG_CXL_BASE) += cxl/ diff --git a/drivers/misc/profiler.c b/drivers/misc/profiler.c new file mode 100644 index 000000000000..49ebd2516bb5 --- /dev/null +++ b/drivers/misc/profiler.c @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2017-2018, 2020 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. + */ + +#define pr_fmt(fmt) "PROFILER: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PROFILER_DEV "profiler" + +static struct class *driver_class; +static dev_t profiler_device_no; + +struct profiler_control { + struct device *pdev; + struct cdev cdev; +}; + +static struct profiler_control profiler; + +struct profiler_dev_handle { + bool released; + int abort; + atomic_t ioctl_count; +}; + + +static int profiler_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, + const void *req_buf, void *resp_buf) +{ + int ret = 0; + uint32_t qseos_cmd_id = 0; + struct scm_desc desc = {0}; + + if (!req_buf || !resp_buf) { + pr_err("Invalid buffer pointer\n"); + return -EINVAL; + } + qseos_cmd_id = *(uint32_t *)req_buf; + + switch (svc_id) { + + case SCM_SVC_BW: + switch (qseos_cmd_id) { + case TZ_BW_SVC_START_ID: + case TZ_BW_SVC_GET_ID: + case TZ_BW_SVC_STOP_ID: + /* Send the command to TZ */ + desc.arginfo = SCM_ARGS(4, SCM_RW, SCM_VAL, + SCM_RW, SCM_VAL); + desc.args[0] = virt_to_phys(& + (((struct tz_bw_svc_buf *) + req_buf)->bwreq)); + desc.args[1] = ((struct tz_bw_svc_buf *) + req_buf)->req_size; + desc.args[2] = virt_to_phys(& + ((struct tz_bw_svc_buf *) + req_buf)->bwresp); + desc.args[3] = sizeof(struct tz_bw_svc_resp); + + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_INFO, + TZ_SVC_BW_PROF_ID), &desc); + break; + default: + pr_err("cmd_id %d is not supported by scm_call2.\n", + qseos_cmd_id); + ret = -EINVAL; + } /*end of switch (qsee_cmd_id) */ + break; + default: + pr_err("svc_id 0x%x is not supported by armv8 scm_call2.\n", + svc_id); + ret = -EINVAL; + break; + } /*end of switch svc_id */ + return ret; +} + + +static int profiler_scm_call(u32 svc_id, u32 tz_cmd_id, const void *cmd_buf, + size_t cmd_len, void *resp_buf, size_t resp_len) +{ + if (!is_scm_armv8()) + return scm_call(svc_id, tz_cmd_id, cmd_buf, cmd_len, + resp_buf, resp_len); + else + return profiler_scm_call2(svc_id, tz_cmd_id, cmd_buf, resp_buf); +} + +static int bw_profiling_command(void *req) +{ + struct tz_bw_svc_resp *bw_resp = NULL; + uint32_t cmd_id = 0; + int ret; + + cmd_id = *(uint32_t *)req; + bw_resp = &((struct tz_bw_svc_buf *)req)->bwresp; + /* Flush buffers from cache to memory. */ + dmac_flush_range(req, req + + PAGE_ALIGN(sizeof(union tz_bw_svc_req))); + dmac_flush_range((void *)bw_resp, ((void *)bw_resp) + + sizeof(struct tz_bw_svc_resp)); + ret = profiler_scm_call(SCM_SVC_BW, TZ_SVC_BW_PROF_ID, req, + sizeof(struct tz_bw_svc_buf), + bw_resp, sizeof(struct tz_bw_svc_resp)); + if (ret) { + pr_err("profiler_scm_call failed with err: %d\n", ret); + return -EINVAL; + } + /* Invalidate cache. */ + dmac_inv_range((void *)bw_resp, ((void *)bw_resp) + + sizeof(struct tz_bw_svc_resp)); + /* Verify cmd id and Check that request succeeded.*/ + if ((bw_resp->status != E_BW_SUCCESS) || + (cmd_id != bw_resp->cmd_id)) { + ret = -1; + pr_err("Status: %d,Cmd: %d\n", + bw_resp->status, + bw_resp->cmd_id); + } + return ret; +} + +static int bw_profiling_start(struct tz_bw_svc_buf *bwbuf) +{ + struct tz_bw_svc_start_req *bwstartreq = NULL; + + bwstartreq = (struct tz_bw_svc_start_req *) &bwbuf->bwreq; + /* Populate request data */ + bwstartreq->cmd_id = TZ_BW_SVC_START_ID; + bwstartreq->version = TZ_BW_SVC_VERSION; + bwbuf->req_size = sizeof(struct tz_bw_svc_start_req); + return bw_profiling_command(bwbuf); +} + +static int bw_profiling_get(void __user *argp, struct tz_bw_svc_buf *bwbuf) +{ + struct tz_bw_svc_get_req *bwgetreq = NULL; + int ret; + char *buf = NULL; + const int bufsize = sizeof(struct profiler_bw_cntrs_req) + - sizeof(uint32_t); + struct profiler_bw_cntrs_req cnt_buf; + + memset(&cnt_buf, 0, sizeof(cnt_buf)); + bwgetreq = (struct tz_bw_svc_get_req *) &bwbuf->bwreq; + /* Allocate memory for get buffer */ + buf = kzalloc(PAGE_ALIGN(bufsize), GFP_KERNEL); + if (buf == NULL) { + ret = -ENOMEM; + pr_err(" Failed to allocate memory\n"); + return ret; + } + /* Populate request data */ + bwgetreq->cmd_id = TZ_BW_SVC_GET_ID; + bwgetreq->buf_ptr = (uint64_t) virt_to_phys(buf); + bwgetreq->buf_size = bufsize; + bwbuf->req_size = sizeof(struct tz_bw_svc_get_req); + dmac_flush_range(buf, ((void *)buf) + PAGE_ALIGN(bwgetreq->buf_size)); + ret = bw_profiling_command(bwbuf); + if (ret) { + pr_err("bw_profiling_command failed\n"); + return ret; + } + dmac_inv_range(buf, ((void *)buf) + PAGE_ALIGN(bwgetreq->buf_size)); + memcpy(&cnt_buf, buf, bufsize); + if (copy_to_user(argp, &cnt_buf, sizeof(struct profiler_bw_cntrs_req))) + pr_err("copy_to_user failed\n"); + /* Free memory for response */ + if (buf != NULL) { + kfree(buf); + buf = NULL; + } + return ret; +} + +static int bw_profiling_stop(struct tz_bw_svc_buf *bwbuf) +{ + struct tz_bw_svc_stop_req *bwstopreq = NULL; + + bwstopreq = (struct tz_bw_svc_stop_req *) &bwbuf->bwreq; + /* Populate request data */ + bwstopreq->cmd_id = TZ_BW_SVC_STOP_ID; + bwbuf->req_size = sizeof(struct tz_bw_svc_stop_req); + return bw_profiling_command(bwbuf); +} + + +static int profiler_get_bw_info(void __user *argp) +{ + int ret = 0; + struct tz_bw_svc_buf *bwbuf = NULL; + struct profiler_bw_cntrs_req cnt_buf; + + ret = copy_from_user(&cnt_buf, argp, + sizeof(struct profiler_bw_cntrs_req)); + if (ret) + return ret; + /* Allocate memory for request */ + bwbuf = kzalloc(PAGE_ALIGN(sizeof(struct tz_bw_svc_buf)), GFP_KERNEL); + if (bwbuf == NULL) + return -ENOMEM; + switch (cnt_buf.cmd) { + case TZ_BW_SVC_START_ID: + ret = bw_profiling_start(bwbuf); + if (ret) + pr_err("bw_profiling_start Failed with ret: %d\n", ret); + break; + case TZ_BW_SVC_GET_ID: + ret = bw_profiling_get(argp, bwbuf); + if (ret) + pr_err("bw_profiling_get Failed with ret: %d\n", ret); + break; + case TZ_BW_SVC_STOP_ID: + ret = bw_profiling_stop(bwbuf); + if (ret) + pr_err("bw_profiling_stop Failed with ret: %d\n", ret); + break; + default: + pr_err("Invalid IOCTL: 0x%x\n", cnt_buf.cmd); + ret = -EINVAL; + } + /* Free memory for command */ + if (bwbuf != NULL) { + kfree(bwbuf); + bwbuf = NULL; + } + return ret; +} + +static int profiler_open(struct inode *inode, struct file *file) +{ + int ret = 0; + struct profiler_dev_handle *data; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + file->private_data = data; + data->abort = 0; + data->released = false; + atomic_set(&data->ioctl_count, 0); + return ret; +} + +static int compat_get_profiler_bw_info( + struct compat_profiler_bw_cntrs_req __user *data32, + struct profiler_bw_cntrs_req __user *data) +{ + compat_uint_t val = 0; + int err = 0; + int i = 0; + + for (i = 0; i < (sizeof(struct profiler_bw_cntrs_req)) + /sizeof(uint32_t) - 1; ++i) { + err |= get_user(val, (compat_uint_t *)data32 + i); + err |= put_user(val, (uint32_t *)data + i); + } + + return err; +} + +static int compat_put_profiler_bw_info( + struct compat_profiler_bw_cntrs_req __user *data32, + struct profiler_bw_cntrs_req __user *data) +{ + compat_uint_t val = 0; + int err = 0; + int i = 0; + + for (i = 0; i < (sizeof(struct profiler_bw_cntrs_req)) + /sizeof(uint32_t) - 1; ++i) { + err |= get_user(val, (uint32_t *)data + i); + err |= put_user(val, (compat_uint_t *)data32 + i); + } + + return err; +} + +static unsigned int convert_cmd(unsigned int cmd) +{ + switch (cmd) { + case COMPAT_PROFILER_IOCTL_GET_BW_INFO: + return PROFILER_IOCTL_GET_BW_INFO; + + default: + return cmd; + } +} + + +static long profiler_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct profiler_dev_handle *data = file->private_data; + void __user *argp = (void __user *) arg; + + if (!data) { + pr_err("Invalid/uninitialized device handle\n"); + return -EINVAL; + } + + if (data->abort) { + pr_err("Aborting profiler driver\n"); + return -ENODEV; + } + + switch (cmd) { + case PROFILER_IOCTL_GET_BW_INFO: + atomic_inc(&data->ioctl_count); + ret = profiler_get_bw_info(argp); + if (ret) + pr_err("failed get system bandwidth info: %d\n", ret); + atomic_dec(&data->ioctl_count); + break; + default: + pr_err("Invalid IOCTL: 0x%x\n", cmd); + return -EINVAL; + } + return ret; +} + +static long compat_profiler_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + + switch (cmd) { + case COMPAT_PROFILER_IOCTL_GET_BW_INFO:{ + struct compat_profiler_bw_cntrs_req __user *data32; + struct profiler_bw_cntrs_req __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (data == NULL) + return -EFAULT; + err = compat_get_profiler_bw_info(data32, data); + if (err) + return err; + ret = profiler_ioctl(file, convert_cmd(cmd), + (unsigned long)data); + err = compat_put_profiler_bw_info(data32, data); + return ret ? ret : err; + } + default: + return -ENOIOCTLCMD; + } + return 0; +} + + +static int profiler_release(struct inode *inode, struct file *file) +{ + pr_info("profiler release\n"); + return 0; +} + +static const struct file_operations profiler_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = profiler_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = compat_profiler_ioctl, +#endif + .open = profiler_open, + .release = profiler_release +}; + +static int profiler_init(void) +{ + int rc; + struct device *class_dev; + + rc = alloc_chrdev_region(&profiler_device_no, 0, 1, PROFILER_DEV); + if (rc < 0) { + pr_err("alloc_chrdev_region failed %d\n", rc); + return rc; + } + + driver_class = class_create(THIS_MODULE, PROFILER_DEV); + if (IS_ERR(driver_class)) { + rc = -ENOMEM; + pr_err("class_create failed %d\n", rc); + goto exit_unreg_chrdev_region; + } + + class_dev = device_create(driver_class, NULL, profiler_device_no, NULL, + PROFILER_DEV); + if (IS_ERR(class_dev)) { + pr_err("class_device_create failed %d\n", rc); + rc = -ENOMEM; + goto exit_destroy_class; + } + + cdev_init(&profiler.cdev, &profiler_fops); + profiler.cdev.owner = THIS_MODULE; + + rc = cdev_add(&profiler.cdev, MKDEV(MAJOR(profiler_device_no), 0), 1); + if (rc < 0) { + pr_err("%s: cdev_add failed %d\n", __func__, rc); + goto exit_destroy_device; + } + + profiler.pdev = class_dev; + return 0; + +exit_destroy_device: + device_destroy(driver_class, profiler_device_no); +exit_destroy_class: + class_destroy(driver_class); +exit_unreg_chrdev_region: + unregister_chrdev_region(profiler_device_no, 1); + return rc; +} + +static void profiler_exit(void) +{ + pr_info("Exiting from profiler\n"); +} + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. trustzone Communicator"); + +module_init(profiler_init); +module_exit(profiler_exit); diff --git a/include/soc/qcom/profiler.h b/include/soc/qcom/profiler.h new file mode 100644 index 000000000000..7d336aeccf50 --- /dev/null +++ b/include/soc/qcom/profiler.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2017, 2020 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 __PROFILER_H_ +#define __PROFILER_H_ + + +struct profiler_bw_cntrs_req { + uint32_t llcc_total; + uint32_t llcc_rd; + uint32_t llcc_wr; + uint32_t cabo_total; + uint32_t cabo_rd; + uint32_t cabo_wr; + uint32_t cmd; +}; + +struct compat_profiler_bw_cntrs_req { + compat_uint_t llcc_total; + compat_uint_t llcc_rd; + compat_uint_t llcc_wr; + compat_uint_t cabo_total; + compat_uint_t cabo_rd; + compat_uint_t cabo_wr; + compat_uint_t cmd; +}; + +/* Error types */ +enum tz_bw_svc_err { + E_BW_SUCCESS = 0, /* Operation successful */ + E_BW_FAILURE = 1, /* Operation failed due to unknown err */ + E_BW_NULL_PARAM = 2, /* Null Parameter */ + E_BW_INVALID_ARG = 3, /* Arg is not recognized */ + E_BW_BAD_ADDRESS = 4, /* Ptr arg is bad address */ + E_BW_INVALID_ARG_LEN = 5, /* Arg length is wrong */ + E_BW_NOT_SUPPORTED = 6, /* Operation not supported */ + E_BW_NOT_PERMITTED = 7, /* Operation not permitted on platform */ + E_BW_TIME_LOCKED = 8, /* Operation not permitted right now */ + E_BW_RESERVED = 0x7FFFFFFF +}; + +#define TZ_BW_SVC_VERSION (1) +#define PROFILER_IOC_MAGIC 0x98 + +#define PROFILER_IOCTL_GET_BW_INFO \ + _IOWR(PROFILER_IOC_MAGIC, 1, struct profiler_bw_cntrs_req) + +#define COMPAT_PROFILER_IOCTL_GET_BW_INFO \ + _IOWR(PROFILER_IOC_MAGIC, 1, struct compat_profiler_bw_cntrs_req) + +/* Command types */ +enum tz_bw_svc_cmd { + TZ_BW_SVC_START_ID = 0x00000001, + TZ_BW_SVC_GET_ID = 0x00000002, + TZ_BW_SVC_STOP_ID = 0x00000003, + TZ_BW_SVC_LAST_ID = 0x7FFFFFFF +}; +/* Start Request */ +struct tz_bw_svc_start_req { + enum tz_bw_svc_cmd cmd_id; + uint32_t version; +} __packed; + +/* Get Request */ +struct tz_bw_svc_get_req { + enum tz_bw_svc_cmd cmd_id; + uint64_t buf_ptr; + uint32_t buf_size; +} __packed; + +/* Stop Request */ +struct tz_bw_svc_stop_req { + enum tz_bw_svc_cmd cmd_id; +} __packed; + +struct tz_bw_svc_resp { + enum tz_bw_svc_cmd cmd_id; + enum tz_bw_svc_err status; +} __packed; + +union tz_bw_svc_req { + struct tz_bw_svc_start_req *start_req; + struct tz_bw_svc_get_req *get_req; + struct tz_bw_svc_stop_req *stop_req; +} __packed; + +struct tz_bw_svc_buf { + union tz_bw_svc_req bwreq; + struct tz_bw_svc_resp bwresp; + uint32_t req_size; +} __packed; + + +#define TZ_SVC_INFO 6 /* Misc. information services */ +#define TZ_SVC_BW_PROF_ID 0x07 + +#endif /* __PROFILER_H_ */ diff --git a/include/soc/qcom/scm.h b/include/soc/qcom/scm.h index a4e59f7e643e..e36ef468bfd9 100644 --- a/include/soc/qcom/scm.h +++ b/include/soc/qcom/scm.h @@ -32,6 +32,7 @@ #define SCM_SVC_RTIC 0x19 #define SCM_SVC_TSENS 0x1E #define SCM_SVC_TZSCHEDULER 0xFC +#define SCM_SVC_BW 0xFD #define SCM_FUSE_READ 0x7 #define SCM_CMD_HDCP 0x01 -- GitLab From 4ba4b4c9bf3a185cdfdc4313e7b2262470e20bf4 Mon Sep 17 00:00:00 2001 From: Sahitya Tummala Date: Mon, 22 Jun 2020 07:34:17 +0530 Subject: [PATCH 0893/1055] ARM: dts: msm: Add rmtfs_sharedmem support for SDM429W Add shared memory support to enable the rmt_storage service in userspace that allows other processor to access the primary storage device to store its data. Change-Id: If77304f54839e21b95a575994aaedd94c8513716 Signed-off-by: Sahitya Tummala --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 249797712a11..3928762357c0 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -338,6 +338,13 @@ status = "disabled"; }; + qcom,rmtfs_sharedmem@00000000 { + compatible = "qcom,sharedmem-uio"; + reg = <0x00000000 0x00180000>; + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + }; + sdhc_1: sdhci@7824900 { compatible = "qcom,sdhci-msm"; reg = <0x7824900 0x500>, <0x7824000 0x800>, <0x7824e00 0x200>; -- GitLab From b6eb1897c3f7a3179b2b77bdb28a1a3f6c1f1029 Mon Sep 17 00:00:00 2001 From: Sanjay Singh Date: Thu, 18 Jun 2020 08:25:17 +0530 Subject: [PATCH 0894/1055] msm: vidc: Update VP9 minimum buffer count Update VP9 output_min_count to 9. Change-Id: I920e534882846ec5e9a5b287e95c2290222fc40f Signed-off-by: Sanjay Singh --- drivers/media/platform/msm/vidc/msm_vdec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index 8ba90efd6811..bb97ecb25431 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2020, 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 @@ -542,7 +542,7 @@ struct msm_vidc_format vdec_formats[] = { .type = OUTPUT_PORT, .defer_outputs = true, .input_min_count = 4, - .output_min_count = 11, + .output_min_count = 9, }, }; -- GitLab From 556f3df030ff7727b286aa27454e23b9faa49a22 Mon Sep 17 00:00:00 2001 From: Shadul Shaikh Date: Mon, 4 May 2020 13:38:18 +0530 Subject: [PATCH 0895/1055] msm: camera: Do CSID reset during CSID release Reset the CSID in release as per HW recommendation. Change-Id: I3c051b9ebc8bebefea999deac0d560de693dfebb Signed-off-by: Shadul Shaikh --- .../platform/msm/camera_v2/sensor/csid/msm_csid.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c index 851bb261ca1b..9f0bd6f9e4f0 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2020, 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 @@ -854,6 +854,14 @@ static int msm_csid_release(struct csid_device *csid_dev) msm_camera_enable_irq(csid_dev->irq, false); + if (msm_camera_tz_is_secured( + MSM_CAMERA_TZ_IO_REGION_CSIDCORE0 + csid_dev->pdev->id) == 0) { + msm_camera_vio_w(csid_dev->ctrl_reg->csid_reg.csid_rst_stb_all, + csid_dev->base, + csid_dev->ctrl_reg->csid_reg.csid_rst_cmd_addr, + csid_dev->pdev->id); + } + msm_camera_clk_enable(&csid_dev->pdev->dev, csid_dev->csid_clk_info, csid_dev->csid_clk, -- GitLab From e6a0d89d1bdd26844b243c3ba82d01cecef53969 Mon Sep 17 00:00:00 2001 From: Rama Krishna Phani A Date: Fri, 12 Jun 2020 20:05:35 +0530 Subject: [PATCH 0896/1055] msm: mhi_dev: update NHWER after M0 from host Host might update NHWER value before issuing M0 to device. So, update number of HW event rings after M0 is received from host. Change-Id: I2e0b28a82e299e66b0167977c4c4ed9d7b6c889e Signed-off-by: Rama Krishna Phani A --- drivers/platform/msm/mhi_dev/mhi.c | 4 ++++ drivers/platform/msm/mhi_dev/mhi_mmio.c | 14 +++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index b03135b2c195..0a8ed321beb3 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -2364,6 +2364,10 @@ static int mhi_dev_cache_host_cfg(struct mhi_dev *mhi) return rc; } + mhi_log(MHI_MSG_VERBOSE, + "Number of Event rings : %d, HW Event rings : %d\n", + mhi->cfg.event_rings, mhi->cfg.hw_event_rings); + mhi->cmd_ctx_shadow.size = sizeof(struct mhi_dev_cmd_ctx); mhi->ev_ctx_shadow.size = sizeof(struct mhi_dev_ev_ctx) * mhi->cfg.event_rings; diff --git a/drivers/platform/msm/mhi_dev/mhi_mmio.c b/drivers/platform/msm/mhi_dev/mhi_mmio.c index 3ee2c2bc150e..7770ea694330 100644 --- a/drivers/platform/msm/mhi_dev/mhi_mmio.c +++ b/drivers/platform/msm/mhi_dev/mhi_mmio.c @@ -709,13 +709,21 @@ EXPORT_SYMBOL(mhi_dev_mmio_init); int mhi_dev_update_ner(struct mhi_dev *dev) { + int rc = 0, mhi_cfg = 0; + if (WARN_ON(!dev)) return -EINVAL; - mhi_dev_mmio_masked_read(dev, MHICFG, MHICFG_NER_MASK, - MHICFG_NER_SHIFT, &dev->cfg.event_rings); + rc = mhi_dev_mmio_read(dev, MHICFG, &mhi_cfg); + if (rc) + return rc; + + pr_debug("MHICFG: 0x%x", mhi_cfg); - pr_debug("NER in HW :%d\n", dev->cfg.event_rings); + dev->cfg.event_rings = + (mhi_cfg & MHICFG_NER_MASK) >> MHICFG_NER_SHIFT; + dev->cfg.hw_event_rings = + (mhi_cfg & MHICFG_NHWER_MASK) >> MHICFG_NHWER_SHIFT; return 0; } -- GitLab From 75148ccdc2d9e37bcce4f4151d42004220bde54e Mon Sep 17 00:00:00 2001 From: Ashok Vuyyuru Date: Tue, 2 Jun 2020 13:27:30 +0530 Subject: [PATCH 0897/1055] msm: ipa3: Add support to fastmap/geometry for each CB Adding changes to support enable/disable fastmap for each CB and setting geometry range for AP SMMU node. Change-Id: I4286561536cd8e41f68b91ce45913337c8ad279f Signed-off-by: Ashok Vuyyuru --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 45 +++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index be5c72374a45..a1191427c30c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -145,6 +145,7 @@ static struct { bool present[IPA_SMMU_CB_MAX]; bool arm_smmu; bool fast_map; + bool fast_map_arr[IPA_SMMU_CB_MAX]; bool s1_bypass_arr[IPA_SMMU_CB_MAX]; bool use_64_bit_dma_mask; u32 ipa_base; @@ -8016,6 +8017,9 @@ static int ipa_smmu_wlan_cb_probe(struct device *dev) "dma-coherent"); cb->valid = true; + if (of_property_read_bool(dev->of_node, + "qcom,smmu-fast-map")) + smmu_info.fast_map_arr[IPA_SMMU_CB_WLAN] = true; if (of_property_read_bool(dev->of_node, "qcom,smmu-s1-bypass") || ipa3_ctx->ipa_config_is_mhi) { smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN] = true; @@ -8043,7 +8047,8 @@ static int ipa_smmu_wlan_cb_probe(struct device *dev) } IPADBG(" WLAN SMMU ATTR ATOMIC\n"); - if (smmu_info.fast_map) { + if (smmu_info.fast_map_arr[IPA_SMMU_CB_WLAN] || + smmu_info.fast_map) { if (iommu_domain_set_attr(cb->iommu, DOMAIN_ATTR_FAST, &fast)) { @@ -8056,7 +8061,8 @@ static int ipa_smmu_wlan_cb_probe(struct device *dev) } pr_info("IPA smmu_info.s1_bypass_arr[WLAN]=%d smmu_info.fast_map=%d\n", - smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN], smmu_info.fast_map); + smmu_info.s1_bypass_arr[IPA_SMMU_CB_WLAN], + smmu_info.fast_map_arr[IPA_SMMU_CB_WLAN]); ret = iommu_attach_device(cb->iommu, dev); if (ret) { @@ -8124,6 +8130,10 @@ static int ipa_smmu_uc_cb_probe(struct device *dev) IPAERR("Fail to read UC start/size iova addresses\n"); return ret; } + + if (of_property_read_bool(dev->of_node, + "qcom,smmu-fast-map")) + smmu_info.fast_map_arr[IPA_SMMU_CB_UC] = true; cb->va_start = iova_ap_mapping[0]; cb->va_size = iova_ap_mapping[1]; cb->va_end = cb->va_start + cb->va_size; @@ -8188,7 +8198,8 @@ static int ipa_smmu_uc_cb_probe(struct device *dev) } IPADBG("SMMU atomic set\n"); - if (smmu_info.fast_map) { + if (smmu_info.fast_map_arr[IPA_SMMU_CB_UC] || + smmu_info.fast_map) { if (iommu_domain_set_attr(cb->mapping->domain, DOMAIN_ATTR_FAST, &fast)) { @@ -8202,7 +8213,8 @@ static int ipa_smmu_uc_cb_probe(struct device *dev) } pr_info("IPA smmu_info.s1_bypass_arr[UC]=%d smmu_info.fast_map=%d\n", - smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC], smmu_info.fast_map); + smmu_info.s1_bypass_arr[IPA_SMMU_CB_UC], + smmu_info.fast_map_arr[IPA_SMMU_CB_UC]); IPADBG("UC CB PROBE sub pdev=%pK attaching IOMMU device\n", dev); ret = arm_iommu_attach_device(cb->dev, cb->mapping); @@ -8251,6 +8263,8 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) u32 size_p; phys_addr_t iova; phys_addr_t pa; + u32 geometry_mapping[2]; + struct iommu_domain_geometry geometry = {0}; IPADBG("AP CB probe: sub pdev=%pK\n", dev); @@ -8265,6 +8279,9 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) IPAERR("Fail to read AP start/size iova addresses\n"); return result; } + if (of_property_read_bool(dev->of_node, + "qcom,smmu-fast-map")) + smmu_info.fast_map_arr[IPA_SMMU_CB_AP] = true; cb->va_start = iova_ap_mapping[0]; cb->va_size = iova_ap_mapping[1]; cb->va_end = cb->va_start + cb->va_size; @@ -8325,7 +8342,8 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) } IPADBG("AP/USB SMMU atomic set\n"); - if (smmu_info.fast_map) { + if (smmu_info.fast_map_arr[IPA_SMMU_CB_AP] || + smmu_info.fast_map) { if (iommu_domain_set_attr(cb->mapping->domain, DOMAIN_ATTR_FAST, &fast)) { @@ -8335,11 +8353,26 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) return -EIO; } IPADBG("SMMU fast map set\n"); + result = of_property_read_u32_array(dev->of_node, + "qcom,geometry-mapping", + geometry_mapping, 2); + if (!result) { + IPAERR("AP Geometry start = %x size= %x\n", + geometry_mapping[0], geometry_mapping[1]); + geometry.aperture_start = geometry_mapping[0]; + geometry.aperture_end = geometry_mapping[1]; + if (iommu_domain_set_attr(cb->mapping->domain, + DOMAIN_ATTR_GEOMETRY, &geometry)) { + IPAERR("Failed to set AP GEOMETRY\n"); + return -EIO; + } + } } } pr_info("IPA smmu_info.s1_bypass_arr[AP]=%d smmu_info.fast_map=%d\n", - smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP], smmu_info.fast_map); + smmu_info.s1_bypass_arr[IPA_SMMU_CB_AP], + smmu_info.fast_map_arr[IPA_SMMU_CB_AP]); result = arm_iommu_attach_device(cb->dev, cb->mapping); if (result) { -- GitLab From b1054302cb13a61c712cc96a2be1f4ec358ff24b Mon Sep 17 00:00:00 2001 From: Ashok Vuyyuru Date: Fri, 12 Jun 2020 13:43:19 +0530 Subject: [PATCH 0898/1055] ARM: dts: msm: Add support to enable/disable fastmap for each CB In IPA driver till fastmap DT flag was using commonly for all nodes. Adding changes to support to enable/disable fastmap for each CB and geometry range for AP node. Change-Id: Ia93ad024e7611cdbdb1f79281d6e1d20c7d19ed4 Signed-off-by: Ashok Vuyyuru --- arch/arm64/boot/dts/qcom/sdxprairie.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index b2e0fb5853bf..8548d20c3808 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -547,7 +547,6 @@ qcom,use-ipa-pm; qcom,use-xbl-boot; qcom,arm-smmu; - qcom,smmu-fast-map; qcom,wlan-ce-db-over-pcie; qcom,bandwidth-vote-for-ipa; qcom,msm-bus,name = "ipa"; @@ -608,6 +607,8 @@ /* modem tables in IMEM */ <0x14688000 0x14688000 0x3000>; qcom,ipa-q6-smem-size = <26624>; + qcom,smmu-fast-map; + qcom,geometry-mapping = <0x0 0xF0000000>; }; ipa_smmu_wlan: ipa_smmu_wlan { -- GitLab From 465494eea833daed92967b34c4996bb3f906e321 Mon Sep 17 00:00:00 2001 From: Ashok Vuyyuru Date: Tue, 16 Jun 2020 17:42:38 +0530 Subject: [PATCH 0899/1055] msm: ipa3: Fix to map the npn phy address only once Ethenet driver npn phy address was same for UL/DL pipes, currently this address was mapped twice. Added changes to map the map npn phy address only once. Change-Id: Icd713943326aad38ecf8e080a73d1d6bb8f641d2 Signed-off-by: Ashok Vuyyuru --- .../msm/ipa/ipa_clients/ipa_uc_offload.c | 4 ++ drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c | 47 ++++++++++--------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c index 042ed5b0eb2c..7090b63f4cc3 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_uc_offload.c @@ -592,6 +592,10 @@ int ipa_uc_offload_conn_pipes(struct ipa_uc_offload_conn_in_params *inp, return -EPERM; } + /*Store the connection info, required during disconnect pipe */ + memcpy(&offload_ctx->conn, &inp->u.ntn, + sizeof(struct ipa_ntn_conn_in_params)); + switch (offload_ctx->proto) { case IPA_UC_NTN: ret = ipa_uc_ntn_conn_pipes(&inp->u.ntn, &outp->u.ntn, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c index c35c54e78e86..e3be643c3d0c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_ntn.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020, 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 @@ -263,7 +263,7 @@ static int ipa3_uc_send_ntn_setup_pipe_cmd( } static int ipa3_smmu_map_uc_ntn_pipes(struct ipa_ntn_setup_info *params, - bool map) + bool map, bool map_unmap_once) { struct iommu_domain *smmu_domain; int result; @@ -279,14 +279,16 @@ static int ipa3_smmu_map_uc_ntn_pipes(struct ipa_ntn_setup_info *params, return -EINVAL; } - result = ipa3_smmu_map_peer_reg(rounddown(params->ntn_reg_base_ptr_pa, - PAGE_SIZE), map, IPA_SMMU_CB_UC); - if (result) { - IPAERR("failed to %s uC regs %d\n", - map ? "map" : "unmap", result); - goto fail; + if (map_unmap_once) { + result = ipa3_smmu_map_peer_reg(rounddown( + params->ntn_reg_base_ptr_pa, PAGE_SIZE), + map, IPA_SMMU_CB_UC); + if (result) { + IPAERR("failed to %s uC regs %d\n", + map ? "map" : "unmap", result); + goto fail; + } } - if (params->smmu_enabled) { IPADBG("smmu is enabled on EMAC\n"); result = ipa3_smmu_map_peer_buff((u64)params->ring_base_iova, @@ -349,14 +351,13 @@ static int ipa3_smmu_map_uc_ntn_pipes(struct ipa_ntn_setup_info *params, IPAERR("Fail to map 0x%llx\n", iova); } else { result = iommu_unmap(smmu_domain, iova_p, size_p); - if (result != params->data_buff_size) + if (result != size_p) { IPAERR("Fail to unmap 0x%llx\n", iova); - } - if (result) { - if (params->smmu_enabled) - goto fail_map_data_buff_smmu_enabled; - else - goto fail_map_data_buff_smmu_disabled; + if (params->smmu_enabled) + goto fail_map_data_buff_smmu_enabled; + else + goto fail_map_data_buff_smmu_disabled; + } } } return 0; @@ -396,6 +397,7 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, int ipa_ep_idx_ul; int ipa_ep_idx_dl; int result = 0; + bool unmapped = false; if (in == NULL) { IPAERR("invalid input\n"); @@ -449,7 +451,7 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, goto fail; } - result = ipa3_smmu_map_uc_ntn_pipes(&in->ul, true); + result = ipa3_smmu_map_uc_ntn_pipes(&in->ul, true, true); if (result) { IPAERR("failed to map SMMU for UL %d\n", result); goto fail; @@ -488,7 +490,7 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, goto fail_disable_dp_ul; } - result = ipa3_smmu_map_uc_ntn_pipes(&in->dl, true); + result = ipa3_smmu_map_uc_ntn_pipes(&in->dl, true, false); if (result) { IPAERR("failed to map SMMU for DL %d\n", result); goto fail_disable_dp_ul; @@ -519,11 +521,12 @@ int ipa3_setup_uc_ntn_pipes(struct ipa_ntn_conn_in_params *in, fail_disable_dp_dl: ipa3_disable_data_path(ipa_ep_idx_dl); fail_smmu_unmap_dl: - ipa3_smmu_map_uc_ntn_pipes(&in->dl, false); + ipa3_smmu_map_uc_ntn_pipes(&in->dl, false, true); + unmapped = true; fail_disable_dp_ul: ipa3_disable_data_path(ipa_ep_idx_ul); fail_smmu_unmap_ul: - ipa3_smmu_map_uc_ntn_pipes(&in->ul, false); + ipa3_smmu_map_uc_ntn_pipes(&in->ul, false, !unmapped); fail: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return result; @@ -603,7 +606,7 @@ int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, } /* unmap the DL pipe */ - result = ipa3_smmu_map_uc_ntn_pipes(¶ms->dl, false); + result = ipa3_smmu_map_uc_ntn_pipes(¶ms->dl, false, true); if (result) { IPAERR("failed to unmap SMMU for DL %d\n", result); goto fail; @@ -624,7 +627,7 @@ int ipa3_tear_down_uc_offload_pipes(int ipa_ep_idx_ul, } /* unmap the UL pipe */ - result = ipa3_smmu_map_uc_ntn_pipes(¶ms->ul, false); + result = ipa3_smmu_map_uc_ntn_pipes(¶ms->ul, false, false); if (result) { IPAERR("failed to unmap SMMU for UL %d\n", result); goto fail; -- GitLab From dcdac345369a376a8f8fbb8e4426f5696fdb24ef Mon Sep 17 00:00:00 2001 From: Anuj Garg Date: Mon, 22 Jun 2020 14:04:58 +0530 Subject: [PATCH 0900/1055] ARM: dts: msm: Remove the pil-force-shutdown flag Remove pil-force-shutdown flag for adsp so that PIL driver should not forcefully shutdown the adsp subsystem. Change-Id: I88f9caaa9c413003e154be3f0fdc44aa633c0334 Signed-off-by: Anuj Garg --- arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi | 1 - arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi | 1 - arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi | 1 - 3 files changed, 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi b/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi index fe487e89b0fd..4b73b902333b 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-air.dtsi @@ -35,7 +35,6 @@ &soc { qcom,lpass@62400000 { status = "ok"; - qcom,pil-force-shutdown; }; qcom,glink { diff --git a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi index 3d9bb16fbda5..1ecae102b065 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-adp-star.dtsi @@ -35,7 +35,6 @@ &soc { qcom,lpass@62400000 { status = "ok"; - qcom,pil-force-shutdown; }; qcom,glink { diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi index 133e874c038b..9f47fd1779ee 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-common.dtsi @@ -80,7 +80,6 @@ &soc { qcom,lpass@17300000 { status = "ok"; - qcom,pil-force-shutdown; }; qcom,ssc@5c00000 { -- GitLab From a7d2d271af8b7fad63010d02318cf22f787d2360 Mon Sep 17 00:00:00 2001 From: Chandrasekhar Mattaparthy Date: Wed, 10 Jun 2020 12:23:40 +0530 Subject: [PATCH 0901/1055] soc: qcom: Add bgcom driver for sdm429w The driver loads the BG firmware into memory and sends a command to the secure userspace application to initiate secure transfer of the BG firmware into internal memory of BG and reset BG. The subsystem restart depends on GPIOs present between SDM429W and BG. Change-Id: I7122824da2814b37a82f4a480068a5677970db7d Signed-off-by: Chandrasekhar Mattaparthy --- .../bindings/soc/qcom/bg_daemon.txt | 20 + .../devicetree/bindings/soc/qcom/bg_spi.txt | 24 + drivers/soc/qcom/Kconfig | 18 + drivers/soc/qcom/Makefile | 2 + drivers/soc/qcom/bgcom.h | 214 ++++ drivers/soc/qcom/bgcom_interface.c | 784 ++++++++++++ drivers/soc/qcom/bgcom_interface.h | 36 + drivers/soc/qcom/bgcom_spi.c | 1131 +++++++++++++++++ drivers/soc/qcom/bgrsb.h | 36 + include/uapi/linux/bgcom_interface.h | 84 ++ 10 files changed, 2349 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt create mode 100644 Documentation/devicetree/bindings/soc/qcom/bg_spi.txt create mode 100644 drivers/soc/qcom/bgcom.h create mode 100644 drivers/soc/qcom/bgcom_interface.c create mode 100644 drivers/soc/qcom/bgcom_interface.h create mode 100644 drivers/soc/qcom/bgcom_spi.c create mode 100644 drivers/soc/qcom/bgrsb.h create mode 100644 include/uapi/linux/bgcom_interface.h diff --git a/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt b/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt new file mode 100644 index 000000000000..7da17b41529f --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/bg_daemon.txt @@ -0,0 +1,20 @@ +Qualcomm Technologies Inc. bg-daemon + +BG-Daemon : When Modem goes down, to re-establish the connections, +BG-Daemon toggles the bg-reset gpio to reset BG. + +Required properties: +- compatible : should be "qcom,bg-daemon" +- qcom,bg-reset-gpio : gpio for the apps processor use to soft reset BG +- ssr-reg1-supply : Power supply needed to power up the BG device. + When BG brought up this regulator will be in normal power mode. +- ssr-reg2-supply : Power supply needed to power up the BG device. + When BG BG brought up this regulator will be in normal power mode. + +Example: + qcom,bg-daemon { + compatible = "qcom,bg-daemon"; + qcom,bg-reset-gpio = <&pm660_gpios 5 0>; + ssr-reg1-supply = <&pm660_l3>; + ssr-reg2-supply = <&pm660_l9>; + }; diff --git a/Documentation/devicetree/bindings/soc/qcom/bg_spi.txt b/Documentation/devicetree/bindings/soc/qcom/bg_spi.txt new file mode 100644 index 000000000000..e9a28a953c47 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/bg_spi.txt @@ -0,0 +1,24 @@ +Qualcomm technologies Inc bg-spi + +BG-COM SPI : bg-spi is used for the communication with Blackghost +chipset. It uses SPI protocol for communication. +BG-COM: bgcome is a thin transport layer over glink which provides +the read/write APIs to communicate with Blackghost chipset. + +Required properties: +- compatible : should be "qcom,bg-spi" +- spi-max-frequency : Maximum SPI clocking speed of device in Hz +- qcom,irq-gpio : GPIO pin +- reg : Register set + +Example: + spi@78b6000 { /* BLSP1 QUP2 */ + status = "ok"; + qcom,bg-spi { + compatible = "qcom,bg-spi"; + reg = <0>; + spi-max-frequency = <19200000>; + interrupt-parent = <&msm_gpio>; + qcom,irq-gpio = <&msm_gpio 110 1>; + }; + }; diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index dbd5759e94de..d68383deb3f4 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -1005,6 +1005,24 @@ config MSM_BAM_DMUX provides a means to support more logical channels via muxing than BAM could without muxing. + config MSM_BGCOM_INTERFACE + bool "Driver support for Blackghost Communication" + depends on MSM_BGCOM + help + Create a bg_com_dev device node for user space communication. + Single user space client can open device node for communication + from hardware. Hardware will provide access to read + registers and read/write AHB memory in the device. + + + config MSM_BGCOM + bool "Provide APIs to communicate with Blackghost chipset" + help + BGCOM is a thin layer above SPI. It is used whithin a SoC for + communication between G-Link/bg_com_dev and BG processor over SPI. + This handle the interrupts raised by BG and notify the G-link with + interrupt event and event data. + config QCOM_SOC_INFO bool "Chip information for QTI SoCs" depends on SOC_BUS diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 53f7674bab11..45b3a90ec21c 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -95,6 +95,8 @@ ifdef CONFIG_MSM_RPM_SMD obj-$(CONFIG_QTI_RPM_STATS_LOG) += rpm_master_stat.o endif obj-$(CONFIG_QMP_DEBUGFS_CLIENT) += qmp-debugfs-client.o +obj-$(CONFIG_MSM_BGCOM) += bgcom_spi.o +obj-$(CONFIG_MSM_BGCOM_INTERFACE) += bgcom_interface.o obj-$(CONFIG_MSM_PERFORMANCE) += msm_performance.o obj-$(CONFIG_MSM_DRM_NOTIFY) += msm_drm_notify.o ifdef CONFIG_DEBUG_FS diff --git a/drivers/soc/qcom/bgcom.h b/drivers/soc/qcom/bgcom.h new file mode 100644 index 000000000000..56f12d0a973c --- /dev/null +++ b/drivers/soc/qcom/bgcom.h @@ -0,0 +1,214 @@ +/* Copyright (c) 2017-2018,2020 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 BGCOM_H +#define BGCOM_H + +#define BGCOM_REG_TZ_TO_MASTER_STATUS 0x01 +#define BGCOM_REG_TZ_TO_MASTER_DATA 0x03 +#define BGCOM_REG_SLAVE_STATUS 0x05 +#define BGCOM_REG_TIMESTAMP 0x07 +#define BGCOM_REG_SLAVE_STATUS_AUTO_CLEAR 0x09 +#define BGCOM_REG_FIFO_FILL 0x0B +#define BGCOM_REG_FIFO_SIZE 0x0D +#define BGCOM_REG_TZ_TO_SLAVE_COMMAND 0x0E +#define BGCOM_REG_TZ_TO_SLAVE_DATA 0x10 +#define BGCOM_REG_MASTER_STATUS 0x12 +#define BGCOM_REG_MASTER_COMMAND 0x14 +#define BGCOM_REG_MSG_WR_REG_4 0x16 +#define BGCOM_REG_TO_SLAVE_FIFO 0x40 +#define BGCOM_REG_TO_MASTER_FIFO 0x41 +#define BGCOM_REG_TO_SLAVE_AHB 0x42 +#define BGCOM_REG_TO_MASTER_AHB 0x43 + +/* Enum to define the bgcom SPI state */ +enum bgcom_spi_state { + BGCOM_SPI_FREE = 0, + BGCOM_SPI_BUSY, +}; + +/* Enums to identify Blackghost events */ +enum bgcom_event_type { + BGCOM_EVENT_NONE = 0, + BGCOM_EVENT_APPLICATION_RUNNING, + BGCOM_EVENT_TO_SLAVE_FIFO_READY, + BGCOM_EVENT_TO_MASTER_FIFO_READY, + BGCOM_EVENT_AHB_READY, + BGCOM_EVENT_TO_MASTER_FIFO_USED, + BGCOM_EVENT_TO_SLAVE_FIFO_FREE, + BGCOM_EVENT_TIMESTAMP_UPDATE, + BGCOM_EVENT_RESET_OCCURRED, + + BGCOM_EVENT_ERROR_WRITE_FIFO_OVERRUN, + BGCOM_EVENT_ERROR_WRITE_FIFO_BUS_ERR, + BGCOM_EVENT_ERROR_WRITE_FIFO_ACCESS, + BGCOM_EVENT_ERROR_READ_FIFO_UNDERRUN, + BGCOM_EVENT_ERROR_READ_FIFO_BUS_ERR, + BGCOM_EVENT_ERROR_READ_FIFO_ACCESS, + BGCOM_EVENT_ERROR_TRUNCATED_READ, + BGCOM_EVENT_ERROR_TRUNCATED_WRITE, + BGCOM_EVENT_ERROR_AHB_ILLEGAL_ADDRESS, + BGCOM_EVENT_ERROR_AHB_BUS_ERR, + BGCOM_EVENT_ERROR_UNKNOWN, +}; + +/* Event specific data */ +union bgcom_event_data_type { + uint32_t unused; + bool application_running; /* BGCOM_EVENT_APPLICATION_RUNNING */ + bool to_slave_fifo_ready; /* BGCOM_EVENT_TO_SLAVE_FIFO_READY */ + bool to_master_fifo_ready; /* BGCOM_EVENT_TO_MASTER_FIFO_READY */ + bool ahb_ready; /* BGCOM_EVENT_AHB_READY */ + uint16_t to_slave_fifo_free; /* BGCOM_EVENT_TO_SLAVE_FIFO_FREE */ + struct fifo_event_data { + uint16_t to_master_fifo_used; + void *data; + } fifo_data; +}; + +/* Client specific data */ +struct bgcom_open_config_type { + /** Private data pointer for client to maintain context. + * This data is passed back to client in the notification callbacks. + */ + void *priv; + + /* Notification callbacks to notify the BG events */ + void (*bgcom_notification_cb)(void *handle, void *priv, + enum bgcom_event_type event, + union bgcom_event_data_type *event_data); +}; + +/** + * bgcom_open() - opens a channel to interact with Blackghost + * @open_config: pointer to the open configuration structure + * + * Open a new connection to blackghost + * + * Return a handle on success or NULL on error + */ +void *bgcom_open(struct bgcom_open_config_type *open_config); + +/** + * bgcom_close() - close the exsting with Blackghost + * @handle: pointer to the handle, provided by bgcom at + * bgcom_open + * + * Open a new connection to blackghost + * + * Return 0 on success or error on invalid handle + */ +int bgcom_close(void **handle); + +/** + * bgcom_reg_read() - Read from the one or more contiguous registers from BG + * @handle: BGCOM handle associated with the channel + * @reg_start_addr : 8 bit start address of the registers to read from + * @num_regs : Number of contiguous registers to read, starting + * from reg_start_addr. + * @read_buf : Buffer to read from the registers. + * Return 0 on success or -Ve on error + */ +int bgcom_reg_read(void *handle, uint8_t reg_start_addr, + uint32_t num_regs, void *read_buf); + +/** + * Write into the one or more contiguous registers. + * + * @param[in] handle BGCOM handle associated with the channel. + * @param[in] reg_start_addr 8bit start address of the registers to write into. + * @param[in] num_regs Number of contiguous registers to write, starting + * from reg_start_addr. + * @param[in] write_buf Buffer to write into the registers. + * + * @return + * 0 if function is successful, + * Otherwise returns error code. + * + * @sideeffects Causes the Blackghost SPI slave to wakeup. Depending up on + * the operation, it may also wakeup the complete Blackghost. + */ + +/** + * bgcom_reg_write() - Write to the one or more contiguous registers on BG + * @handle: BGCOM handle associated with the channel + * @reg_start_addr : 8 bit start address of the registers to read from + * @num_regs : Number of contiguous registers to write, starting + * from reg_start_addr. + * @write_buf : Buffer to be written to the registers. + * Return 0 on success or -Ve on error + */ +int bgcom_reg_write(void *handle, uint8_t reg_start_addr, + uint8_t num_regs, void *write_buf); + +/** + * bgcom_fifo_read() - Read data from the TO_MASTER_FIFO. + * @handle: BGCOM handle associated with the channel + * @num_words : number of words to read from FIFO + * @read_buf : Buffer read from FIFO. + * Return 0 on success or -Ve on error + */ +int bgcom_fifo_read(void *handle, uint32_t num_words, + void *read_buf); + +/** + * bgcom_fifo_write() - Write data to the TO_SLAVE_FIFO. + * @handle: BGCOM handle associated with the channel + * @num_words : number of words to write on FIFO + * @write_buf : Buffer written to FIFO. + * Return 0 on success or -Ve on error + */ +int bgcom_fifo_write(void *handle, uint32_t num_words, + void *write_buf); + +/** + * bgcom_ahb_read() - Read data from the AHB memory. + * @handle: BGCOM handle associated with the channel + * @ahb_start_addr : Memory start address from where to read + * @num_words : number of words to read from AHB + * @read_buf : Buffer read from FIFO. + * Return 0 on success or -Ve on error + */ +int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr, + uint32_t num_words, void *read_buf); + +/** + * bgcom_ahb_write() - Write data to the AHB memory. + * @handle: BGCOM handle associated with the channel + * @ahb_start_addr : Memory start address from where to start write + * @num_words : number of words to read from AHB + * @write_buf : Buffer to write in AHB. + * Return 0 on success or -Ve on error + */ +int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, + uint32_t num_words, void *write_buf); + +/** + * bgcom_suspend() - Suspends the channel. + * @handle: BGCOM handle associated with the channel + * Return 0 on success or -Ve on error + */ +int bgcom_suspend(void *handle); + +/** + * bgcom_resume() - Resumes the channel. + * @handle: BGCOM handle associated with the channel + * Return 0 on success or -Ve on error + */ +int bgcom_resume(void *handle); + +int bgcom_set_spi_state(enum bgcom_spi_state state); + +void bgcom_bgdown_handler(void); + +#endif /* BGCOM_H */ diff --git a/drivers/soc/qcom/bgcom_interface.c b/drivers/soc/qcom/bgcom_interface.c new file mode 100644 index 000000000000..bcb51a249e54 --- /dev/null +++ b/drivers/soc/qcom/bgcom_interface.c @@ -0,0 +1,784 @@ +/* Copyright (c) 2017-2020, 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. + * + */ +#define pr_fmt(msg) "bgcom_dev:" msg + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bgcom.h" +#include "linux/bgcom_interface.h" +#include "bgcom_interface.h" +#include +#include +#include +#include +#include +#include + +#define BGCOM "bg_com_dev" + +#define BGDAEMON_LDO09_LPM_VTG 0 +#define BGDAEMON_LDO09_NPM_VTG 10000 + +#define BGDAEMON_LDO03_LPM_VTG 0 +#define BGDAEMON_LDO03_NPM_VTG 10000 + +#define MPPS_DOWN_EVENT_TO_BG_TIMEOUT 3000 +#define ADSP_DOWN_EVENT_TO_BG_TIMEOUT 3000 +#define SLEEP_FOR_SPI_BUS 2000 + +enum { + SSR_DOMAIN_BG, + SSR_DOMAIN_MODEM, + SSR_DOMAIN_ADSP, + SSR_DOMAIN_MAX, +}; + +enum ldo_task { + ENABLE_LDO03, + ENABLE_LDO09, + DISABLE_LDO03, + DISABLE_LDO09 +}; + +struct bgdaemon_regulator { + struct regulator *regldo03; + struct regulator *regldo09; +}; + +struct bgdaemon_priv { + struct bgdaemon_regulator rgltr; + enum ldo_task ldo_action; + void *pil_h; + bool pending_bg_twm_wear_load; + struct workqueue_struct *bgdaemon_wq; + struct work_struct bgdaemon_load_twm_bg_work; + bool bg_twm_wear_load; +}; + +struct bg_event { + enum bg_event_type e_type; +}; + +struct service_info { + const char name[32]; + int domain_id; + void *handle; + struct notifier_block *nb; +}; + +static char *ssr_domains[] = { + "bg-wear", + "modem", + "adsp", +}; + +static struct bgdaemon_priv *dev; +static unsigned int bgreset_gpio; +static DEFINE_MUTEX(bg_char_mutex); +static struct cdev bg_cdev; +static struct class *bg_class; +struct device *dev_ret; +static dev_t bg_dev; +static int device_open; +static void *handle; +static bool twm_exit; +static bool bg_app_running; +static struct bgcom_open_config_type config_type; +static DECLARE_COMPLETION(bg_modem_down_wait); +static DECLARE_COMPLETION(bg_adsp_down_wait); + +/** + * send_uevent(): send events to user space + * pce : ssr event handle value + * Return: 0 on success, standard Linux error code on error + * + * It adds pce value to event and broadcasts to user space. + */ +static int send_uevent(struct bg_event *pce) +{ + char event_string[32]; + char *envp[2] = { event_string, NULL }; + + snprintf(event_string, ARRAY_SIZE(event_string), + "BG_EVENT=%d", pce->e_type); + return kobject_uevent_env(&dev_ret->kobj, KOBJ_CHANGE, envp); +} + +static void bgcom_load_twm_bg_work(struct work_struct *work) +{ + if (dev->pil_h) { + pr_err("bg-wear is already loaded\n"); + subsystem_put(dev->pil_h); + dev->pil_h = NULL; + bg_soft_reset(); + } else { + dev->bg_twm_wear_load = true; + dev->pil_h = subsystem_get_with_fwname("bg-wear", + "bg-twm-wear"); + if (!dev->pil_h) + pr_err("failed to load bg-twm-wear\n"); + } +} + +static int bgdaemon_configure_regulators(bool state) +{ + int retval; + + if (state == true) { + retval = regulator_enable(dev->rgltr.regldo03); + if (retval) + pr_err("Failed to enable LDO-03 regulator:%d\n", + retval); + retval = regulator_enable(dev->rgltr.regldo09); + if (retval) + pr_err("Failed to enable LDO-09 regulator:%d\n", + retval); + } + if (state == false) { + retval = regulator_disable(dev->rgltr.regldo03); + if (retval) + pr_err("Failed to disable LDO-03 regulator:%d\n", + retval); + retval = regulator_disable(dev->rgltr.regldo09); + if (retval) + pr_err("Failed to disable LDO-09 regulator:%d\n", + retval); + } + return retval; +} + +static int bgdaemon_init_regulators(struct device *pdev) +{ + int rc; + struct regulator *reg03; + struct regulator *reg09; + + reg03 = regulator_get(pdev, "ssr-reg1"); + if (IS_ERR_OR_NULL(reg03)) { + rc = PTR_ERR(reg03); + pr_err("Unable to get regulator for LDO-03\n"); + goto err_ret; + } + reg09 = regulator_get(pdev, "ssr-reg2"); + if (IS_ERR_OR_NULL(reg09)) { + rc = PTR_ERR(reg09); + pr_err("Unable to get regulator for LDO-09\n"); + goto err_ret; + } + dev->rgltr.regldo03 = reg03; + dev->rgltr.regldo09 = reg09; + return 0; +err_ret: + return rc; +} + +static int bgdaemon_ldowork(enum ldo_task do_action) +{ + int ret; + + switch (do_action) { + case ENABLE_LDO03: + ret = regulator_set_load(dev->rgltr.regldo03, + BGDAEMON_LDO03_NPM_VTG); + if (ret < 0) { + pr_err("Failed to request LDO-03 voltage:%d\n", + ret); + goto err_ret; + } + break; + case ENABLE_LDO09: + ret = regulator_set_load(dev->rgltr.regldo09, + BGDAEMON_LDO09_NPM_VTG); + if (ret < 0) { + pr_err("Failed to request LDO-09 voltage:%d\n", + ret); + goto err_ret; + } + break; + case DISABLE_LDO03: + ret = regulator_set_load(dev->rgltr.regldo03, + BGDAEMON_LDO03_LPM_VTG); + if (ret < 0) { + pr_err("Failed to disable LDO-03:%d\n", ret); + goto err_ret; + } + break; + case DISABLE_LDO09: + ret = regulator_set_load(dev->rgltr.regldo09, + BGDAEMON_LDO09_LPM_VTG); + if (ret < 0) { + pr_err("Failed to disable LDO-09:%d\n", ret); + goto err_ret; + } + break; + default: + ret = -EINVAL; + } + +err_ret: + return ret; +} + +static int bgcom_char_open(struct inode *inode, struct file *file) +{ + int ret; + + mutex_lock(&bg_char_mutex); + if (device_open == 1) { + pr_err("device is already open\n"); + mutex_unlock(&bg_char_mutex); + return -EBUSY; + } + device_open++; + handle = bgcom_open(&config_type); + mutex_unlock(&bg_char_mutex); + if (IS_ERR(handle)) { + device_open = 0; + ret = PTR_ERR(handle); + handle = NULL; + return ret; + } + return 0; +} + +static int bgchar_read_cmd(struct bg_ui_data *fui_obj_msg, + int type) +{ + void *read_buf; + int ret; + void __user *result = (void *) + (uintptr_t)fui_obj_msg->result; + + read_buf = kmalloc_array(fui_obj_msg->num_of_words, sizeof(uint32_t), + GFP_KERNEL); + if (read_buf == NULL) + return -ENOMEM; + switch (type) { + case REG_READ: + ret = bgcom_reg_read(handle, fui_obj_msg->cmd, + fui_obj_msg->num_of_words, + read_buf); + break; + case AHB_READ: + ret = bgcom_ahb_read(handle, + fui_obj_msg->bg_address, + fui_obj_msg->num_of_words, + read_buf); + break; + } + if (!ret && copy_to_user(result, read_buf, + fui_obj_msg->num_of_words * sizeof(uint32_t))) { + pr_err("copy to user failed\n"); + ret = -EFAULT; + } + kfree(read_buf); + return ret; +} + +static int bgchar_write_cmd(struct bg_ui_data *fui_obj_msg, int type) +{ + void *write_buf; + int ret = -EINVAL; + void __user *write = (void *) + (uintptr_t)fui_obj_msg->write; + + write_buf = kmalloc_array(fui_obj_msg->num_of_words, sizeof(uint32_t), + GFP_KERNEL); + if (write_buf == NULL) + return -ENOMEM; + write_buf = memdup_user(write, + fui_obj_msg->num_of_words * sizeof(uint32_t)); + if (IS_ERR(write_buf)) { + ret = PTR_ERR(write_buf); + kfree(write_buf); + return ret; + } + switch (type) { + case REG_WRITE: + ret = bgcom_reg_write(handle, fui_obj_msg->cmd, + fui_obj_msg->num_of_words, + write_buf); + break; + case AHB_WRITE: + ret = bgcom_ahb_write(handle, + fui_obj_msg->bg_address, + fui_obj_msg->num_of_words, + write_buf); + break; + } + kfree(write_buf); + return ret; +} + +int bg_soft_reset(void) +{ + pr_debug("do BG reset using gpio %d\n", bgreset_gpio); + if (!gpio_is_valid(bgreset_gpio)) { + pr_err("gpio %d is not valid\n", bgreset_gpio); + return -ENXIO; + } + if (gpio_direction_output(bgreset_gpio, 1)) + pr_err("gpio %d direction not set\n", bgreset_gpio); + + /* Sleep for 50ms for hardware to detect signal as high */ + msleep(50); + + gpio_set_value(bgreset_gpio, 0); + + /* Sleep for 50ms for hardware to detect signal as high */ + msleep(50); + gpio_set_value(bgreset_gpio, 1); + + return 0; +} +EXPORT_SYMBOL(bg_soft_reset); + +static int modem_down2_bg(void) +{ + complete(&bg_modem_down_wait); + return 0; +} + +static int adsp_down2_bg(void) +{ + complete(&bg_adsp_down_wait); + return 0; +} + +static long bg_com_ioctl(struct file *filp, + unsigned int ui_bgcom_cmd, unsigned long arg) +{ + int ret; + struct bg_ui_data ui_obj_msg; + + switch (ui_bgcom_cmd) { + case REG_READ: + case AHB_READ: + if (copy_from_user(&ui_obj_msg, (void __user *) arg, + sizeof(ui_obj_msg))) { + pr_err("The copy from user failed\n"); + ret = -EFAULT; + } + ret = bgchar_read_cmd(&ui_obj_msg, + ui_bgcom_cmd); + if (ret < 0) + pr_err("bgchar_read_cmd failed\n"); + break; + case AHB_WRITE: + case REG_WRITE: + if (copy_from_user(&ui_obj_msg, (void __user *) arg, + sizeof(ui_obj_msg))) { + pr_err("The copy from user failed\n"); + ret = -EFAULT; + } + ret = bgchar_write_cmd(&ui_obj_msg, ui_bgcom_cmd); + if (ret < 0) + pr_err("bgchar_write_cmd failed\n"); + break; + case SET_SPI_FREE: + ret = bgcom_set_spi_state(BGCOM_SPI_FREE); + break; + case SET_SPI_BUSY: + ret = bgcom_set_spi_state(BGCOM_SPI_BUSY); + /* Add sleep for SPI Bus to release*/ + msleep(SLEEP_FOR_SPI_BUS); + break; + case BG_SOFT_RESET: + ret = bg_soft_reset(); + break; + case BG_MODEM_DOWN2_BG_DONE: + ret = modem_down2_bg(); + break; + case BG_ADSP_DOWN2_BG_DONE: + ret = adsp_down2_bg(); + case BG_TWM_EXIT: + twm_exit = true; + ret = 0; + break; + case BG_APP_RUNNING: + bg_app_running = true; + ret = 0; + break; + case BG_WEAR_LOAD: + ret = 0; + if (dev->pil_h) { + pr_err("bg-wear is already loaded\n"); + ret = -EFAULT; + break; + } + dev->bg_twm_wear_load = false; + dev->pil_h = subsystem_get_with_fwname("bg-wear", "bg-wear"); + if (!dev->pil_h) { + pr_err("failed to load bg-wear\n"); + ret = -EFAULT; + } + break; + case BG_WEAR_TWM_LOAD: + dev->pending_bg_twm_wear_load = true; + queue_work(dev->bgdaemon_wq, &dev->bgdaemon_load_twm_bg_work); + ret = 0; + break; + case BG_WEAR_UNLOAD: + if (dev->pil_h) { + subsystem_put(dev->pil_h); + dev->pil_h = NULL; + bg_soft_reset(); + } + ret = 0; + break; + default: + ret = -ENOIOCTLCMD; + break; + } + return ret; +} + +static int bgcom_char_close(struct inode *inode, struct file *file) +{ + int ret; + + mutex_lock(&bg_char_mutex); + ret = bgcom_close(&handle); + device_open = 0; + mutex_unlock(&bg_char_mutex); + return ret; +} + +static int bg_daemon_probe(struct platform_device *pdev) +{ + struct device_node *node; + unsigned int reset_gpio; + int ret; + + node = pdev->dev.of_node; + + pr_info("%s started", __func__); + + dev = kzalloc(sizeof(struct bgdaemon_priv), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + reset_gpio = of_get_named_gpio(node, "qcom,bg-reset-gpio", 0); + if (!gpio_is_valid(reset_gpio)) { + pr_err("gpio %d found is not valid\n", reset_gpio); + goto err_ret; + } + + if (gpio_request(reset_gpio, "bg_reset_gpio")) { + pr_err("gpio %d request failed\n", reset_gpio); + goto err_ret; + } + + if (gpio_direction_output(reset_gpio, 1)) { + pr_err("gpio %d direction not set\n", reset_gpio); + goto err_ret; + } + + pr_info("bg-soft-reset gpio successfully requested\n"); + bgreset_gpio = reset_gpio; + + ret = bgdaemon_init_regulators(&pdev->dev); + if (ret != 0) { + pr_err("Failed to init regulators:%d\n", ret); + goto err_device; + } + ret = bgdaemon_configure_regulators(true); + if (ret) { + pr_err("Failed to confifigure regulators:%d\n", ret); + bgdaemon_configure_regulators(false); + goto err_ret; + } + pr_info("%s success", __func__); + +err_device: + return -ENODEV; +err_ret: + return 0; +} + +static const struct of_device_id bg_daemon_of_match[] = { + { .compatible = "qcom,bg-daemon", }, + { } +}; +MODULE_DEVICE_TABLE(of, bg_daemon_of_match); + +static struct platform_driver bg_daemon_driver = { + .probe = bg_daemon_probe, + .driver = { + .name = "bg-daemon", + .of_match_table = bg_daemon_of_match, + }, +}; + +static const struct file_operations fops = { + .owner = THIS_MODULE, + .open = bgcom_char_open, + .release = bgcom_char_close, + .unlocked_ioctl = bg_com_ioctl, +}; + +static int __init init_bg_com_dev(void) +{ + int ret; + + ret = alloc_chrdev_region(&bg_dev, 0, 1, BGCOM); + if (ret < 0) { + pr_err("failed with error %d\n", ret); + return ret; + } + cdev_init(&bg_cdev, &fops); + ret = cdev_add(&bg_cdev, bg_dev, 1); + if (ret < 0) { + unregister_chrdev_region(bg_dev, 1); + pr_err("device registration failed\n"); + return ret; + } + bg_class = class_create(THIS_MODULE, BGCOM); + if (IS_ERR_OR_NULL(bg_class)) { + cdev_del(&bg_cdev); + unregister_chrdev_region(bg_dev, 1); + pr_err("class creation failed\n"); + return PTR_ERR(bg_class); + } + + dev_ret = device_create(bg_class, NULL, bg_dev, NULL, BGCOM); + if (IS_ERR_OR_NULL(dev_ret)) { + class_destroy(bg_class); + cdev_del(&bg_cdev); + unregister_chrdev_region(bg_dev, 1); + pr_err("device create failed\n"); + return PTR_ERR(dev_ret); + } + + if (platform_driver_register(&bg_daemon_driver)) + pr_err("%s: failed to register bg-daemon register\n", __func__); + + dev->bgdaemon_wq = + create_singlethread_workqueue("bgdaemon-work-queue"); + if (!dev->bgdaemon_wq) { + pr_err("Failed to init BG-DAEMON work-queue\n"); + goto free_wq; + } + INIT_WORK(&dev->bgdaemon_load_twm_bg_work, bgcom_load_twm_bg_work); + + return 0; + +free_wq: + destroy_workqueue(dev->bgdaemon_wq); + return -EFAULT; +} + +static void __exit exit_bg_com_dev(void) +{ + device_destroy(bg_class, bg_dev); + class_destroy(bg_class); + cdev_del(&bg_cdev); + unregister_chrdev_region(bg_dev, 1); + bgdaemon_configure_regulators(false); + platform_driver_unregister(&bg_daemon_driver); +} + +/** + *ssr_bg_cb(): callback function is called + *by ssr framework when BG goes down, up and during ramdump + *collection. It handles BG shutdown and power up events. + */ +static int ssr_bg_cb(struct notifier_block *this, + unsigned long opcode, void *data) +{ + struct bg_event bge; + + switch (opcode) { + case SUBSYS_BEFORE_SHUTDOWN: + bge.e_type = BG_BEFORE_POWER_DOWN; + bgdaemon_ldowork(ENABLE_LDO03); + bgdaemon_ldowork(ENABLE_LDO09); + bgcom_bgdown_handler(); + bgcom_set_spi_state(BGCOM_SPI_BUSY); + send_uevent(&bge); + break; + case SUBSYS_AFTER_SHUTDOWN: + /* Add sleep for SPI Bus to release*/ + msleep(SLEEP_FOR_SPI_BUS); + if (dev->pending_bg_twm_wear_load) { + /* Load bg-twm-wear */ + dev->pending_bg_twm_wear_load = false; + queue_work(dev->bgdaemon_wq, + &dev->bgdaemon_load_twm_bg_work); + } + break; + case SUBSYS_AFTER_POWERUP: + if (dev->bg_twm_wear_load) + bge.e_type = TWM_BG_AFTER_POWER_UP; + else + bge.e_type = BG_AFTER_POWER_UP; + bgdaemon_ldowork(DISABLE_LDO03); + bgdaemon_ldowork(DISABLE_LDO09); + bgcom_set_spi_state(BGCOM_SPI_FREE); + send_uevent(&bge); + break; + } + return NOTIFY_DONE; +} + +/** + *ssr_modem_cb(): callback function is called + *by ssr framework when modem goes down, up and during ramdump + *collection. It handles modem shutdown and power up events. + */ +static int ssr_modem_cb(struct notifier_block *this, + unsigned long opcode, void *data) +{ + struct bg_event modeme; + int ret; + + switch (opcode) { + case SUBSYS_BEFORE_SHUTDOWN: + modeme.e_type = MODEM_BEFORE_POWER_DOWN; + reinit_completion(&bg_modem_down_wait); + send_uevent(&modeme); + ret = wait_for_completion_timeout(&bg_modem_down_wait, + msecs_to_jiffies(MPPS_DOWN_EVENT_TO_BG_TIMEOUT)); + if (!ret) + pr_err("Time out on modem down event\n"); + break; + case SUBSYS_AFTER_POWERUP: + modeme.e_type = MODEM_AFTER_POWER_UP; + send_uevent(&modeme); + break; + } + return NOTIFY_DONE; +} + +static int ssr_adsp_cb(struct notifier_block *this, + unsigned long opcode, void *data) +{ + struct bg_event adspe; + int ret; + + switch (opcode) { + case SUBSYS_BEFORE_SHUTDOWN: + adspe.e_type = ADSP_BEFORE_POWER_DOWN; + reinit_completion(&bg_adsp_down_wait); + send_uevent(&adspe); + ret = wait_for_completion_timeout(&bg_adsp_down_wait, + msecs_to_jiffies(ADSP_DOWN_EVENT_TO_BG_TIMEOUT)); + if (!ret) + pr_err("Time out on adsp down event\n"); + break; + case SUBSYS_AFTER_POWERUP: + adspe.e_type = ADSP_AFTER_POWER_UP; + send_uevent(&adspe); + break; + } + return NOTIFY_DONE; +} +bool is_twm_exit(void) +{ + if (twm_exit) { + twm_exit = false; + return true; + } + return false; +} +EXPORT_SYMBOL(is_twm_exit); + +bool is_bg_running(void) +{ + if (bg_app_running) { + bg_app_running = false; + return true; + } + return false; +} +EXPORT_SYMBOL(is_bg_running); + +static struct notifier_block ssr_modem_nb = { + .notifier_call = ssr_modem_cb, + .priority = 0, +}; + +static struct notifier_block ssr_adsp_nb = { + .notifier_call = ssr_adsp_cb, + .priority = 0, +}; + +static struct notifier_block ssr_bg_nb = { + .notifier_call = ssr_bg_cb, + .priority = 0, +}; + +static struct service_info service_data[3] = { + { + .name = "SSR_BG", + .domain_id = SSR_DOMAIN_BG, + .nb = &ssr_bg_nb, + .handle = NULL, + }, + { + .name = "SSR_MODEM", + .domain_id = SSR_DOMAIN_MODEM, + .nb = &ssr_modem_nb, + .handle = NULL, + }, + { + .name = "SSR_ADSP", + .domain_id = SSR_DOMAIN_ADSP, + .nb = &ssr_adsp_nb, + .handle = NULL, + }, +}; + +/** + * ssr_register checks that domain id should be in range and register + * SSR framework for value at domain id. + */ +static int __init ssr_register(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(service_data); i++) { + if ((service_data[i].domain_id < 0) || + (service_data[i].domain_id >= SSR_DOMAIN_MAX)) { + pr_err("Invalid service ID = %d\n", + service_data[i].domain_id); + } else { + service_data[i].handle = + subsys_notif_register_notifier( + ssr_domains[service_data[i].domain_id], + service_data[i].nb); + if (IS_ERR_OR_NULL(service_data[i].handle)) { + pr_err("subsys register failed for id = %d", + service_data[i].domain_id); + service_data[i].handle = NULL; + } + } + } + return 0; +} + +module_init(init_bg_com_dev); +late_initcall(ssr_register); +module_exit(exit_bg_com_dev); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/bgcom_interface.h b/drivers/soc/qcom/bgcom_interface.h new file mode 100644 index 000000000000..7568adca6ce4 --- /dev/null +++ b/drivers/soc/qcom/bgcom_interface.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2017-2019,2020 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 BGCOM_INTERFACE_H +#define BGCOM_INTERFACE_H + +/* + * bg_soft_reset() - soft reset Blackghost + * Return 0 on success or -Ve on error + */ +int bg_soft_reset(void); + +/* + * is_twm_exit() + * Return true if device is booting up on TWM exit. + * value is auto cleared once read. + */ +bool is_twm_exit(void); + +/* + * is_bg_running() + * Return true if bg is running. + * value is auto cleared once read. + */ +bool is_bg_running(void); + +#endif /* BGCOM_INTERFACE_H */ diff --git a/drivers/soc/qcom/bgcom_spi.c b/drivers/soc/qcom/bgcom_spi.c new file mode 100644 index 000000000000..e7993251a4d8 --- /dev/null +++ b/drivers/soc/qcom/bgcom_spi.c @@ -0,0 +1,1131 @@ +/* Copyright (c) 2017-2020, 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. + * + */ + +#define pr_fmt(msg) "bgcom: %s: " msg, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bgcom.h" +#include "bgrsb.h" +#include "bgcom_interface.h" + +#define BG_SPI_WORD_SIZE (0x04) +#define BG_SPI_READ_LEN (0x04) +#define BG_SPI_WRITE_CMND_LEN (0x01) +#define BG_SPI_FIFO_READ_CMD (0x41) +#define BG_SPI_FIFO_WRITE_CMD (0x40) +#define BG_SPI_AHB_READ_CMD (0x43) +#define BG_SPI_AHB_WRITE_CMD (0x42) +#define BG_SPI_AHB_CMD_LEN (0x05) +#define BG_SPI_AHB_READ_CMD_LEN (0x08) +#define BG_STATUS_REG (0x05) +#define BG_CMND_REG (0x14) + +#define BG_SPI_MAX_WORDS (0x3FFFFFFD) +#define BG_SPI_MAX_REGS (0x0A) +#define HED_EVENT_ID_LEN (0x02) +#define HED_EVENT_SIZE_LEN (0x02) +#define HED_EVENT_DATA_STRT_LEN (0x05) +#define CMA_BFFR_POOL_SIZE (128*1024) + +#define MAX_RETRY 100 + +enum bgcom_state { + /*BGCOM Staus ready*/ + BGCOM_PROB_SUCCESS = 0, + BGCOM_PROB_WAIT = 1, + BGCOM_STATE_SUSPEND = 2, + BGCOM_STATE_ACTIVE = 3 +}; + +enum bgcom_req_type { + /*BGCOM local requests*/ + BGCOM_READ_REG = 0, + BGCOM_READ_FIFO = 1, + BGCOM_READ_AHB = 2, + BGCOM_WRITE_REG = 3, +}; + +struct bg_spi_priv { + struct spi_device *spi; + /* Transaction related */ + struct mutex xfer_mutex; + void *lhandle; + /* Message for single transfer */ + struct spi_message msg1; + struct spi_transfer xfer1; + int irq_lock; + + enum bgcom_state bg_state; +}; + +struct cb_data { + void *priv; + void *handle; + void (*bgcom_notification_cb)(void *handle, void *priv, + enum bgcom_event_type event, + union bgcom_event_data_type *event_data); + struct list_head list; +}; + +struct bg_context { + struct bg_spi_priv *bg_spi; + enum bgcom_state state; + struct cb_data *cb; +}; + +struct event_list { + struct event *evnt; + struct list_head list; +}; +static void *bg_com_drv; +static uint32_t g_slav_status_reg; + +/* BGCOM client callbacks set-up */ +static void send_input_events(struct work_struct *work); +static struct list_head cb_head = LIST_HEAD_INIT(cb_head); +static struct list_head pr_lst_hd = LIST_HEAD_INIT(pr_lst_hd); +static DEFINE_SPINLOCK(lst_setup_lock); +static enum bgcom_spi_state spi_state; + + +static struct workqueue_struct *wq; +static DECLARE_WORK(input_work, send_input_events); + +static struct mutex bg_resume_mutex; + +static atomic_t bg_is_spi_active; +static int bg_irq; + +static uint8_t *fxd_mem_buffer; +static struct mutex cma_buffer_lock; + +static struct spi_device *get_spi_device(void) +{ + struct bg_spi_priv *bg_spi = container_of(bg_com_drv, + struct bg_spi_priv, lhandle); + struct spi_device *spi = bg_spi->spi; + return spi; +} + +static void augmnt_fifo(uint8_t *data, int pos) +{ + data[pos] = '\0'; +} + +static void send_input_events(struct work_struct *work) +{ + struct list_head *temp; + struct list_head *pos; + struct event_list *node; + struct event *evnt; + + if (list_empty(&pr_lst_hd)) + return; + + list_for_each_safe(pos, temp, &pr_lst_hd) { + node = list_entry(pos, struct event_list, list); + evnt = node->evnt; +// bgrsb_send_input(evnt); + kfree(evnt); + spin_lock(&lst_setup_lock); + list_del(&node->list); + spin_unlock(&lst_setup_lock); + kfree(node); + } +} + +int bgcom_set_spi_state(enum bgcom_spi_state state) +{ + struct bg_spi_priv *bg_spi = container_of(bg_com_drv, + struct bg_spi_priv, lhandle); + if (state < 0 || state > 1) + return -EINVAL; + + if (state == spi_state) + return 0; + + mutex_lock(&bg_spi->xfer_mutex); + spi_state = state; + mutex_unlock(&bg_spi->xfer_mutex); + return 0; +} +EXPORT_SYMBOL(bgcom_set_spi_state); + +static inline +void add_to_irq_list(struct cb_data *data) +{ + list_add_tail(&data->list, &cb_head); +} + +static bool is_bgcom_ready(void) +{ + return (bg_com_drv != NULL ? true : false); +} + +static void bg_spi_reinit_xfer(struct spi_transfer *xfer) +{ + xfer->tx_buf = NULL; + xfer->rx_buf = NULL; + xfer->delay_usecs = 0; + xfer->len = 0; +} + +static int read_bg_locl(enum bgcom_req_type req_type, + uint32_t no_of_words, void *buf) +{ + + struct bg_context clnt_handle; + struct bg_spi_priv *spi = + container_of(bg_com_drv, struct bg_spi_priv, lhandle); + int ret = 0; + + if (!buf) + return -EINVAL; + + clnt_handle.bg_spi = spi; + + switch (req_type) { + case BGCOM_READ_REG: + ret = bgcom_reg_read(&clnt_handle, + BG_STATUS_REG, no_of_words, buf); + break; + case BGCOM_READ_FIFO: + ret = bgcom_fifo_read(&clnt_handle, no_of_words, buf); + break; + case BGCOM_WRITE_REG: + ret = bgcom_reg_write(&clnt_handle, BG_CMND_REG, + no_of_words, buf); + break; + case BGCOM_READ_AHB: + break; + } + return ret; +} + +static int bgcom_transfer(void *handle, uint8_t *tx_buf, + uint8_t *rx_buf, uint32_t txn_len) +{ + struct spi_transfer *tx_xfer; + struct bg_spi_priv *bg_spi; + struct bg_context *cntx; + struct spi_device *spi; + int ret; + + if (!handle || !tx_buf) + return -EINVAL; + + cntx = (struct bg_context *)handle; + + if (cntx->state == BGCOM_PROB_WAIT) { + if (!is_bgcom_ready()) + return -ENODEV; + cntx->bg_spi = container_of(bg_com_drv, + struct bg_spi_priv, lhandle); + cntx->state = BGCOM_PROB_SUCCESS; + } + bg_spi = cntx->bg_spi; + + if (!bg_spi) + return -ENODEV; + + tx_xfer = &bg_spi->xfer1; + spi = bg_spi->spi; + + if (!atomic_read(&bg_is_spi_active)) + return -ECANCELED; + + mutex_lock(&bg_spi->xfer_mutex); + bg_spi_reinit_xfer(tx_xfer); + tx_xfer->tx_buf = tx_buf; + if (rx_buf) + tx_xfer->rx_buf = rx_buf; + + tx_xfer->len = txn_len; + ret = spi_sync(spi, &bg_spi->msg1); + mutex_unlock(&bg_spi->xfer_mutex); + + if (ret) + pr_err("SPI transaction failed: %d\n", ret); + return ret; +} + +/* BG-COM Interrupt handling */ +static inline +void send_event(enum bgcom_event_type event, + void *data) +{ + struct list_head *pos; + struct cb_data *cb; + + /* send interrupt notification for each + * registered call-back + */ + list_for_each(pos, &cb_head) { + cb = list_entry(pos, struct cb_data, list); + cb->bgcom_notification_cb(cb->handle, + cb->priv, event, data); + } +} + +void bgcom_bgdown_handler(void) +{ + send_event(BGCOM_EVENT_RESET_OCCURRED, NULL); + g_slav_status_reg = 0; +} +EXPORT_SYMBOL(bgcom_bgdown_handler); + +static void parse_fifo(uint8_t *data, union bgcom_event_data_type *event_data) +{ + uint16_t p_len; + uint8_t sub_id; + uint32_t evnt_tm; + uint16_t event_id; + void *evnt_data; + struct event *evnt; + struct event_list *data_list; + + while (*data != '\0') { + + event_id = *((uint16_t *) data); + data = data + HED_EVENT_ID_LEN; + p_len = *((uint16_t *) data); + data = data + HED_EVENT_SIZE_LEN; + + if (event_id == 0xFFFE) { + + sub_id = *data; + evnt_tm = *((uint32_t *)(data+1)); + + evnt = kmalloc(sizeof(*evnt), GFP_KERNEL); + evnt->sub_id = sub_id; + evnt->evnt_tm = evnt_tm; + evnt->evnt_data = + *(int16_t *)(data + HED_EVENT_DATA_STRT_LEN); + + data_list = kmalloc(sizeof(*data_list), GFP_KERNEL); + data_list->evnt = evnt; + spin_lock(&lst_setup_lock); + list_add_tail(&data_list->list, &pr_lst_hd); + spin_unlock(&lst_setup_lock); + } else if (event_id == 0x0001) { + evnt_data = kmalloc(p_len, GFP_KERNEL); + if (evnt_data != NULL) { + memcpy(evnt_data, data, p_len); + event_data->fifo_data.to_master_fifo_used = + p_len/BG_SPI_WORD_SIZE; + event_data->fifo_data.data = evnt_data; + send_event(BGCOM_EVENT_TO_MASTER_FIFO_USED, + event_data); + } + } + data = data + p_len; + } + if (!list_empty(&pr_lst_hd)) + queue_work(wq, &input_work); +} + +static void send_back_notification(uint32_t slav_status_reg, + uint32_t slav_status_auto_clear_reg, + uint32_t fifo_fill_reg, uint32_t fifo_size_reg) +{ + uint16_t master_fifo_used; + uint16_t slave_fifo_free; + uint32_t *ptr; + int ret; + union bgcom_event_data_type event_data = { .fifo_data = {0} }; + + master_fifo_used = (uint16_t)fifo_fill_reg; + slave_fifo_free = (uint16_t)(fifo_fill_reg >> 16); + + if (slav_status_auto_clear_reg & BIT(31)) + send_event(BGCOM_EVENT_RESET_OCCURRED, NULL); + + if (slav_status_auto_clear_reg & BIT(30)) + send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_OVERRUN, NULL); + + if (slav_status_auto_clear_reg & BIT(29)) + send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_BUS_ERR, NULL); + + if (slav_status_auto_clear_reg & BIT(28)) + send_event(BGCOM_EVENT_ERROR_WRITE_FIFO_ACCESS, NULL); + + if (slav_status_auto_clear_reg & BIT(27)) + send_event(BGCOM_EVENT_ERROR_READ_FIFO_UNDERRUN, NULL); + + if (slav_status_auto_clear_reg & BIT(26)) + send_event(BGCOM_EVENT_ERROR_READ_FIFO_BUS_ERR, NULL); + + if (slav_status_auto_clear_reg & BIT(25)) + send_event(BGCOM_EVENT_ERROR_READ_FIFO_ACCESS, NULL); + + if (slav_status_auto_clear_reg & BIT(24)) + send_event(BGCOM_EVENT_ERROR_TRUNCATED_READ, NULL); + + if (slav_status_auto_clear_reg & BIT(23)) + send_event(BGCOM_EVENT_ERROR_TRUNCATED_WRITE, NULL); + + if (slav_status_auto_clear_reg & BIT(22)) + send_event(BGCOM_EVENT_ERROR_AHB_ILLEGAL_ADDRESS, NULL); + + if (slav_status_auto_clear_reg & BIT(21)) + send_event(BGCOM_EVENT_ERROR_AHB_BUS_ERR, NULL); + + /* check if BG status is changed */ + if (g_slav_status_reg ^ slav_status_reg) { + if (slav_status_reg & BIT(30)) { + event_data.application_running = true; + send_event(BGCOM_EVENT_APPLICATION_RUNNING, + &event_data); + } + + if (slav_status_reg & BIT(29)) { + event_data.to_slave_fifo_ready = true; + send_event(BGCOM_EVENT_TO_SLAVE_FIFO_READY, + &event_data); + } + + if (slav_status_reg & BIT(28)) { + event_data.to_master_fifo_ready = true; + send_event(BGCOM_EVENT_TO_MASTER_FIFO_READY, + &event_data); + } + + if (slav_status_reg & BIT(27)) { + event_data.ahb_ready = true; + send_event(BGCOM_EVENT_AHB_READY, + &event_data); + } + } + + if (master_fifo_used > 0) { + ptr = kzalloc(master_fifo_used*BG_SPI_WORD_SIZE + 1, + GFP_KERNEL | GFP_ATOMIC); + if (ptr != NULL) { + ret = read_bg_locl(BGCOM_READ_FIFO, + master_fifo_used, ptr); + if (!ret) { + augmnt_fifo((uint8_t *)ptr, + master_fifo_used*BG_SPI_WORD_SIZE); + parse_fifo((uint8_t *)ptr, &event_data); + } + kfree(ptr); + } + } + + event_data.to_slave_fifo_free = slave_fifo_free; + send_event(BGCOM_EVENT_TO_SLAVE_FIFO_FREE, &event_data); +} + +static void bg_irq_tasklet_hndlr_l(void) +{ + uint32_t slave_status_reg; + uint32_t glink_isr_reg; + uint32_t slav_status_auto_clear_reg; + uint32_t fifo_fill_reg; + uint32_t fifo_size_reg; + int ret = 0; + uint32_t irq_buf[5] = {0}; + + ret = read_bg_locl(BGCOM_READ_REG, 5, &irq_buf[0]); + if (ret) + return; + + /* save current state */ + slave_status_reg = irq_buf[0]; + glink_isr_reg = irq_buf[1]; + slav_status_auto_clear_reg = irq_buf[2]; + fifo_fill_reg = irq_buf[3]; + fifo_size_reg = irq_buf[4]; + + send_back_notification(slave_status_reg, + slav_status_auto_clear_reg, fifo_fill_reg, fifo_size_reg); + + g_slav_status_reg = slave_status_reg; +} + +int bgcom_ahb_read(void *handle, uint32_t ahb_start_addr, + uint32_t num_words, void *read_buf) +{ + uint32_t txn_len; + uint8_t *tx_buf; + uint8_t *rx_buf; + uint32_t size; + int ret; + uint8_t cmnd = 0; + uint32_t ahb_addr = 0; + + if (!handle || !read_buf || num_words == 0 + || num_words > BG_SPI_MAX_WORDS) { + pr_err("Invalid param\n"); + return -EINVAL; + } + if (!is_bgcom_ready()) + return -ENODEV; + + if (spi_state == BGCOM_SPI_BUSY) { + pr_err("Device busy\n"); + return -EBUSY; + } + + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + + size = num_words*BG_SPI_WORD_SIZE; + txn_len = BG_SPI_AHB_READ_CMD_LEN + size; + + tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + if (!tx_buf) + return -ENOMEM; + + rx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + if (!rx_buf) { + kfree(tx_buf); + return -ENOMEM; + } + + cmnd |= BG_SPI_AHB_READ_CMD; + ahb_addr |= ahb_start_addr; + + memcpy(tx_buf, &cmnd, sizeof(cmnd)); + memcpy(tx_buf+sizeof(cmnd), &ahb_addr, sizeof(ahb_addr)); + + ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len); + + if (!ret) + memcpy(read_buf, rx_buf+BG_SPI_AHB_READ_CMD_LEN, size); + + kfree(tx_buf); + kfree(rx_buf); + return ret; +} +EXPORT_SYMBOL(bgcom_ahb_read); + +int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, + uint32_t num_words, void *write_buf) +{ + dma_addr_t dma_hndl; + uint32_t txn_len; + uint8_t *tx_buf; + uint32_t size; + int ret; + bool is_cma_used = false; + uint8_t cmnd = 0; + uint32_t ahb_addr = 0; + struct spi_device *spi = get_spi_device(); + + if (!handle || !write_buf || num_words == 0 + || num_words > BG_SPI_MAX_WORDS) { + pr_err("Invalid param\n"); + return -EINVAL; + } + + if (!is_bgcom_ready()) + return -ENODEV; + + if (spi_state == BGCOM_SPI_BUSY) { + pr_err("Device busy\n"); + return -EBUSY; + } + + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + + mutex_lock(&cma_buffer_lock); + size = num_words*BG_SPI_WORD_SIZE; + txn_len = BG_SPI_AHB_CMD_LEN + size; + if (fxd_mem_buffer != NULL && txn_len <= CMA_BFFR_POOL_SIZE) { + memset(fxd_mem_buffer, 0, txn_len); + tx_buf = fxd_mem_buffer; + is_cma_used = true; + } else { + pr_info("DMA memory used for size[%d]\n", txn_len); + tx_buf = dma_zalloc_coherent(&spi->dev, txn_len, + &dma_hndl, GFP_KERNEL); + } + + if (!tx_buf) { + mutex_unlock(&cma_buffer_lock); + return -ENOMEM; + } + + cmnd |= BG_SPI_AHB_WRITE_CMD; + ahb_addr |= ahb_start_addr; + + memcpy(tx_buf, &cmnd, sizeof(cmnd)); + memcpy(tx_buf+sizeof(cmnd), &ahb_addr, sizeof(ahb_addr)); + memcpy(tx_buf+BG_SPI_AHB_CMD_LEN, write_buf, size); + + ret = bgcom_transfer(handle, tx_buf, NULL, txn_len); + if (!is_cma_used) + dma_free_coherent(&spi->dev, txn_len, tx_buf, dma_hndl); + mutex_unlock(&cma_buffer_lock); + return ret; +} +EXPORT_SYMBOL(bgcom_ahb_write); + +int bgcom_fifo_write(void *handle, uint32_t num_words, + void *write_buf) +{ + uint32_t txn_len; + uint8_t *tx_buf; + uint32_t size; + int ret; + uint8_t cmnd = 0; + + if (!handle || !write_buf || num_words == 0 + || num_words > BG_SPI_MAX_WORDS) { + pr_err("Invalid param\n"); + return -EINVAL; + } + + if (!is_bgcom_ready()) + return -ENODEV; + + if (spi_state == BGCOM_SPI_BUSY) { + pr_err("Device busy\n"); + return -EBUSY; + } + + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + + size = num_words*BG_SPI_WORD_SIZE; + txn_len = BG_SPI_WRITE_CMND_LEN + size; + + tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + + if (!tx_buf) + return -ENOMEM; + + cmnd |= BG_SPI_FIFO_WRITE_CMD; + memcpy(tx_buf, &cmnd, sizeof(cmnd)); + memcpy(tx_buf+sizeof(cmnd), write_buf, size); + + ret = bgcom_transfer(handle, tx_buf, NULL, txn_len); + kfree(tx_buf); + return ret; +} +EXPORT_SYMBOL(bgcom_fifo_write); + +int bgcom_fifo_read(void *handle, uint32_t num_words, + void *read_buf) +{ + uint32_t txn_len; + uint8_t *tx_buf; + uint8_t *rx_buf; + uint32_t size; + uint8_t cmnd = 0; + int ret = 0; + + if (!handle || !read_buf || num_words == 0 + || num_words > BG_SPI_MAX_WORDS) { + pr_err("Invalid param\n"); + return -EINVAL; + } + + if (!is_bgcom_ready()) + return -ENODEV; + + if (spi_state == BGCOM_SPI_BUSY) { + pr_err("Device busy\n"); + return -EBUSY; + } + + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + + size = num_words*BG_SPI_WORD_SIZE; + txn_len = BG_SPI_READ_LEN + size; + tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + + if (!tx_buf) + return -ENOMEM; + + rx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + + if (!rx_buf) { + kfree(tx_buf); + return -ENOMEM; + } + + cmnd |= BG_SPI_FIFO_READ_CMD; + memcpy(tx_buf, &cmnd, sizeof(cmnd)); + + ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len); + + if (!ret) + memcpy(read_buf, rx_buf+BG_SPI_READ_LEN, size); + kfree(tx_buf); + kfree(rx_buf); + return ret; +} +EXPORT_SYMBOL(bgcom_fifo_read); + +int bgcom_reg_write(void *handle, uint8_t reg_start_addr, + uint8_t num_regs, void *write_buf) +{ + uint32_t txn_len; + uint8_t *tx_buf; + uint32_t size; + uint8_t cmnd = 0; + int ret = 0; + + if (!handle || !write_buf || num_regs == 0 + || num_regs > BG_SPI_MAX_REGS) { + pr_err("Invalid param\n"); + return -EINVAL; + } + + if (!is_bgcom_ready()) + return -ENODEV; + + if (spi_state == BGCOM_SPI_BUSY) { + pr_err("Device busy\n"); + return -EBUSY; + } + + if (bgcom_resume(handle)) { + pr_err("Failed to resume\n"); + return -EBUSY; + } + + size = num_regs*BG_SPI_WORD_SIZE; + txn_len = BG_SPI_WRITE_CMND_LEN + size; + + tx_buf = kzalloc(txn_len, GFP_KERNEL); + + if (!tx_buf) + return -ENOMEM; + + cmnd |= reg_start_addr; + memcpy(tx_buf, &cmnd, sizeof(cmnd)); + memcpy(tx_buf+sizeof(cmnd), write_buf, size); + + ret = bgcom_transfer(handle, tx_buf, NULL, txn_len); + kfree(tx_buf); + return ret; +} +EXPORT_SYMBOL(bgcom_reg_write); + +int bgcom_reg_read(void *handle, uint8_t reg_start_addr, + uint32_t num_regs, void *read_buf) +{ + uint32_t txn_len; + uint8_t *tx_buf; + uint8_t *rx_buf; + uint32_t size; + int ret; + uint8_t cmnd = 0; + + if (!handle || !read_buf || num_regs == 0 + || num_regs > BG_SPI_MAX_REGS) { + pr_err("Invalid param\n"); + return -EINVAL; + } + + if (!is_bgcom_ready()) + return -ENODEV; + + if (spi_state == BGCOM_SPI_BUSY) { + pr_err("Device busy\n"); + return -EBUSY; + } + + size = num_regs*BG_SPI_WORD_SIZE; + txn_len = BG_SPI_READ_LEN + size; + + tx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + + if (!tx_buf) + return -ENOMEM; + + rx_buf = kzalloc(txn_len, GFP_KERNEL | GFP_ATOMIC); + + if (!rx_buf) { + kfree(tx_buf); + return -ENOMEM; + } + + cmnd |= reg_start_addr; + memcpy(tx_buf, &cmnd, sizeof(cmnd)); + + ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len); + + if (!ret) + memcpy(read_buf, rx_buf+BG_SPI_READ_LEN, size); + kfree(tx_buf); + kfree(rx_buf); + return ret; +} +EXPORT_SYMBOL(bgcom_reg_read); + +static int is_bg_resume(void *handle) +{ + uint32_t txn_len; + int ret; + uint8_t tx_buf[8] = {0}; + uint8_t rx_buf[8] = {0}; + uint32_t cmnd_reg = 0; + + if (spi_state == BGCOM_SPI_BUSY) { + printk_ratelimited("SPI is held by TZ\n"); + goto ret_err; + } + + txn_len = 0x08; + tx_buf[0] = 0x05; + ret = bgcom_transfer(handle, tx_buf, rx_buf, txn_len); + if (!ret) + memcpy(&cmnd_reg, rx_buf+BG_SPI_READ_LEN, 0x04); + +ret_err: + return cmnd_reg & BIT(31); +} + +int bgcom_resume(void *handle) +{ + struct bg_spi_priv *bg_spi; + struct bg_context *cntx; + int retry = 0; + + if (handle == NULL) + return -EINVAL; + + if (!atomic_read(&bg_is_spi_active)) + return -ECANCELED; + + cntx = (struct bg_context *)handle; + + /* if client is outside bgcom scope and + * handle is provided before BGCOM probed + */ + if (cntx->state == BGCOM_PROB_WAIT) { + pr_info("handle is provided before BGCOM probed\n"); + if (!is_bgcom_ready()) + return -EAGAIN; + cntx->bg_spi = container_of(bg_com_drv, + struct bg_spi_priv, lhandle); + cntx->state = BGCOM_PROB_SUCCESS; + } + + bg_spi = cntx->bg_spi; + + mutex_lock(&bg_resume_mutex); + if (bg_spi->bg_state == BGCOM_STATE_ACTIVE) + goto unlock; + enable_irq(bg_irq); + do { + if (is_bg_resume(handle)) { + bg_spi->bg_state = BGCOM_STATE_ACTIVE; + break; + } + udelay(1000); + ++retry; + } while (retry < MAX_RETRY); + +unlock: + mutex_unlock(&bg_resume_mutex); + if (retry == MAX_RETRY) { + /* BG failed to resume. Trigger BG soft reset. */ + pr_err("BG failed to resume\n"); + pr_err("%s: gpio#95 value is: %d\n", + __func__, gpio_get_value(95)); + pr_err("%s: gpio#97 value is: %d\n", + __func__, gpio_get_value(97)); + BUG(); + bg_soft_reset(); + return -ETIMEDOUT; + } + return 0; +} +EXPORT_SYMBOL(bgcom_resume); + +int bgcom_suspend(void *handle) +{ + if (!handle) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL(bgcom_suspend); + +void *bgcom_open(struct bgcom_open_config_type *open_config) +{ + struct bg_spi_priv *spi; + struct cb_data *irq_notification; + struct bg_context *clnt_handle = + kzalloc(sizeof(*clnt_handle), GFP_KERNEL); + + if (!clnt_handle) + return NULL; + + /* Client handle Set-up */ + if (!is_bgcom_ready()) { + clnt_handle->bg_spi = NULL; + clnt_handle->state = BGCOM_PROB_WAIT; + } else { + spi = container_of(bg_com_drv, struct bg_spi_priv, lhandle); + clnt_handle->bg_spi = spi; + clnt_handle->state = BGCOM_PROB_SUCCESS; + } + clnt_handle->cb = NULL; + /* Interrupt callback Set-up */ + if (open_config && open_config->bgcom_notification_cb) { + irq_notification = kzalloc(sizeof(*irq_notification), + GFP_KERNEL); + if (!irq_notification) + goto error_ret; + + /* set irq node */ + irq_notification->handle = clnt_handle; + irq_notification->priv = open_config->priv; + irq_notification->bgcom_notification_cb = + open_config->bgcom_notification_cb; + add_to_irq_list(irq_notification); + clnt_handle->cb = irq_notification; + } + return clnt_handle; + +error_ret: + kfree(clnt_handle); + return NULL; +} +EXPORT_SYMBOL(bgcom_open); + +int bgcom_close(void **handle) +{ + struct bg_context *lhandle; + struct cb_data *cb = NULL; + + if (*handle == NULL) + return -EINVAL; + lhandle = *handle; + cb = lhandle->cb; + if (cb) + list_del(&cb->list); + + kfree(*handle); + *handle = NULL; + return 0; +} +EXPORT_SYMBOL(bgcom_close); + +static irqreturn_t bg_irq_tasklet_hndlr(int irq, void *device) +{ + struct bg_spi_priv *bg_spi = device; + + /* check if call-back exists */ + if (!atomic_read(&bg_is_spi_active)) { + pr_debug("Interrupt received in suspend state\n"); + return IRQ_HANDLED; + } else if (list_empty(&cb_head)) { + pr_debug("No callback registered\n"); + return IRQ_HANDLED; + } else if (spi_state == BGCOM_SPI_BUSY) { + /* delay for SPI to be freed */ + msleep(50); + return IRQ_HANDLED; + } else if (!bg_spi->irq_lock) { + bg_spi->irq_lock = 1; + bg_irq_tasklet_hndlr_l(); + bg_spi->irq_lock = 0; + } + return IRQ_HANDLED; +} + +static void bg_spi_init(struct bg_spi_priv *bg_spi) +{ + if (!bg_spi) { + pr_err("device not found\n"); + return; + } + + /* BGCOM SPI set-up */ + mutex_init(&bg_spi->xfer_mutex); + spi_message_init(&bg_spi->msg1); + spi_message_add_tail(&bg_spi->xfer1, &bg_spi->msg1); + + /* BGCOM IRQ set-up */ + bg_spi->irq_lock = 0; + + spi_state = BGCOM_SPI_FREE; + + wq = create_singlethread_workqueue("input_wq"); + + bg_spi->bg_state = BGCOM_STATE_ACTIVE; + + bg_com_drv = &bg_spi->lhandle; + + mutex_init(&bg_resume_mutex); + + fxd_mem_buffer = kmalloc(CMA_BFFR_POOL_SIZE, GFP_KERNEL | GFP_ATOMIC); + + mutex_init(&cma_buffer_lock); +} + +static int bg_spi_probe(struct spi_device *spi) +{ + struct bg_spi_priv *bg_spi; + struct device_node *node; + int irq_gpio = 0; + int ret; + + bg_spi = devm_kzalloc(&spi->dev, sizeof(*bg_spi), + GFP_KERNEL | GFP_ATOMIC); + + pr_info("%s started\n", __func__); + + if (!bg_spi) + return -ENOMEM; + bg_spi->spi = spi; + spi_set_drvdata(spi, bg_spi); + bg_spi_init(bg_spi); + + /* BGCOM Interrupt probe */ + node = spi->dev.of_node; + irq_gpio = of_get_named_gpio(node, "qcom,irq-gpio", 0); + if (!gpio_is_valid(irq_gpio)) { + pr_err("gpio %d found is not valid\n", irq_gpio); + goto err_ret; + } + + ret = gpio_request(irq_gpio, "bgcom_gpio"); + if (ret) { + pr_err("gpio %d request failed\n", irq_gpio); + goto err_ret; + } + + ret = gpio_direction_input(irq_gpio); + if (ret) { + pr_err("gpio_direction_input not set: %d\n", ret); + goto err_ret; + } + + bg_irq = gpio_to_irq(irq_gpio); + ret = request_threaded_irq(bg_irq, NULL, bg_irq_tasklet_hndlr, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "qcom-bg_spi", bg_spi); + + if (ret) + goto err_ret; + + atomic_set(&bg_is_spi_active, 1); + dma_set_coherent_mask(&spi->dev, DMA_BIT_MASK(64)); + pr_info("%s success\n", __func__); + pr_info("Bgcom Probed successfully\n"); + return ret; + +err_ret: + bg_com_drv = NULL; + mutex_destroy(&bg_spi->xfer_mutex); + spi_set_drvdata(spi, NULL); + return -ENODEV; +} + +static int bg_spi_remove(struct spi_device *spi) +{ + struct bg_spi_priv *bg_spi = spi_get_drvdata(spi); + + bg_com_drv = NULL; + mutex_destroy(&bg_spi->xfer_mutex); + devm_kfree(&spi->dev, bg_spi); + spi_set_drvdata(spi, NULL); + if (fxd_mem_buffer != NULL) + kfree(fxd_mem_buffer); + mutex_destroy(&cma_buffer_lock); + return 0; +} + +static void bg_spi_shutdown(struct spi_device *spi) +{ + bg_spi_remove(spi); +} + +static int bgcom_pm_suspend(struct device *dev) +{ + uint32_t cmnd_reg = 0; + struct spi_device *s_dev = to_spi_device(dev); + struct bg_spi_priv *bg_spi = spi_get_drvdata(s_dev); + int ret = 0; + + if (bg_spi->bg_state == BGCOM_STATE_SUSPEND) + return 0; + + cmnd_reg |= BIT(31); + ret = read_bg_locl(BGCOM_WRITE_REG, 1, &cmnd_reg); + if (ret == 0) { + bg_spi->bg_state = BGCOM_STATE_SUSPEND; + atomic_set(&bg_is_spi_active, 0); + disable_irq(bg_irq); + } + pr_info("suspended with : %d\n", ret); + return ret; +} + +static int bgcom_pm_resume(struct device *dev) +{ + struct bg_context clnt_handle; + int ret; + struct bg_spi_priv *spi = + container_of(bg_com_drv, struct bg_spi_priv, lhandle); + + clnt_handle.bg_spi = spi; + atomic_set(&bg_is_spi_active, 1); + ret = bgcom_resume(&clnt_handle); + pr_info("Bgcom resumed with : %d\n", ret); + return ret; +} + +static const struct dev_pm_ops bgcom_pm = { + .suspend = bgcom_pm_suspend, + .resume = bgcom_pm_resume, +}; + +static const struct of_device_id bg_spi_of_match[] = { + { .compatible = "qcom,bg-spi", }, + { } +}; +MODULE_DEVICE_TABLE(of, bg_spi_of_match); + +static struct spi_driver bg_spi_driver = { + .driver = { + .name = "bg-spi", + .of_match_table = bg_spi_of_match, + .pm = &bgcom_pm, + }, + .probe = bg_spi_probe, + .remove = bg_spi_remove, + .shutdown = bg_spi_shutdown, +}; + +module_spi_driver(bg_spi_driver); +MODULE_DESCRIPTION("bg SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/bgrsb.h b/drivers/soc/qcom/bgrsb.h new file mode 100644 index 000000000000..93a58b34bd28 --- /dev/null +++ b/drivers/soc/qcom/bgrsb.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2017-2018,2020 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 BGRSB_H +#define BGRSB_H + +struct event { + uint8_t sub_id; + int16_t evnt_data; + uint32_t evnt_tm; +}; + + +struct bg_glink_chnl { + char *chnl_name; + char *chnl_edge; + char *chnl_trnsprt; +}; + +/** + * bgrsb_send_input() - send the recived input to input framework + * @evnt: pointer to the event structure + */ +int bgrsb_send_input(struct event *evnt); + +#endif /* BGCOM_H */ diff --git a/include/uapi/linux/bgcom_interface.h b/include/uapi/linux/bgcom_interface.h new file mode 100644 index 000000000000..76632a9ef2ee --- /dev/null +++ b/include/uapi/linux/bgcom_interface.h @@ -0,0 +1,84 @@ +#ifndef LINUX_BG_CHAR_H + +#include + +#define LINUX_BG_CHAR_H +#define BGCOM_REG_READ 0 +#define BGCOM_AHB_READ 1 +#define BGCOM_AHB_WRITE 2 +#define BGCOM_SET_SPI_FREE 3 +#define BGCOM_SET_SPI_BUSY 4 +#define BGCOM_REG_WRITE 5 +#define BGCOM_SOFT_RESET 6 +#define BGCOM_MODEM_DOWN2_BG 7 +#define BGCOM_TWM_EXIT 8 +#define BGCOM_BG_APP_RUNNING 9 +#define BGCOM_ADSP_DOWN2_BG 10 +#define BGCOM_BG_WEAR_LOAD 11 +#define BGCOM_BG_WEAR_TWM_LOAD 12 +#define BGCOM_BG_WEAR_UNLOAD 13 +#define EXCHANGE_CODE 'V' + +struct bg_ui_data { + __u64 __user write; + __u64 __user result; + __u32 bg_address; + __u32 cmd; + __u32 num_of_words; +}; + +enum bg_event_type { + BG_BEFORE_POWER_DOWN = 1, + BG_AFTER_POWER_DOWN, + BG_BEFORE_POWER_UP, + BG_AFTER_POWER_UP, + MODEM_BEFORE_POWER_DOWN, + MODEM_AFTER_POWER_UP, + ADSP_BEFORE_POWER_DOWN, + ADSP_AFTER_POWER_UP, + TWM_BG_AFTER_POWER_UP, +}; + +#define REG_READ \ + _IOWR(EXCHANGE_CODE, BGCOM_REG_READ, \ + struct bg_ui_data) +#define AHB_READ \ + _IOWR(EXCHANGE_CODE, BGCOM_AHB_READ, \ + struct bg_ui_data) +#define AHB_WRITE \ + _IOW(EXCHANGE_CODE, BGCOM_AHB_WRITE, \ + struct bg_ui_data) +#define SET_SPI_FREE \ + _IOR(EXCHANGE_CODE, BGCOM_SET_SPI_FREE, \ + struct bg_ui_data) +#define SET_SPI_BUSY \ + _IOR(EXCHANGE_CODE, BGCOM_SET_SPI_BUSY, \ + struct bg_ui_data) +#define REG_WRITE \ + _IOWR(EXCHANGE_CODE, BGCOM_REG_WRITE, \ + struct bg_ui_data) +#define BG_SOFT_RESET \ + _IOWR(EXCHANGE_CODE, BGCOM_SOFT_RESET, \ + struct bg_ui_data) +#define BG_TWM_EXIT \ + _IOWR(EXCHANGE_CODE, BGCOM_TWM_EXIT, \ + struct bg_ui_data) +#define BG_APP_RUNNING \ + _IOWR(EXCHANGE_CODE, BGCOM_BG_APP_RUNNING, \ + struct bg_ui_data) +#define BG_MODEM_DOWN2_BG_DONE \ + _IOWR(EXCHANGE_CODE, BGCOM_MODEM_DOWN2_BG, \ + struct bg_ui_data) +#define BG_WEAR_LOAD \ + _IOWR(EXCHANGE_CODE, BGCOM_BG_WEAR_LOAD, \ + struct bg_ui_data) +#define BG_WEAR_TWM_LOAD \ + _IOWR(EXCHANGE_CODE, BGCOM_BG_WEAR_TWM_LOAD, \ + struct bg_ui_data) +#define BG_WEAR_UNLOAD \ + _IOWR(EXCHANGE_CODE, BGCOM_BG_WEAR_UNLOAD, \ + struct bg_ui_data) +#define BG_ADSP_DOWN2_BG_DONE \ + _IOWR(EXCHANGE_CODE, BGCOM_ADSP_DOWN2_BG, \ + struct bg_ui_data) +#endif -- GitLab From b0ab9807c2237264007cf3f761e388de64fb7892 Mon Sep 17 00:00:00 2001 From: Anant Goel Date: Thu, 18 Jun 2020 17:21:33 -0700 Subject: [PATCH 0902/1055] staging: android: ion: Add support for Carveout allocations in ion_alloc Add support in ion_alloc for allocations of type ION_HEAP_TYPE_CARVEOUT as this is required for certain audio use cases. Change-Id: Ie300607d38173859e51b0f5421891badada594e7 Signed-off-by: Anant Goel --- drivers/staging/android/ion/ion.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 8f92df270d43..bc0679ec4d20 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1130,6 +1130,7 @@ struct dma_buf *ion_alloc(size_t len, unsigned int heap_id_mask, if (!((1 << heap->id) & heap_id_mask)) continue; if (heap->type == ION_HEAP_TYPE_SYSTEM || + heap->type == ION_HEAP_TYPE_CARVEOUT || heap->type == (enum ion_heap_type)ION_HEAP_TYPE_HYP_CMA || heap->type == (enum ion_heap_type)ION_HEAP_TYPE_SYSTEM_SECURE) { -- GitLab From a19eccfc46d556e4c07bcde2c8ecc7a189485abf Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Mon, 22 Jun 2020 10:38:43 -0700 Subject: [PATCH 0903/1055] ARM: dts: msm: Add 1.8v override for SA515M telematics CDP Override pinctrl to support RGMII 1.8V regulator. Change-Id: Iaf1464ac987815cceeb1fb1ffb922d283416748b Acked-by: Ning Cai Signed-off-by: Sunil Paidimarri --- .../boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts b/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts index 81dfac855db4..165a3275f2af 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts +++ b/arch/arm64/boot/dts/qcom/sdxprairie-v2-dsda-cdp.dts @@ -63,3 +63,19 @@ &vbus_detect { status = "okay"; }; + +ðqos_hw { + /delete-property/ vreg_rgmii-supply; + pinctrl-names = "default", + "dev-emac_pin_pps_0", + "dev-emac_pin_pps_1"; + pinctrl-0 = <&vreg_rgmii_off_default>; + pinctrl-1 = <&emac_pin_pps_0>; + pinctrl-2 = <&emac_pin_pps_1>; + qcom,phy-reset-delay-msecs = <10>; +}; + +&vreg_rgmii_io_pads { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; +}; -- GitLab From 5da1a289db6c7a47dc96236f30471d01fa13020a Mon Sep 17 00:00:00 2001 From: Sneh Shah Date: Fri, 19 Jun 2020 15:20:05 +0530 Subject: [PATCH 0904/1055] arm: dts: msm: Add dt entry to enable geometry mapping in EMAC Add dt entry to to enable geometry mapping for fastmap to save memory. Change-Id: I201734811d8161810c82b3b15fcac75d16ae1093 Signed-off-by: Sneh Shah --- arch/arm64/boot/dts/qcom/sdxprairie.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index b2e0fb5853bf..1e7e6b7e23c7 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -1588,6 +1588,7 @@ compatible = "qcom,emac-smmu-embedded"; iommus = <&apps_smmu 0x1c0 0xf>; qcom,iova-mapping = <0x80000000 0x40000000>; + qcom,smmu-geometry; }; }; -- GitLab From e1c04f032416997b6795eab0f7be301e007b2d6a Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Mon, 5 Aug 2019 16:18:03 +0530 Subject: [PATCH 0905/1055] sched: Improve the scheduler This change is for general scheduler improvements. Change-Id: I5e7c2d92ae5cddaa4dc37d68dfb7a184a72b1c12 Signed-off-by: Lingutla Chandrasekhar --- fs/proc/base.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/proc/base.c b/fs/proc/base.c index 693d67501ea7..b37ec658c63a 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3054,6 +3054,9 @@ static ssize_t proc_sched_task_boost_period_write(struct file *file, unsigned int sched_boost_period; int err; + if (!task) + return -ESRCH; + memset(buffer, 0, sizeof(buffer)); if (count > sizeof(buffer) - 1) count = sizeof(buffer) - 1; -- GitLab From c3e4aac9048e299b94e17980468e0ebaf3746993 Mon Sep 17 00:00:00 2001 From: Mohamed Sunfeer Date: Tue, 23 Jun 2020 15:25:06 +0530 Subject: [PATCH 0906/1055] qseecom: use legacy command for bgapp use the legacy command for sending any data to trusted application only if the app name is bgapp. Change-Id: If3460a8b512e8f74e9ff35848237b7e6333334b1 Signed-off-by: Mohamed Sunfeer --- drivers/misc/qseecom.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index f402e161e55f..5d7c03a2d68c 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -5108,8 +5108,10 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, } perf_enabled = true; } - if (!strcmp(data->client.app_name, "securemm")) + if (!strcmp(data->client.app_name, "securemm") || + !strcmp(data->client.app_name, "bgapp")) { data->use_legacy_cmd = true; + } dmac_flush_range(req.cmd_req_buf, req.cmd_req_buf + req.cmd_req_len); -- GitLab From 3818393792dfc4e91472894226fb053cb6342adb Mon Sep 17 00:00:00 2001 From: Jiten Patel Date: Thu, 11 Jun 2020 19:16:41 +0530 Subject: [PATCH 0907/1055] ARM: dts: msm: Add qseecom node for sdm429 Add qseecom driver node to enable the qseecom driver to communicate with trustzone.The qseecom heap and the qseecom_ta heap will be used by qseecom userspace library for allocating memory for loading trusted applications. Change-Id: Ia7179f6dc0f29266e0aae0222baf188c2b3427ea Signed-off-by: Jiten Patel --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 9e709b8e2c27..a86fb3694266 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -140,6 +140,34 @@ }; + qcom_seecom: qseecom@85b00000 { + compatible = "qcom,qseecom"; + reg = <0x85b00000 0x800000>; + reg-names = "secapp-region"; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,commonlib64-loaded-by-uefi; + qcom,support-bus-scaling; + qcom,msm-bus,name = "qseecom-noc"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <55 512 0 0>, + <55 512 0 0>, + <55 512 120000 1200000>, + <55 512 393600 3936000>; + clocks = <&gcc CRYPTO_CLK_SRC>, + <&gcc GCC_CRYPTO_CLK>, + <&gcc GCC_CRYPTO_AHB_CLK>, + <&gcc GCC_CRYPTO_AXI_CLK>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + qcom,ce-opp-freq = <100000000>; + }; + aliases { sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ sdhc2 = &sdhc_2; /* SDC2 for SD card */ -- GitLab From 3c1e4045d36b543688469ea8247bbe98e7ae9e53 Mon Sep 17 00:00:00 2001 From: Avinash Chandra Date: Tue, 16 Jun 2020 17:43:15 +0530 Subject: [PATCH 0908/1055] ARM: dts: msm: Add audio support -include audio dts for qcs410 iot target. -Delete fsa i2c handle property as analog usb type C support not required. CRs-Fixed: 2708966 Change-Id: I034e890c5571f15119d1275317be38f6410e53d4 Signed-off-by: Avinash Chandra Signed-off-by: Sohail Hoque --- arch/arm64/boot/dts/qcom/qcs410-iot.dts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs410-iot.dts b/arch/arm64/boot/dts/qcom/qcs410-iot.dts index bac1561fdc2a..2fe709638dbc 100644 --- a/arch/arm64/boot/dts/qcom/qcs410-iot.dts +++ b/arch/arm64/boot/dts/qcom/qcs410-iot.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, 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 @@ -14,9 +14,14 @@ #include "qcs410.dtsi" #include "qcs410-iot.dtsi" +#include "sm6150-audio-overlay.dtsi" / { model = "Qualcomm Technologies, Inc. QCS410 IOT"; compatible = "qcom,qcs410-iot", "qcom,qcs410", "qcom,iot"; qcom,board-id = <32 0>; }; + +&sm6150_snd { + /delete-property/ fsa4480-i2c-handle; +}; -- GitLab From 24f1e7adaa2b20850f08c126d41b09bf357b7fb5 Mon Sep 17 00:00:00 2001 From: Shadul Shaikh Date: Tue, 7 Apr 2020 14:53:29 +0530 Subject: [PATCH 0909/1055] msm: camera: Update CSIPHY/CSID v3.5 registers Update CSIPHY v3.5 registers to align with CSIPHY HPG and CSID v3.5 reset command register value. Change-Id: Id3878b6a0877fe3acb0c69a5dba06f28765f249d Signed-off-by: Shadul Shaikh --- .../camera_v2/sensor/csid/include/msm_csid_3_5_hwreg.h | 4 ++-- .../sensor/csiphy/include/msm_csiphy_3_5_hwreg.h | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_hwreg.h index d5463443068e..d145c0945eaa 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_hwreg.h +++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/msm_csid_3_5_hwreg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015, 2018, 2020, 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 @@ -49,7 +49,7 @@ static struct csid_reg_parms_t csid_v3_5 = { 0xB8, 0xBC, 11, - 0x7FFF, + 0x7FFFF, 0x4, 17, 0x30050000, diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h index 68f8ea37b080..216bfccd87d0 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_3_5_hwreg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2016, 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 2018-2020, 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 @@ -26,7 +26,7 @@ static struct csiphy_reg_parms_t csiphy_v3_5 = { static struct csiphy_reg_3ph_parms_t csiphy_v3_5_3ph = { /*MIPI CSI PHY registers*/ - {0x814, 0x0}, + {0x814, 0xD5}, {0x818, 0x1}, {0x188, 0x7F}, {0x18C, 0x7F}, @@ -80,15 +80,15 @@ static struct csiphy_reg_3ph_parms_t csiphy_v3_5_3ph = { {0x4, 0x8}, {0x8, 0x0}, {0xC, 0xA5}, - {0x10, 0x52}, + {0x10, 0x50}, {0x2C, 0x1}, {0x30, 0x2}, - {0x34, 0x3}, + {0x34, 0x1}, {0x38, 0x1}, {0x3C, 0xB8}, {0x1C, 0xA}, {0x14, 0x0}, - {0x0, 0x0}, + {0x0, 0xD7}, {0x700, 0xC0}, }; #endif -- GitLab From 5c777bbf6918909976b72258d297ae0bf00ead2a Mon Sep 17 00:00:00 2001 From: Deepak Dimri Date: Tue, 23 Jun 2020 18:07:02 +0530 Subject: [PATCH 0910/1055] defconfig: sa2150p-nand: Add 3D Graphics driver Add 3D Graphics driver for sa2150p-nand. Change-Id: I897912da5ae2a79bc2c9f0777f863aa4b9834b7b Signed-off-by: Deepak Dimri --- arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig | 1 + arch/arm64/configs/vendor/sa2150p-nand_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig index 71b80351e077..796f4f6df27e 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig @@ -435,6 +435,7 @@ CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y CONFIG_PWM=y CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y diff --git a/arch/arm64/configs/vendor/sa2150p-nand_defconfig b/arch/arm64/configs/vendor/sa2150p-nand_defconfig index 0993256a8b2f..16c381f7460d 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand_defconfig @@ -452,6 +452,7 @@ CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y CONFIG_PWM=y CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y -- GitLab From 2d040f8915f988ee0e625997b7e4654728e507c0 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Wed, 10 Jun 2020 14:22:54 +0530 Subject: [PATCH 0911/1055] wcnss: Export wcnss smd tx method Export wcnss smd tx wrapper for wlan driver uses. Change-Id: I5fcdf2eeb86e7735c12743483f9bef39022c15a6 Signed-off-by: Govind Singh --- drivers/soc/qcom/wcnss/wcnss_wlan.c | 29 +++++++++++++++++------------ include/linux/wcnss_wlan.h | 1 + 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/soc/qcom/wcnss/wcnss_wlan.c b/drivers/soc/qcom/wcnss/wcnss_wlan.c index 5ae9596daab4..e97b72bd5e7c 100644 --- a/drivers/soc/qcom/wcnss/wcnss_wlan.c +++ b/drivers/soc/qcom/wcnss/wcnss_wlan.c @@ -1963,15 +1963,16 @@ int wcnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 buffer_size, } EXPORT_SYMBOL(wcnss_get_wlan_unsafe_channel); -static int wcnss_smd_tx(void *data, int len) +int wcnss_smd_tx(struct rpmsg_endpoint *channel, void *data, int len) { int ret = 0; - ret = rpmsg_send(penv->channel, data, len); + ret = rpmsg_send(channel, data, len); if (ret < 0) return ret; return 0; } +EXPORT_SYMBOL(wcnss_smd_tx); static int wcnss_get_battery_volt(u32 *result_uv) { @@ -2088,7 +2089,7 @@ static void wcnss_send_vbatt_indication(struct work_struct *work) wcnss_log(DBG, "send curr_volt: %d to FW\n", vbatt_msg.vbatt.curr_volt); - ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len); + ret = wcnss_smd_tx(penv->channel, &vbatt_msg, vbatt_msg.hdr.msg_len); if (ret < 0) wcnss_log(ERR, "smd tx failed\n"); } @@ -2120,7 +2121,7 @@ static void wcnss_update_vbatt(struct work_struct *work) return; } mutex_unlock(&penv->vbat_monitor_mutex); - ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len); + ret = wcnss_smd_tx(penv->channel, &vbatt_msg, vbatt_msg.hdr.msg_len); if (ret < 0) wcnss_log(ERR, "smd tx failed\n"); } @@ -2140,7 +2141,7 @@ static void wcnss_send_cal_rsp(unsigned char fw_status) rsphdr->msg_len = sizeof(struct smd_msg_hdr) + 1; memcpy(msg + sizeof(struct smd_msg_hdr), &fw_status, 1); - rc = wcnss_smd_tx(msg, rsphdr->msg_len); + rc = wcnss_smd_tx(penv->channel, msg, rsphdr->msg_len); if (rc < 0) wcnss_log(ERR, "smd tx failed\n"); @@ -2270,7 +2271,8 @@ static void wcnss_process_smd_msg(void *buf, int len) case WCNSS_PRONTO_HW: smd_msg.msg_type = WCNSS_BUILD_VER_REQ; smd_msg.msg_len = sizeof(smd_msg); - rc = wcnss_smd_tx(&smd_msg, smd_msg.msg_len); + rc = wcnss_smd_tx(penv->channel, &smd_msg, + smd_msg.msg_len); if (rc < 0) wcnss_log(ERR, "smd tx failed: %s\n", __func__); @@ -2357,7 +2359,7 @@ static void wcnss_send_version_req(struct work_struct *worker) smd_msg.msg_type = WCNSS_VERSION_REQ; smd_msg.msg_len = sizeof(smd_msg); - ret = wcnss_smd_tx(&smd_msg, smd_msg.msg_len); + ret = wcnss_smd_tx(penv->channel, &smd_msg, smd_msg.msg_len); if (ret < 0) wcnss_log(ERR, "smd tx failed\n"); } @@ -2397,7 +2399,7 @@ static void wcnss_send_pm_config(struct work_struct *worker) hdr->msg_type = WCNSS_PM_CONFIG_REQ; hdr->msg_len = sizeof(struct smd_msg_hdr) + (prop_len * sizeof(int)); - rc = wcnss_smd_tx(msg, hdr->msg_len); + rc = wcnss_smd_tx(penv->channel, msg, hdr->msg_len); if (rc < 0) wcnss_log(ERR, "smd tx failed\n"); @@ -2488,7 +2490,8 @@ static void wcnss_nvbin_dnld(void) (nv_blob_addr + count * NV_FRAGMENT_SIZE), cur_frag_size); - ret = wcnss_smd_tx(outbuffer, dnld_req_msg->hdr.msg_len); + ret = wcnss_smd_tx(penv->channel, outbuffer, + dnld_req_msg->hdr.msg_len); retry_count = 0; while ((ret == -ENOSPC) && (retry_count <= 3)) { @@ -2502,7 +2505,7 @@ static void wcnss_nvbin_dnld(void) /* wait and try again */ msleep(20); retry_count++; - ret = wcnss_smd_tx(outbuffer, + ret = wcnss_smd_tx(penv->channel, outbuffer, dnld_req_msg->hdr.msg_len); } @@ -2581,7 +2584,9 @@ static void wcnss_caldata_dnld(const void *cal_data, (cal_data + count * NV_FRAGMENT_SIZE), cur_frag_size); - ret = wcnss_smd_tx(outbuffer, cal_msg->hdr.msg_len); + ret = wcnss_smd_tx(penv->channel, outbuffer, + cal_msg->hdr.msg_len); + retry_count = 0; while ((ret == -ENOSPC) && (retry_count <= 3)) { @@ -2595,7 +2600,7 @@ static void wcnss_caldata_dnld(const void *cal_data, /* wait and try again */ msleep(20); retry_count++; - ret = wcnss_smd_tx(outbuffer, + ret = wcnss_smd_tx(penv->channel, outbuffer, cal_msg->hdr.msg_len); } diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 0decda7587b9..73ab6121bab5 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -169,6 +169,7 @@ int wcnss_get_wlan_unsafe_channel( u16 *ch_count); struct rpmsg_endpoint *wcnss_open_channel(const char *name, rpmsg_rx_cb_t cb, void *priv); +int wcnss_smd_tx(struct rpmsg_endpoint *channel, void *data, int len); #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev) #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data)) /* WLAN driver uses these names */ -- GitLab From f14f0d5e4e1c9b03e4b38bc30506ebe8c0c197e5 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Mon, 22 Jun 2020 15:22:39 +0530 Subject: [PATCH 0912/1055] wcnss: Export SMD channel close API for wlan driver removal The SMD channel is not the primary WCNSS channel and must explicitly be closed as the device is removed, or the channel will already be open on a subsequent probe call in e.g. the case of reloading the wlan kernel module. Export SMD channel close API for wlan driver removal case. Change-Id: I2f140c429d7c57b8dd53e4e62c9e4dc12b42bf8e Signed-off-by: Govind Singh --- drivers/soc/qcom/wcnss/wcnss_wlan.c | 6 ++++++ include/linux/wcnss_wlan.h | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/soc/qcom/wcnss/wcnss_wlan.c b/drivers/soc/qcom/wcnss/wcnss_wlan.c index e97b72bd5e7c..6d2962e4a7b9 100644 --- a/drivers/soc/qcom/wcnss/wcnss_wlan.c +++ b/drivers/soc/qcom/wcnss/wcnss_wlan.c @@ -1335,6 +1335,12 @@ struct rpmsg_endpoint *wcnss_open_channel(const char *name, rpmsg_rx_cb_t cb, } EXPORT_SYMBOL(wcnss_open_channel); +void wcnss_close_channel(struct rpmsg_endpoint *channel) +{ + rpmsg_destroy_ept(channel); +} +EXPORT_SYMBOL(wcnss_close_channel); + static int wcnss_ctrl_smd_callback(struct rpmsg_device *rpdev, void *data, int count, diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 73ab6121bab5..678a65f8baba 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -169,6 +169,7 @@ int wcnss_get_wlan_unsafe_channel( u16 *ch_count); struct rpmsg_endpoint *wcnss_open_channel(const char *name, rpmsg_rx_cb_t cb, void *priv); +void wcnss_close_channel(struct rpmsg_endpoint *channel); int wcnss_smd_tx(struct rpmsg_endpoint *channel, void *data, int len); #define wcnss_wlan_get_drvdata(dev) dev_get_drvdata(dev) #define wcnss_wlan_set_drvdata(dev, data) dev_set_drvdata((dev), (data)) -- GitLab From f4e260f486ee320dd31a9ae70894808e6b9b9277 Mon Sep 17 00:00:00 2001 From: Deepak Dimri Date: Tue, 16 Jun 2020 00:58:08 +0530 Subject: [PATCH 0913/1055] defconfig: sa2150p: remove bluetooth driver not required Telematics products based on sa2150p does not feature BT therefore drivers are removed. Change-Id: Ic194bcae2210c19cc8a558a4ad5c2b67450548c6 Signed-off-by: Deepak Dimri --- arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig | 7 ++----- arch/arm64/configs/vendor/sa2150p-nand_defconfig | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig index 796f4f6df27e..866252a414f4 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig @@ -204,11 +204,6 @@ CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_CAN=y CONFIG_QTI_CAN=y -CONFIG_BT=y -# CONFIG_BT_BREDR is not set -# CONFIG_BT_LE is not set -# CONFIG_BT_DEBUGFS is not set -CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_MAC80211=m @@ -288,6 +283,7 @@ CONFIG_I2C_MSM_V2=y CONFIG_SPI=y CONFIG_SPI_QUP=y CONFIG_SPMI=y +CONFIG_SLIMBUS=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PPS_CLIENT_GPIO=y CONFIG_PTP_1588_CLOCK=y @@ -493,6 +489,7 @@ CONFIG_HARDENED_USERCOPY=y CONFIG_HARDENED_USERCOPY_PAGESPAN=y CONFIG_SECURITY_SELINUX=y CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_CMAC=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/vendor/sa2150p-nand_defconfig b/arch/arm64/configs/vendor/sa2150p-nand_defconfig index 16c381f7460d..530ed6e2e3c7 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand_defconfig @@ -210,11 +210,6 @@ CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_CAN=y CONFIG_QTI_CAN=y -CONFIG_BT=y -# CONFIG_BT_BREDR is not set -# CONFIG_BT_LE is not set -# CONFIG_BT_DEBUGFS is not set -CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_MAC80211=m @@ -298,6 +293,7 @@ CONFIG_SPI_QUP=y CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_SLIMBUS=y CONFIG_SLIMBUS_MSM_NGD=y CONFIG_PPS_CLIENT_GPIO=y CONFIG_PTP_1588_CLOCK=y @@ -543,6 +539,7 @@ CONFIG_HARDENED_USERCOPY=y CONFIG_HARDENED_USERCOPY_PAGESPAN=y CONFIG_SECURITY_SELINUX=y CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_CMAC=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y -- GitLab From 92962304961bbca6f70f7aca574c568b0626ede7 Mon Sep 17 00:00:00 2001 From: Deepak Dimri Date: Tue, 23 Jun 2020 19:43:06 +0530 Subject: [PATCH 0914/1055] defconfig: sa2150p: remove IEEE 802.11 support Telematics products based on sa2150p do not support wireless communication therefore this commit removes wireless configuration API, wireless regulatory rules database, hardware independent IEEE 802.11 networking stack, minstrel 802.11ac support and RF switches control drivers. Change-Id: I030cb956cf8e96a21e33d51643d81b969ca4dbd1 Signed-off-by: Deepak Dimri --- arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig | 6 ------ arch/arm64/configs/vendor/sa2150p-nand_defconfig | 6 ------ 2 files changed, 12 deletions(-) diff --git a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig index 866252a414f4..8ad55958506e 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig @@ -204,12 +204,6 @@ CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_CAN=y CONFIG_QTI_CAN=y -CONFIG_CFG80211=y -CONFIG_CFG80211_INTERNAL_REGDB=y -CONFIG_MAC80211=m -CONFIG_MAC80211_RC_MINSTREL_VHT=y -CONFIG_MAC80211_DEBUGFS=y -CONFIG_RFKILL=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_MTD=y diff --git a/arch/arm64/configs/vendor/sa2150p-nand_defconfig b/arch/arm64/configs/vendor/sa2150p-nand_defconfig index 530ed6e2e3c7..b215279b7c17 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand_defconfig @@ -210,12 +210,6 @@ CONFIG_QRTR=y CONFIG_QRTR_SMD=y CONFIG_CAN=y CONFIG_QTI_CAN=y -CONFIG_CFG80211=y -CONFIG_CFG80211_INTERNAL_REGDB=y -CONFIG_MAC80211=m -CONFIG_MAC80211_RC_MINSTREL_VHT=y -CONFIG_MAC80211_DEBUGFS=y -CONFIG_RFKILL=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_MTD=y -- GitLab From 25b4ae556349352733c7435e6ee2ff128287d51e Mon Sep 17 00:00:00 2001 From: Raghu Ananya Arabolu Date: Fri, 25 Oct 2019 10:50:46 -0700 Subject: [PATCH 0915/1055] msm: kgsl: Do not double free pages in kgsl_memdesc We have a situation where the page count value is non-zero but the pages pointer is pointing to memory that is already freed. We then go on to access this invalid pages pointer to free the pages that have already been freed. We now check for the validity of the pages pointer before attempting to free it. Also set the page count to 0 before freeing pages and set the pages pointer to NULL after freeing pages. Change-Id: I2b8e63a5f2ad2245f0068214b8925b147435d5db Signed-off-by: Raghu Ananya Arabolu Signed-off-by: Pankaj Gupta --- drivers/gpu/msm/kgsl_pool.c | 8 ++++++++ drivers/gpu/msm/kgsl_sharedmem.c | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c index ea9e52354f56..b3ad32257cde 100644 --- a/drivers/gpu/msm/kgsl_pool.c +++ b/drivers/gpu/msm/kgsl_pool.c @@ -265,12 +265,20 @@ void kgsl_pool_free_pages(struct page **pages, unsigned int pcount) if (pages == NULL || pcount == 0) return; + if (WARN(!kern_addr_valid((unsigned long)pages), + "Address of pages=%pK is not valid\n", pages)) + return; + for (i = 0; i < pcount;) { /* * Free each page or compound page group individually. */ struct page *p = pages[i]; + if (WARN(!kern_addr_valid((unsigned long)p), + "Address of page=%pK is not valid\n", p)) + return; + i += 1 << compound_order(p); kgsl_pool_free_page(p); } diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 9746d15163a4..f96baacb7842 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, 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 @@ -1053,8 +1053,11 @@ void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc) kfree(memdesc->sgt); } + memdesc->page_count = 0; if (memdesc->pages) kgsl_free(memdesc->pages); + memdesc->pages = NULL; + } EXPORT_SYMBOL(kgsl_sharedmem_free); -- GitLab From ea1c45f40e5dac7c7d0536d85730f04d80255594 Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Tue, 23 Jun 2020 10:20:41 -0700 Subject: [PATCH 0916/1055] msm: ipa: Support hardware accelerated DIAG over qdss Add support to accelarate QDSS diag traffic over IPA to the PCIe host. Change-Id: Ia1f534b249e5581ebec4bf7deac073de50a252fe Signed-off-by: Michael Adisumarta --- drivers/platform/msm/gsi/gsi.c | 1 + drivers/platform/msm/ipa/ipa_api.c | 29 ++- drivers/platform/msm/ipa/ipa_api.h | 6 + drivers/platform/msm/ipa/ipa_v3/Makefile | 2 +- drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 7 + drivers/platform/msm/ipa/ipa_v3/ipa_qdss.c | 267 ++++++++++++++++++++ drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 84 +++++- include/linux/ipa_qdss.h | 107 ++++++++ include/linux/msm_gsi.h | 30 ++- include/uapi/linux/msm_ipa.h | 3 +- 10 files changed, 530 insertions(+), 6 deletions(-) create mode 100644 drivers/platform/msm/ipa/ipa_v3/ipa_qdss.c create mode 100644 include/linux/ipa_qdss.h diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index cba9f546fb38..0626b7f3234f 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -2173,6 +2173,7 @@ static void gsi_program_chan_ctx(struct gsi_chan_props *props, unsigned int ee, break; case GSI_CHAN_PROT_AQC: case GSI_CHAN_PROT_11AD: + case GSI_CHAN_PROT_QDSS: prot_msb = 1; break; default: diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c index 0977a048f93d..755910c02582 100644 --- a/drivers/platform/msm/ipa/ipa_api.c +++ b/drivers/platform/msm/ipa/ipa_api.c @@ -222,7 +222,7 @@ const char *ipa_clients_strings[IPA_CLIENT_MAX] = { __stringify(IPA_CLIENT_Q6_CV2X_CONS), __stringify(IPA_CLIENT_MHI_LOW_LAT_PROD), __stringify(IPA_CLIENT_MHI_LOW_LAT_CONS), - __stringify(RESERVERD_PROD_110), + __stringify(IPA_CLIENT_QDSS_PROD), __stringify(IPA_CLIENT_MHI_QDSS_CONS), }; @@ -3809,6 +3809,33 @@ bool ipa_pm_is_used(void) return ret; } +/** + * ipa_conn_qdss_pipes() - connect qdss pipes + */ +int ipa_qdss_conn_pipes(struct ipa_qdss_conn_in_params *in, + struct ipa_qdss_conn_out_params *out) +{ + int ret; + + IPA_API_DISPATCH_RETURN(ipa_conn_qdss_pipes, in, out); + + return ret; +} +EXPORT_SYMBOL(ipa_qdss_conn_pipes); + +/** + * ipa_disconn_qdss_pipes() - disconnect qdss pipes + */ +int ipa_qdss_disconn_pipes(void) +{ + int ret; + + IPA_API_DISPATCH_RETURN(ipa_disconn_qdss_pipes); + + return ret; +} +EXPORT_SYMBOL(ipa_qdss_disconn_pipes); + static const struct dev_pm_ops ipa_pm_ops = { .suspend_noirq = ipa_ap_suspend, .resume_noirq = ipa_ap_resume, diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h index 8b7799ca053c..b1f8a00d12ac 100644 --- a/drivers/platform/msm/ipa/ipa_api.h +++ b/drivers/platform/msm/ipa/ipa_api.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "ipa_common_i.h" #ifndef _IPA_API_H_ @@ -498,6 +499,11 @@ struct ipa_api_controller { int (*ipa_del_socksv5_conn)(uint32_t handle); + int (*ipa_conn_qdss_pipes)(struct ipa_qdss_conn_in_params *in, + struct ipa_qdss_conn_out_params *out); + + int (*ipa_disconn_qdss_pipes)(void); + }; #ifdef CONFIG_IPA diff --git a/drivers/platform/msm/ipa/ipa_v3/Makefile b/drivers/platform/msm/ipa/ipa_v3/Makefile index a7b53937ac1e..64096537f865 100644 --- a/drivers/platform/msm/ipa/ipa_v3/Makefile +++ b/drivers/platform/msm/ipa/ipa_v3/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_IPA3) += ipat.o ipat-y := ipa.o ipa_debugfs.o ipa_hdr.o ipa_flt.o ipa_rt.o ipa_dp.o ipa_client.o \ ipa_utils.o ipa_nat.o ipa_intf.o teth_bridge.o ipa_interrupts.o \ ipa_uc.o ipa_uc_wdi.o ipa_dma.o ipa_uc_mhi.o ipa_mhi.o ipa_uc_ntn.o \ - ipa_hw_stats.o ipa_pm.o ipa_wdi3_i.o ipa_odl.o ipa_wigig_i.o + ipa_hw_stats.o ipa_pm.o ipa_wdi3_i.o ipa_odl.o ipa_wigig_i.o ipa_qdss.o ipat-$(CONFIG_IPA_EMULATION) += ipa_dt_replacement.o diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index a064074ea0df..16e5db011bb8 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -2394,6 +2394,9 @@ int ipa3_cfg_ep_route(u32 clnt_hdl, const struct ipa_ep_cfg_route *ipa_ep_cfg); int ipa3_cfg_ep_holb(u32 clnt_hdl, const struct ipa_ep_cfg_holb *ipa_ep_cfg); +int ipa3_force_cfg_ep_holb(u32 clnt_hdl, + struct ipa_ep_cfg_holb *ipa_ep_cfg); + void ipa3_cal_ep_holb_scale_base_val(u32 tmr_val, struct ipa_ep_cfg_holb *ep_holb); @@ -2823,6 +2826,10 @@ void ipa3_debugfs_post_init(void); void ipa3_debugfs_remove(void); void ipa3_dump_buff_internal(void *base, dma_addr_t phy_base, u32 size); + +int ipa3_conn_qdss_pipes(struct ipa_qdss_conn_in_params *in, + struct ipa_qdss_conn_out_params *out); +int ipa3_disconn_qdss_pipes(void); #ifdef IPA_DEBUG #define IPA_DUMP_BUFF(base, phy_base, size) \ ipa3_dump_buff_internal(base, phy_base, size) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qdss.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qdss.c new file mode 100644 index 000000000000..dd95fcd398a0 --- /dev/null +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qdss.c @@ -0,0 +1,267 @@ +/* Copyright (c) 2018-2020, 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 "ipa_i.h" + +#define IPA_HOLB_TMR_VALUE 0 +#define OFFLOAD_DRV_NAME "ipa_qdss" +#define IPA_QDSS_DBG(fmt, args...) \ + do { \ + pr_debug(OFFLOAD_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +#define IPA_QDSS_ERR(fmt, args...) \ + do { \ + pr_err(OFFLOAD_DRV_NAME " %s:%d " fmt, \ + __func__, __LINE__, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf(), \ + OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \ + IPA_IPC_LOGGING(ipa_get_ipc_logbuf_low(), \ + OFFLOAD_DRV_NAME " %s:%d " fmt, ## args); \ + } while (0) + +static void ipa3_qdss_gsi_chan_err_cb(struct gsi_chan_err_notify *notify) +{ + switch (notify->evt_id) { + case GSI_CHAN_INVALID_TRE_ERR: + IPAERR("Got GSI_CHAN_INVALID_TRE_ERR\n"); + break; + case GSI_CHAN_NON_ALLOCATED_EVT_ACCESS_ERR: + IPAERR("Got GSI_CHAN_NON_ALLOCATED_EVT_ACCESS_ERR\n"); + break; + case GSI_CHAN_OUT_OF_BUFFERS_ERR: + IPAERR("Got GSI_CHAN_OUT_OF_BUFFERS_ERR\n"); + break; + case GSI_CHAN_OUT_OF_RESOURCES_ERR: + IPAERR("Got GSI_CHAN_OUT_OF_RESOURCES_ERR\n"); + break; + case GSI_CHAN_UNSUPPORTED_INTER_EE_OP_ERR: + IPAERR("Got GSI_CHAN_UNSUPPORTED_INTER_EE_OP_ERR\n"); + break; + case GSI_CHAN_HWO_1_ERR: + IPAERR("Got GSI_CHAN_HWO_1_ERR\n"); + break; + default: + IPAERR("Unexpected err evt: %d\n", notify->evt_id); + } + ipa_assert(); +} + +int ipa3_conn_qdss_pipes(struct ipa_qdss_conn_in_params *in, + struct ipa_qdss_conn_out_params *out) +{ + struct gsi_chan_props gsi_channel_props; + struct ipa3_ep_context *ep_rx; + const struct ipa_gsi_ep_config *gsi_ep_info; + union __packed gsi_channel_scratch ch_scratch; + u32 gsi_db_addr_low, gsi_db_addr_high; + struct ipa_ep_cfg ep_cfg = { { 0 } }; + int ipa_ep_idx_rx, ipa_ep_idx_tx; + int result = 0; + struct ipa_ep_cfg_holb holb_cfg; + + if (!(in && out)) { + IPA_QDSS_ERR("Empty parameters. in=%pK out=%pK\n", in, out); + return -IPA_QDSS_PIPE_CONN_FAILURE; + } + + ipa_ep_idx_tx = ipa3_get_ep_mapping(IPA_CLIENT_MHI_QDSS_CONS); + if ((ipa_ep_idx_tx) < 0 || (!ipa3_ctx->ipa_config_is_mhi)) { + IPA_QDSS_ERR("getting EP map failed\n"); + return -IPA_QDSS_PIPE_CONN_FAILURE; + } + + ipa_ep_idx_rx = ipa3_get_ep_mapping(IPA_CLIENT_QDSS_PROD); + if ((ipa_ep_idx_rx == -1) || + (ipa_ep_idx_rx >= IPA3_MAX_NUM_PIPES)) { + IPA_QDSS_ERR("out of range ipa_ep_idx_rx = %d\n", + ipa_ep_idx_rx); + return -IPA_QDSS_PIPE_CONN_FAILURE; + } + + ep_rx = &ipa3_ctx->ep[ipa_ep_idx_rx]; + + if (ep_rx->valid) { + IPA_QDSS_ERR("EP already allocated.\n"); + return IPA_QDSS_SUCCESS; + } + + memset(ep_rx, 0, offsetof(struct ipa3_ep_context, sys)); + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + + ep_rx->valid = 1; + ep_rx->client = IPA_CLIENT_QDSS_PROD; + if (ipa3_cfg_ep(ipa_ep_idx_rx, &ep_rx->cfg)) { + IPAERR("fail to setup rx pipe cfg\n"); + goto fail; + } + + /* setup channel ring */ + memset(&gsi_channel_props, 0, sizeof(gsi_channel_props)); + gsi_channel_props.prot = GSI_CHAN_PROT_QDSS; + gsi_channel_props.dir = GSI_CHAN_DIR_TO_GSI; + + gsi_ep_info = ipa3_get_gsi_ep_info(ep_rx->client); + if (!gsi_ep_info) { + IPA_QDSS_ERR("Failed getting GSI EP info for client=%d\n", + ep_rx->client); + goto fail; + } + + gsi_channel_props.ch_id = gsi_ep_info->ipa_gsi_chan_num; + gsi_channel_props.re_size = GSI_CHAN_RE_SIZE_8B; + gsi_channel_props.use_db_eng = GSI_CHAN_DB_MODE; + gsi_channel_props.err_cb = ipa3_qdss_gsi_chan_err_cb; + gsi_channel_props.ring_len = in->desc_fifo_size; + gsi_channel_props.ring_base_addr = + in->desc_fifo_base_addr; + result = gsi_alloc_channel(&gsi_channel_props, ipa3_ctx->gsi_dev_hdl, + &ep_rx->gsi_chan_hdl); + if (result != GSI_STATUS_SUCCESS) { + IPA_QDSS_ERR("Failed allocating gsi_chan_hdl=%d\n", + &ep_rx->gsi_chan_hdl); + goto fail; + } + + ep_rx->gsi_mem_info.chan_ring_len = gsi_channel_props.ring_len; + ep_rx->gsi_mem_info.chan_ring_base_addr = + gsi_channel_props.ring_base_addr; + + /* write channel scratch, do we need this? */ + memset(&ch_scratch, 0, sizeof(ch_scratch)); + ch_scratch.qdss.bam_p_evt_dest_addr = in->bam_p_evt_dest_addr; + ch_scratch.qdss.data_fifo_base_addr = in->data_fifo_base_addr; + ch_scratch.qdss.data_fifo_size = in->data_fifo_size; + ch_scratch.qdss.bam_p_evt_threshold = in->bam_p_evt_threshold; + ch_scratch.qdss.override_eot = in->override_eot; + result = gsi_write_channel_scratch( + ep_rx->gsi_chan_hdl, ch_scratch); + if (result != GSI_STATUS_SUCCESS) { + IPA_QDSS_ERR("failed to write channel scratch\n"); + goto fail_write_scratch; + } + + /* query channel db address */ + if (gsi_query_channel_db_addr(ep_rx->gsi_chan_hdl, + &gsi_db_addr_low, &gsi_db_addr_high)) { + IPA_QDSS_ERR("failed to query gsi rx db addr\n"); + goto fail_write_scratch; + } + out->ipa_rx_db_pa = (phys_addr_t)(gsi_db_addr_low); + IPA_QDSS_DBG("QDSS out->ipa_rx_db_pa %llu\n", out->ipa_rx_db_pa); + + /* Configuring HOLB on MHI endpoint */ + memset(&holb_cfg, 0, sizeof(holb_cfg)); + holb_cfg.en = IPA_HOLB_TMR_EN; + holb_cfg.tmr_val = IPA_HOLB_TMR_VALUE; + result = ipa3_force_cfg_ep_holb(ipa_ep_idx_tx, &holb_cfg); + if (result) + IPA_QDSS_ERR("Configuring HOLB failed client_type =%d\n", + IPA_CLIENT_MHI_QDSS_CONS); + + /* Set DMA */ + IPA_QDSS_DBG("DMA from %d to %d", IPA_CLIENT_QDSS_PROD, + IPA_CLIENT_MHI_QDSS_CONS); + ep_cfg.mode.mode = IPA_DMA; + ep_cfg.mode.dst = IPA_CLIENT_MHI_QDSS_CONS; + ep_cfg.seq.set_dynamic = true; + if (ipa3_cfg_ep(ipa3_get_ep_mapping(IPA_CLIENT_QDSS_PROD), + &ep_cfg)) { + IPA_QDSS_ERR("Setting DMA mode failed\n"); + goto fail_write_scratch; + } + + /* Start QDSS_rx gsi channel */ + result = ipa3_start_gsi_channel(ipa_ep_idx_rx); + if (result) { + IPA_QDSS_ERR("Failed starting QDSS gsi channel\n"); + goto fail_write_scratch; + } + + IPA_QDSS_DBG("QDSS connect pipe success"); + + return IPA_QDSS_SUCCESS; + +fail_write_scratch: + gsi_dealloc_channel(ep_rx->gsi_chan_hdl); + memset(ep_rx, 0, sizeof(struct ipa3_ep_context)); +fail: + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return -IPA_QDSS_PIPE_CONN_FAILURE; +} + +int ipa3_disconn_qdss_pipes(void) +{ + int result = 0; + int ipa_ep_idx_rx; + struct ipa3_ep_context *ep_rx; + struct ipa_ep_cfg ep_cfg = { { 0 } }; + + ipa_ep_idx_rx = ipa_get_ep_mapping(IPA_CLIENT_QDSS_PROD); + if (ipa_ep_idx_rx == -1) { + IPA_QDSS_ERR("fail to get ep mapping\n"); + return -IPA_QDSS_PIPE_DISCONN_FAILURE; + } + + if (ipa_ep_idx_rx >= IPA3_MAX_NUM_PIPES) { + IPA_QDSS_ERR("ep out of range.\n"); + return -IPA_QDSS_PIPE_DISCONN_FAILURE; + } + + /* Stop QDSS_rx gsi channel / release channel */ + result = ipa3_stop_gsi_channel(ipa_ep_idx_rx); + if (result) { + IPA_QDSS_ERR("Failed stopping QDSS gsi channel\n"); + goto fail; + } + + /* Resetting gsi channel */ + result = ipa3_reset_gsi_channel(ipa_ep_idx_rx); + if (result) { + IPA_QDSS_ERR("Failed resetting QDSS gsi channel\n"); + goto fail; + } + + /* Reset DMA */ + IPA_QDSS_ERR("Resetting DMA %d to %d", + IPA_CLIENT_QDSS_PROD, IPA_CLIENT_MHI_QDSS_CONS); + ep_cfg.mode.mode = IPA_BASIC; + ep_cfg.mode.dst = IPA_CLIENT_MHI_QDSS_CONS; + ep_cfg.seq.set_dynamic = true; + if (ipa3_cfg_ep(ipa3_get_ep_mapping(IPA_CLIENT_QDSS_PROD), + &ep_cfg)) { + IPAERR("Resetting DMA mode failed\n"); + } + + /* Deallocating and Clearing ep config */ + ep_rx = &ipa3_ctx->ep[ipa_ep_idx_rx]; + gsi_dealloc_channel(ep_rx->gsi_chan_hdl); + memset(ep_rx, 0, sizeof(struct ipa3_ep_context)); + + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + IPA_QDSS_DBG("QDSS disconnect pipe success"); + + return IPA_QDSS_SUCCESS; +fail: + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return -IPA_QDSS_PIPE_DISCONN_FAILURE; +} diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index cf42c36d8c25..319e6c13f5d2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -2608,6 +2608,12 @@ static const struct ipa_ep_configuration ipa3_ep_mapping IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_PCIE, { 3, 5, 8, 16, IPA_EE_AP, GSI_SMART_PRE_FETCH, 3 } }, + [IPA_4_5_MHI][IPA_CLIENT_QDSS_PROD] = { + true, IPA_v4_5_MHI_GROUP_QDSS, + false, + IPA_DPS_HPS_SEQ_TYPE_DMA_ONLY, + QMB_MASTER_SELECT_DDR, + { 11, 14, 10, 16, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 } }, /* Only for test purpose */ [IPA_4_5_MHI][IPA_CLIENT_TEST_PROD] = { true, QMB_MASTER_SELECT_DDR, @@ -2701,11 +2707,11 @@ static const struct ipa_ep_configuration ipa3_ep_mapping QMB_MASTER_SELECT_PCIE, { 30, 6, 9, 9, IPA_EE_AP, GSI_SMART_PRE_FETCH, 4 } }, [IPA_4_5_MHI][IPA_CLIENT_MHI_QDSS_CONS] = { - true, IPA_v4_5_MHI_GROUP_PCIE, + true, IPA_v4_5_MHI_GROUP_QDSS, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, QMB_MASTER_SELECT_PCIE, - { 24, 3, 8, 14, IPA_EE_AP, GSI_SMART_PRE_FETCH, 3 } }, + { 24, 3, 8, 14, IPA_EE_AP, GSI_ESCAPE_BUF_ONLY, 0 } }, /* Dummy consumer (pipe 31) is used in L2TP rt rule */ [IPA_4_5_MHI][IPA_CLIENT_DUMMY_CONS] = { true, QMB_MASTER_SELECT_DDR, @@ -5495,6 +5501,78 @@ int ipa3_cfg_ep_holb(u32 clnt_hdl, const struct ipa_ep_cfg_holb *ep_holb) return 0; } +/** + * ipa3_force_cfg_ep_holb() - IPA end-point holb configuration + * for QDSS_MHI_CONS pipe + * + * If an IPA producer pipe is full, IPA HW by default will block + * indefinitely till space opens up. During this time no packets + * including those from unrelated pipes will be processed. Enabling + * HOLB means IPA HW will be allowed to drop packets as/when needed + * and indefinite blocking is avoided. + * + * @clnt_hdl: [in] opaque client handle assigned by IPA to client + * @ipa_ep_cfg: [in] IPA end-point configuration params + * + * Returns: 0 on success, negative on failure + */ +int ipa3_force_cfg_ep_holb(u32 clnt_hdl, + struct ipa_ep_cfg_holb *ep_holb) +{ + if (clnt_hdl >= ipa3_ctx->ipa_num_pipes || + ep_holb == NULL) { + IPAERR("bad parm.\n"); + return -EINVAL; + } + + IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl)); + + if (ep_holb->en == IPA_HOLB_TMR_DIS) { + ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_EN_n, + clnt_hdl, ep_holb); + goto success; + } + + /* Follow HPG sequence to DIS_HOLB, Configure Timer, and HOLB_EN */ + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) { + ep_holb->en = IPA_HOLB_TMR_DIS; + ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_EN_n, + clnt_hdl, ep_holb); + } + + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) { + int res; + + res = ipa3_process_timer_cfg(ep_holb->tmr_val * 1000, + &ep_holb->pulse_generator, + &ep_holb->scaled_time); + if (res) { + IPAERR("failed to process HOLB timer tmr=%u\n", + ep_holb->tmr_val); + ipa_assert(); + return res; + } + } + + ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_TIMER_n, + clnt_hdl, ep_holb); + + /* Enable HOLB */ + ep_holb->en = IPA_HOLB_TMR_EN; + ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_EN_n, + clnt_hdl, ep_holb); + /* IPA4.5 issue requires HOLB_EN to be written twice */ + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_5) + ipahal_write_reg_n_fields(IPA_ENDP_INIT_HOL_BLOCK_EN_n, + clnt_hdl, ep_holb); + +success: + IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl)); + IPADBG("cfg holb %u ep=%d tmr=%d\n", ep_holb->en, clnt_hdl, + ep_holb->tmr_val); + return 0; +} + /** * ipa3_cfg_ep_holb_by_client() - IPA end-point holb configuration * @@ -7293,6 +7371,8 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type, ipa3_get_prot_id; api_ctrl->ipa_add_socksv5_conn = ipa3_add_socksv5_conn; api_ctrl->ipa_del_socksv5_conn = ipa3_del_socksv5_conn; + api_ctrl->ipa_conn_qdss_pipes = ipa3_conn_qdss_pipes; + api_ctrl->ipa_disconn_qdss_pipes = ipa3_disconn_qdss_pipes; return 0; } diff --git a/include/linux/ipa_qdss.h b/include/linux/ipa_qdss.h new file mode 100644 index 000000000000..eca9cecfb4b7 --- /dev/null +++ b/include/linux/ipa_qdss.h @@ -0,0 +1,107 @@ +/* Copyright (c) 2020, 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 _IPA_QDSS_H_ +#define _IPA_QDSS_H_ + +#include + +/** + * enum ipa_qdss_notify - these are the only return items + * @IPA_QDSS_SUCCESS: will be returned as it is for both conn + * and disconn + * @IPA_QDSS_PIPE_CONN_FAILURE: will be returned as negative value + * @IPA_QDSS_PIPE_DISCONN_FAILURE: will be returned as negative value + */ +enum ipa_qdss_notify { + IPA_QDSS_SUCCESS, + IPA_QDSS_PIPE_CONN_FAILURE, + IPA_QDSS_PIPE_DISCONN_FAILURE, +}; + +/** + * struct ipa_qdss_conn_in_params - QDSS -> IPA TX configuration + * @data_fifo_base_addr: Base address of the data FIFO used by BAM + * @data_fifo_size: Size of the data FIFO + * @desc_fifo_base_addr: Base address of the descriptor FIFO by BAM + * @desc_fifo_size: Should be configured to 1 by QDSS + * @bam_p_evt_dest_addr: equivalent to event_ring_doorbell_pa + * physical address of the doorbell that IPA uC + * will update the headpointer of the event ring. + * QDSS should send BAM_P_EVNT_REG address in this var + * Configured with the GSI Doorbell Address. + * GSI sends Update RP by doing a write to this address + * @bam_p_evt_threshold: Threshold level of how many bytes consumed + * @override_eot: if override EOT==1, it doesn't check the EOT bit in + * the descriptor + */ +struct ipa_qdss_conn_in_params { + phys_addr_t data_fifo_base_addr; + u32 data_fifo_size; + phys_addr_t desc_fifo_base_addr; + u32 desc_fifo_size; + phys_addr_t bam_p_evt_dest_addr; + u32 bam_p_evt_threshold; + u32 override_eot; +}; + +/** + * struct ipa_qdss_conn_out_params - information provided + * to QDSS driver + * @rx_db_pa: physical address of IPA doorbell for RX (QDSS->IPA transactions) + * QDSS to take this address and assign it to BAM_P_EVENT_DEST_ADDR + */ +struct ipa_qdss_conn_out_params { + phys_addr_t ipa_rx_db_pa; +}; + +#if defined CONFIG_IPA3 + +/** + * ipa_qdss_conn_pipes - Client should call this + * function to connect QDSS -> IPA pipe + * + * @in: [in] input parameters from client + * @out: [out] output params to client + * + * Note: Should not be called from atomic context + * + * @Return 0 on success, negative on failure + */ +int ipa_qdss_conn_pipes(struct ipa_qdss_conn_in_params *in, + struct ipa_qdss_conn_out_params *out); + +/** + * ipa_qdss_disconn_pipes() - Client should call this + * function to disconnect pipes + * + * Note: Should not be called from atomic context + * + * Returns: 0 on success, negative on failure + */ +int ipa_qdss_disconn_pipes(void); + +#else /* CONFIG_IPA3 */ + +static inline int ipa_qdss_conn_pipes(struct ipa_qdss_conn_in_params *in, + struct ipa_qdss_conn_out_params *out) +{ + return -IPA_QDSS_PIPE_CONN_FAILURE; +} + +static inline int ipa_qdss_disconn_pipes(void) +{ + return -IPA_QDSS_PIPE_DISCONN_FAILURE; +} + +#endif /* CONFIG_IPA3 */ +#endif /* _IPA_QDSS_H_ */ diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h index de179ee36d13..520a53033484 100644 --- a/include/linux/msm_gsi.h +++ b/include/linux/msm_gsi.h @@ -234,6 +234,8 @@ enum gsi_chan_prot { GSI_CHAN_PROT_MHIP = 0x7, GSI_CHAN_PROT_AQC = 0x8, GSI_CHAN_PROT_11AD = 0x9, + GSI_CHAN_PROT_MHIC = 0xA, + GSI_CHAN_PROT_QDSS = 0xB, }; enum gsi_chan_dir { @@ -917,6 +919,32 @@ struct __packed gsi_wdi3_channel_scratch { uint32_t reserved2 : 16; }; +/** + * gsi_qdss_channel_scratch - QDSS SW config area of + * channel scratch + * + * @bam_p_evt_dest_addr: equivalent to event_ring_doorbell_pa + * physical address of the doorbell that IPA uC + * will update the headpointer of the event ring. + * QDSS should send BAM_P_EVNT_REG address in this var + * Configured with the GSI Doorbell Address. + * GSI sends Update RP by doing a write to this address + * @data_fifo_base_addr: Base address of the data FIFO used by BAM + * @data_fifo_size: Size of the data FIFO + * @bam_p_evt_threshold: Threshold level of how many bytes consumed + * @override_eot: if override EOT==1, it doesn't check the EOT bit in + * the descriptor + */ +struct __packed gsi_qdss_channel_scratch { + uint32_t bam_p_evt_dest_addr; + uint32_t data_fifo_base_addr; + uint32_t data_fifo_size : 16; + uint32_t bam_p_evt_threshold : 16; + uint32_t reserved1 : 2; + uint32_t override_eot : 1; + uint32_t reserved2 : 29; +}; + /** * gsi_wdi3_channel_scratch2 - WDI3 protocol SW config area of * channel scratch2 @@ -969,6 +997,7 @@ union __packed gsi_channel_scratch { struct __packed gsi_wdi3_channel_scratch wdi3; struct __packed gsi_mhip_channel_scratch mhip; struct __packed gsi_wdi2_channel_scratch_new wdi2_new; + struct __packed gsi_qdss_channel_scratch qdss; struct __packed { uint32_t word1; uint32_t word2; @@ -1727,7 +1756,6 @@ int gsi_halt_channel_ee(unsigned int chan_idx, unsigned int ee, int *code); void gsi_wdi3_write_evt_ring_db(unsigned long chan_hdl, uint32_t db_addr_low, uint32_t db_addr_high); - /** * gsi_wdi3_dump_register - dump wdi3 related gsi registers * diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index eb8594bd0435..497526feb0ca 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -415,7 +415,7 @@ enum ipa_client_type { IPA_CLIENT_MHI_LOW_LAT_PROD = 108, IPA_CLIENT_MHI_LOW_LAT_CONS = 109, - /* RESERVERD PROD = 110, */ + IPA_CLIENT_QDSS_PROD = 110, IPA_CLIENT_MHI_QDSS_CONS = 111, }; @@ -441,6 +441,7 @@ enum ipa_client_type { #define IPA_CLIENT_MHI_PRIME_RMNET_CONS IPA_CLIENT_MHI_PRIME_RMNET_CONS #define IPA_CLIENT_MHI_PRIME_DPL_PROD IPA_CLIENT_MHI_PRIME_DPL_PROD #define IPA_CLIENT_MHI_QDSS_CONS IPA_CLIENT_MHI_QDSS_CONS +#define IPA_CLIENT_QDSS_PROD IPA_CLIENT_QDSS_PROD #define IPA_CLIENT_IS_APPS_CONS(client) \ ((client) == IPA_CLIENT_APPS_LAN_CONS || \ -- GitLab From 486abb8e43375e8a8cee3f45040ccfd9697329f1 Mon Sep 17 00:00:00 2001 From: Chunhuan Zhan Date: Fri, 19 Jun 2020 18:12:01 +0800 Subject: [PATCH 0917/1055] msm: ais: fix 6155 crop issue on mini IFE driver Check the state when csid config_rdi_path and csid deinit_rdi_path. Change-Id: I79c8757fa84c839dfaa8a6b8e4f4789b563718e1 Signed-off-by: Chunhuan Zhan --- .../ais/ais_isp/csid_hw/ais_ife_csid_core.c | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c b/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c index c1603049376b..6aeaa6d88063 100644 --- a/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c +++ b/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c @@ -677,10 +677,17 @@ static int ais_ife_csid_config_rdi_path( struct ais_ife_csid_path_cfg *tmp = &csid_hw->rdi_cfg[i]; + /* + * doesn't compare with itself and + * not INIT/STREAMING rdi + */ + if (id == i || + tmp->state < AIS_ISP_RESOURCE_STATE_INIT_HW) + continue; + /*checking for multiple streams of same VC*/ - if (i != id && - tmp->vc == path_cfg->vc && - tmp->decode_fmt == path_cfg->decode_fmt) { + if (tmp->vc == path_cfg->vc && + tmp->decode_fmt == path_cfg->decode_fmt) { val = path_cfg->decode_fmt << csid_reg->cmn_reg->fmt_shift_val; @@ -784,9 +791,12 @@ static int ais_ife_csid_deinit_rdi_path( struct ais_ife_csid_path_cfg *tmp = &csid_hw->rdi_cfg[i]; - if (i != id && - tmp->vc == path_cfg->vc && - tmp->decode_fmt == path_cfg->decode_fmt) + if (i == id || + tmp->state == AIS_ISP_RESOURCE_STATE_AVAILABLE) + continue; + + if (tmp->vc == path_cfg->vc && + tmp->decode_fmt == path_cfg->decode_fmt) check_cnt++; } -- GitLab From 714e6514c76849b8b67ee4e3cc823b40b97a7f03 Mon Sep 17 00:00:00 2001 From: Dundi Raviteja Date: Tue, 23 Jun 2020 19:08:52 +0530 Subject: [PATCH 0918/1055] wcnss: validate build version response correctly Build version response contains smd_msg_hdr also, so validate build version response length by considering the size of smd_msg_hdr. Change-Id: I538ea8bfd1ab8cab1c128fb3f628ba70f08860be CRs-Fixed: 2716972 Signed-off-by: Dundi Raviteja --- drivers/soc/qcom/wcnss/wcnss_wlan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/wcnss/wcnss_wlan.c b/drivers/soc/qcom/wcnss/wcnss_wlan.c index 5ae9596daab4..0c41f4c61291 100644 --- a/drivers/soc/qcom/wcnss/wcnss_wlan.c +++ b/drivers/soc/qcom/wcnss/wcnss_wlan.c @@ -2291,8 +2291,8 @@ static void wcnss_process_smd_msg(void *buf, int len) break; case WCNSS_BUILD_VER_RSP: - /* ToDo: WCNSS_MAX_BUILD_VER_LEN + sizeof(struct smd_msg_hdr) */ - if (len > WCNSS_MAX_BUILD_VER_LEN) { + if (len > sizeof(struct smd_msg_hdr) + + WCNSS_MAX_BUILD_VER_LEN) { wcnss_log(ERR, "invalid build version:%d\n", len); return; -- GitLab From 0e6a626fa9b363e21743e07d79de0bbb714999c4 Mon Sep 17 00:00:00 2001 From: Chandrasekhar Mattaparthy Date: Wed, 10 Jun 2020 11:39:58 +0530 Subject: [PATCH 0919/1055] defconfig: sdm429w: Enable BGCOM drivers Used to communicate with BG peripheral. Change-Id: Ia489c7e9a0b8d71688fc8e663e79de69af278300 Signed-off-by: Chandrasekhar Mattaparthy --- arch/arm/configs/vendor/sdm429-bg-perf_defconfig | 2 ++ arch/arm/configs/vendor/sdm429-bg_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig index a0e22655968e..26cde56ccf4f 100644 --- a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig @@ -559,6 +559,8 @@ CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y CONFIG_QCOM_CX_IPEAK=y CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_BGCOM_INTERFACE=y +CONFIG_MSM_BGCOM=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm/configs/vendor/sdm429-bg_defconfig b/arch/arm/configs/vendor/sdm429-bg_defconfig index 4377ff628eff..59a786624bb5 100644 --- a/arch/arm/configs/vendor/sdm429-bg_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg_defconfig @@ -584,6 +584,8 @@ CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y CONFIG_QCOM_CX_IPEAK=y CONFIG_MSM_BAM_DMUX=y +CONFIG_MSM_BGCOM_INTERFACE=y +CONFIG_MSM_BGCOM=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y -- GitLab From 4b9e09205ecb9849fe0916412be6f45ae88c22bb Mon Sep 17 00:00:00 2001 From: VijayaKumar T M Date: Thu, 4 Jun 2020 10:51:12 +0530 Subject: [PATCH 0920/1055] ARM: dts: msm: Remove camera pil memory Save 5MB boot memory by removing camera pil memory which is not used by trinket. CRs-Fixed: 2697987 Change-Id: Ibc12944c8cc7570335467116f487f0f1b99e7ab9 Signed-off-by: VijayaKumar T M --- arch/arm64/boot/dts/qcom/trinket.dtsi | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/trinket.dtsi b/arch/arm64/boot/dts/qcom/trinket.dtsi index 2bb87b62d3e8..7169990ed365 100644 --- a/arch/arm64/boot/dts/qcom/trinket.dtsi +++ b/arch/arm64/boot/dts/qcom/trinket.dtsi @@ -448,12 +448,6 @@ reg = <0 0x46200000 0 0x2d00000>; }; - pil_camera_mem: camera_region@4ab00000 { - compatible = "removed-dma-pool"; - no-map; - reg = <0 0x4ab00000 0 0x500000>; - }; - pil_modem_mem: modem_region@4b000000 { compatible = "removed-dma-pool"; no-map; -- GitLab From fbfddd6349434a4ab4b7706030d1ba1852511c10 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Fri, 17 Apr 2020 01:42:09 +0530 Subject: [PATCH 0921/1055] msm: mhi_dev: Disable IPA DMA during MHI cleanup Call IPA API to disable DMA for proper reference count management in the IPA driver. Change-Id: I9bb741dc8d3c24dfd6e03b1c324eb47dccc2526c Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/mhi_dev/mhi_sm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.c b/drivers/platform/msm/mhi_dev/mhi_sm.c index 7c08ad1eae8c..62d4fe0bf7de 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.c +++ b/drivers/platform/msm/mhi_dev/mhi_sm.c @@ -1142,6 +1142,7 @@ int mhi_dev_sm_exit(struct mhi_dev *mhi_dev) flush_workqueue(mhi_sm_ctx->mhi_sm_wq); destroy_workqueue(mhi_sm_ctx->mhi_sm_wq); /* Initiate MHI IPA reset */ + ipa_dma_disable(); ipa_mhi_destroy(); ipa_dma_destroy(); mutex_destroy(&mhi_sm_ctx->mhi_state_lock); -- GitLab From 43d98659e6481e90e563774b264f98404463eb32 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Tue, 23 Jun 2020 17:52:27 +0530 Subject: [PATCH 0922/1055] sched: core_ctl: Fix possible uninitialized variable While setting boost to cluster_data, we iterate clusters with local uninitialized cluster variable, it is possible that, the cluster could be null and is used in trace point. Fix it by moving trace print to cluster validated point. Change-Id: I466a92f2640cd5058f79355ee0cf354c41c79f7b Signed-off-by: Lingutla Chandrasekhar --- kernel/sched/core_ctl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c index da18b81348af..8966f8b9fd03 100644 --- a/kernel/sched/core_ctl.c +++ b/kernel/sched/core_ctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, 2020, 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 @@ -819,7 +819,7 @@ static u64 core_ctl_check_timestamp; int core_ctl_set_boost(bool boost) { unsigned int index = 0; - struct cluster_data *cluster; + struct cluster_data *cluster = NULL; unsigned long flags; int ret = 0; bool boost_state_changed = false; @@ -850,7 +850,8 @@ int core_ctl_set_boost(bool boost) apply_need(cluster); } - trace_core_ctl_set_boost(cluster->boost, ret); + if (cluster) + trace_core_ctl_set_boost(cluster->boost, ret); return ret; } -- GitLab From a6bfa556b3e3c1ab94ffaa76e2f21cf0d1e94e10 Mon Sep 17 00:00:00 2001 From: Nitesh Gupta Date: Thu, 30 Apr 2020 23:28:38 +0530 Subject: [PATCH 0923/1055] msm: mhi_dev: Increase size of ipa_clnt_hndl array ipa_clnt_hndl array supports only 4 channels. Few targets can support more MHI HW channels and can cause out of bound access for higher MHI channels. Increase ipa_clnt_hndl array size to accommodate the maximum number of supported MHI HW channels. Change-Id: Ifb4b17c40a7ac690b9a7fd864b7eb0ade2e5de43 Signed-off-by: Nitesh Gupta --- drivers/platform/msm/mhi_dev/mhi.c | 15 +++++++++++++++ drivers/platform/msm/mhi_dev/mhi.h | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index b03135b2c195..040e9217b813 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -1294,6 +1294,11 @@ static int mhi_hwc_chcmd(struct mhi_dev *mhi, uint chid, switch (type) { case MHI_DEV_RING_EL_RESET: case MHI_DEV_RING_EL_STOP: + if ((chid-HW_CHANNEL_BASE) > NUM_HW_CHANNELS) { + pr_err("Invalid Channel ID = 0x%X\n", chid); + return -EINVAL; + } + rc = ipa_mhi_disconnect_pipe( mhi->ipa_clnt_hndl[chid-HW_CHANNEL_BASE]); if (rc) @@ -1304,6 +1309,16 @@ static int mhi_hwc_chcmd(struct mhi_dev *mhi, uint chid, connect_params.channel_id = chid; connect_params.sys.skip_ep_cfg = true; + if (chid > HW_CHANNEL_END) { + pr_err("Channel DB for %d not enabled\n", chid); + return -EINVAL; + } + + if ((chid-HW_CHANNEL_BASE) > NUM_HW_CHANNELS) { + pr_err("Invalid Channel = 0x%X\n", chid); + return -EINVAL; + } + rc = ipa_mhi_connect_pipe(&connect_params, &mhi->ipa_clnt_hndl[chid-HW_CHANNEL_BASE]); if (rc) diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h index 5dd8559dcaa4..ecd9708fc768 100644 --- a/drivers/platform/msm/mhi_dev/mhi.h +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -271,6 +271,7 @@ struct mhi_config { #define NUM_CHANNELS 128 #define HW_CHANNEL_BASE 100 +#define NUM_HW_CHANNELS 15 #define HW_CHANNEL_END 110 #define MHI_ENV_VALUE 2 #define MHI_MASK_ROWS_CH_EV_DB 4 @@ -549,7 +550,7 @@ struct mhi_dev { size_t ch_ring_start; /* IPA Handles */ - u32 ipa_clnt_hndl[4]; + u32 ipa_clnt_hndl[NUM_HW_CHANNELS]; struct workqueue_struct *ring_init_wq; struct work_struct ring_init_cb_work; struct work_struct re_init; -- GitLab From 7db3a1a5c9a9dcd2f085298fd0fb819ad082f74c Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Wed, 24 Jun 2020 06:21:15 +0530 Subject: [PATCH 0924/1055] regulator: qpnp-lcdb: Disable step voltage ramp for PM8150L V3 The S/W work around to program the LCDB voltage in 500 mV steps is required only for PM8150L version < V3. So, ignore this W/A for the PM8150L V3 and above. Change-Id: Iaaf15062a19c5f6ae492f949d721a991e5b46669 Signed-off-by: Kiran Gunda --- drivers/regulator/qpnp-lcdb-regulator.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c index f32fbd9f4c2d..396ed5415eea 100644 --- a/drivers/regulator/qpnp-lcdb-regulator.c +++ b/drivers/regulator/qpnp-lcdb-regulator.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, 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 @@ -2092,7 +2092,12 @@ static void qpnp_lcdb_pmic_config(struct qpnp_lcdb *lcdb) lcdb->wa_flags |= NCP_SCP_DISABLE_WA; break; case PMI632_SUBTYPE: - case PM6150L_SUBTYPE: + lcdb->wa_flags |= FORCE_PD_ENABLE_WA; + break; + case PM8150L_SUBTYPE: + if (lcdb->pmic_rev_id->rev4 >= PM8150L_V3P0_REV4) + lcdb->voltage_step_ramp = false; + lcdb->wa_flags |= FORCE_PD_ENABLE_WA; break; default: -- GitLab From 0eb39dba654333e281713f5bffb21d1b2fdaec94 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Wed, 10 Jun 2020 12:18:17 -0700 Subject: [PATCH 0925/1055] dfc: add stall recovery timer Add watchdog timer to recover potential data stall when data is not going to the expected DRB and no DFC indication is received. Change-Id: Iaa4b4814967cf9400c36115a083922376d23928d Acked-by: Weiyi Chen Signed-off-by: Subash Abhinov Kasiviswanathan --- .../net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 5 +- drivers/soc/qcom/dfc_qmi.c | 11 +- drivers/soc/qcom/qmi_rmnet.c | 110 +++++++++++++++++- drivers/soc/qcom/qmi_rmnet_i.h | 19 +++ include/soc/qcom/qmi_rmnet.h | 8 +- include/trace/events/dfc.h | 22 ++++ 6 files changed, 164 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c index 6244f3da37c5..2a21dbdba973 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c @@ -126,7 +126,7 @@ static void rmnet_vnd_uninit(struct net_device *dev) gro_cells_destroy(&priv->gro_cells); free_percpu(priv->pcpu_stats); - qos = priv->qos_info; + qos = rcu_dereference(priv->qos_info); RCU_INIT_POINTER(priv->qos_info, NULL); qmi_rmnet_qos_exit_pre(qos); } @@ -370,7 +370,8 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev, rmnet_dev->rtnl_link_ops = &rmnet_link_ops; priv->mux_id = id; - priv->qos_info = qmi_rmnet_qos_init(real_dev, id); + rcu_assign_pointer(priv->qos_info, + qmi_rmnet_qos_init(real_dev, rmnet_dev, id)); netdev_dbg(rmnet_dev, "rmnet dev created\n"); } diff --git a/drivers/soc/qcom/dfc_qmi.c b/drivers/soc/qcom/dfc_qmi.c index cca126db23f6..ef4470ea9445 100644 --- a/drivers/soc/qcom/dfc_qmi.c +++ b/drivers/soc/qcom/dfc_qmi.c @@ -1034,14 +1034,18 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, itm->grant_size = adjusted_grant; /* No further query if the adjusted grant is less - * than 20% of the original grant + * than 20% of the original grant. Add to watch to + * recover if no indication is received. */ if (dfc_qmap && is_query && - itm->grant_size < (fc_info->num_bytes / 5)) + itm->grant_size < (fc_info->num_bytes / 5)) { itm->grant_thresh = itm->grant_size; - else + qmi_rmnet_watchdog_add(itm); + } else { itm->grant_thresh = qmi_rmnet_grant_per(itm->grant_size); + qmi_rmnet_watchdog_remove(itm); + } itm->seq = fc_info->seq_num; itm->ack_req = ack_req; @@ -1143,6 +1147,7 @@ static void dfc_update_tx_link_status(struct net_device *dev, itm->grant_size = 0; itm->tcp_bidir = false; itm->bytes_in_flight = 0; + qmi_rmnet_watchdog_remove(itm); dfc_bearer_flow_ctl(dev, itm, qos); } else if (itm->grant_size == 0 && tx_status && !itm->rat_switch) { itm->grant_size = DEFAULT_GRANT; diff --git a/drivers/soc/qcom/qmi_rmnet.c b/drivers/soc/qcom/qmi_rmnet.c index 963bec244260..8a88865e6e0b 100644 --- a/drivers/soc/qcom/qmi_rmnet.c +++ b/drivers/soc/qcom/qmi_rmnet.c @@ -55,6 +55,7 @@ MODULE_PARM_DESC(rmnet_wq_frequency, "Frequency of PS check in ms"); 1 : rmnet_wq_frequency/10) * (HZ/100)) #define NO_DELAY (0x0000 * HZ) #define PS_INTERVAL_KT (ms_to_ktime(1000)) +#define WATCHDOG_EXPIRE_JF (msecs_to_jiffies(50)) #ifdef CONFIG_QCOM_QMI_DFC static unsigned int qmi_rmnet_scale_factor = 5; @@ -235,6 +236,89 @@ static void qmi_rmnet_reset_txq(struct net_device *dev, unsigned int txq) } } +/** + * qmi_rmnet_watchdog_fn - watchdog timer func + */ +static void qmi_rmnet_watchdog_fn(struct timer_list *t) +{ + struct rmnet_bearer_map *bearer; + + bearer = container_of(t, struct rmnet_bearer_map, watchdog); + + trace_dfc_watchdog(bearer->qos->mux_id, bearer->bearer_id, 2); + + spin_lock_bh(&bearer->qos->qos_lock); + + if (bearer->watchdog_quit) + goto done; + + /* + * Possible stall, try to recover. Enable 80% query and jumpstart + * the bearer if disabled. + */ + bearer->watchdog_expire_cnt++; + bearer->bytes_in_flight = 0; + if (!bearer->grant_size) { + bearer->grant_size = DEFAULT_GRANT; + bearer->grant_thresh = qmi_rmnet_grant_per(bearer->grant_size); + dfc_bearer_flow_ctl(bearer->qos->vnd_dev, bearer, bearer->qos); + } else { + bearer->grant_thresh = qmi_rmnet_grant_per(bearer->grant_size); + } + +done: + bearer->watchdog_started = false; + spin_unlock_bh(&bearer->qos->qos_lock); +} + +/** + * qmi_rmnet_watchdog_add - add the bearer to watch + * Needs to be called with qos_lock + */ +void qmi_rmnet_watchdog_add(struct rmnet_bearer_map *bearer) +{ + bearer->watchdog_quit = false; + + if (bearer->watchdog_started) + return; + + bearer->watchdog_started = true; + mod_timer(&bearer->watchdog, jiffies + WATCHDOG_EXPIRE_JF); + + trace_dfc_watchdog(bearer->qos->mux_id, bearer->bearer_id, 1); +} + +/** + * qmi_rmnet_watchdog_remove - remove the bearer from watch + * Needs to be called with qos_lock + */ +void qmi_rmnet_watchdog_remove(struct rmnet_bearer_map *bearer) +{ + bearer->watchdog_quit = true; + + if (!bearer->watchdog_started) + return; + + if (try_to_del_timer_sync(&bearer->watchdog) >= 0) + bearer->watchdog_started = false; + + trace_dfc_watchdog(bearer->qos->mux_id, bearer->bearer_id, 0); +} + +/** + * qmi_rmnet_bearer_clean - clean the removed bearer + * Needs to be called with rtn_lock but not qos_lock + */ +static void qmi_rmnet_bearer_clean(struct qos_info *qos) +{ + if (qos->removed_bearer) { + qos->removed_bearer->watchdog_quit = true; + del_timer_sync(&qos->removed_bearer->watchdog); + kfree(qos->removed_bearer); + qos->removed_bearer = NULL; + } +} + static struct rmnet_bearer_map *__qmi_rmnet_bearer_get( struct qos_info *qos_info, u8 bearer_id) { @@ -254,6 +338,8 @@ static struct rmnet_bearer_map *__qmi_rmnet_bearer_get( bearer->grant_thresh = qmi_rmnet_grant_per(bearer->grant_size); bearer->mq_idx = INVALID_MQ; bearer->ack_mq_idx = INVALID_MQ; + bearer->qos = qos_info; + timer_setup(&bearer->watchdog, qmi_rmnet_watchdog_fn, 0); list_add(&bearer->list, &qos_info->bearer_head); } @@ -289,7 +375,7 @@ static void __qmi_rmnet_bearer_put(struct net_device *dev, /* Remove from bearer map */ list_del(&bearer->list); - kfree(bearer); + qos_info->removed_bearer = bearer; } } @@ -420,6 +506,9 @@ static int qmi_rmnet_add_flow(struct net_device *dev, struct tcmsg *tcm, done: spin_unlock_bh(&qos_info->qos_lock); + + qmi_rmnet_bearer_clean(qos_info); + return rc; } @@ -463,6 +552,9 @@ qmi_rmnet_del_flow(struct net_device *dev, struct tcmsg *tcm, netif_tx_wake_all_queues(dev); spin_unlock_bh(&qos_info->qos_lock); + + qmi_rmnet_bearer_clean(qos_info); + return 0; } @@ -744,6 +836,8 @@ void qmi_rmnet_enable_all_flows(struct net_device *dev) bearer->tcp_bidir = false; bearer->rat_switch = false; + qmi_rmnet_watchdog_remove(bearer); + if (bearer->tx_off) continue; @@ -906,7 +1000,8 @@ inline unsigned int qmi_rmnet_grant_per(unsigned int grant) } EXPORT_SYMBOL(qmi_rmnet_grant_per); -void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id) +void *qmi_rmnet_qos_init(struct net_device *real_dev, + struct net_device *vnd_dev, u8 mux_id) { struct qos_info *qos; @@ -916,6 +1011,7 @@ void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id) qos->mux_id = mux_id; qos->real_dev = real_dev; + qos->vnd_dev = vnd_dev; qos->tran_num = 0; INIT_LIST_HEAD(&qos->flow_head); INIT_LIST_HEAD(&qos->bearer_head); @@ -927,10 +1023,18 @@ EXPORT_SYMBOL(qmi_rmnet_qos_init); void qmi_rmnet_qos_exit_pre(void *qos) { + struct qos_info *qosi = (struct qos_info *)qos; + struct rmnet_bearer_map *bearer; + if (!qos) return; - list_add(&((struct qos_info *)qos)->list, &qos_cleanup_list); + list_for_each_entry(bearer, &qosi->bearer_head, list) { + bearer->watchdog_quit = true; + del_timer_sync(&bearer->watchdog); + } + + list_add(&qosi->list, &qos_cleanup_list); } EXPORT_SYMBOL(qmi_rmnet_qos_exit_pre); diff --git a/drivers/soc/qcom/qmi_rmnet_i.h b/drivers/soc/qcom/qmi_rmnet_i.h index 844dafe0b333..d28c5c99aaee 100644 --- a/drivers/soc/qcom/qmi_rmnet_i.h +++ b/drivers/soc/qcom/qmi_rmnet_i.h @@ -16,6 +16,7 @@ #include #include +#include #define MAX_MQ_NUM 16 #define MAX_CLIENT_NUM 2 @@ -33,6 +34,8 @@ extern int dfc_mode; extern int dfc_qmap; +struct qos_info; + struct rmnet_bearer_map { struct list_head list; u8 bearer_id; @@ -51,6 +54,11 @@ struct rmnet_bearer_map { u32 ack_txid; u32 mq_idx; u32 ack_mq_idx; + struct qos_info *qos; + struct timer_list watchdog; + bool watchdog_started; + bool watchdog_quit; + u32 watchdog_expire_cnt; }; struct rmnet_flow_map { @@ -76,11 +84,13 @@ struct qos_info { struct list_head list; u8 mux_id; struct net_device *real_dev; + struct net_device *vnd_dev; struct list_head flow_head; struct list_head bearer_head; struct mq_map mq[MAX_MQ_NUM]; u32 tran_num; spinlock_t qos_lock; + struct rmnet_bearer_map *removed_bearer; }; struct qmi_info { @@ -151,6 +161,11 @@ void dfc_qmap_send_ack(struct qos_info *qos, u8 bearer_id, u16 seq, u8 type); struct rmnet_bearer_map *qmi_rmnet_get_bearer_noref(struct qos_info *qos_info, u8 bearer_id); + +void qmi_rmnet_watchdog_add(struct rmnet_bearer_map *bearer); + +void qmi_rmnet_watchdog_remove(struct rmnet_bearer_map *bearer); + #else static inline struct rmnet_flow_map * qmi_rmnet_get_flow_map(struct qos_info *qos_info, @@ -194,6 +209,10 @@ dfc_qmap_client_init(void *port, int index, struct svc_info *psvc, static inline void dfc_qmap_client_exit(void *dfc_data) { } + +static inline void qmi_rmnet_watchdog_remove(struct rmnet_bearer_map *bearer) +{ +} #endif #ifdef CONFIG_QCOM_QMI_POWER_COLLAPSE diff --git a/include/soc/qcom/qmi_rmnet.h b/include/soc/qcom/qmi_rmnet.h index dbfdca1006de..2e5a8e70a712 100644 --- a/include/soc/qcom/qmi_rmnet.h +++ b/include/soc/qcom/qmi_rmnet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, 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 @@ -52,7 +52,8 @@ qmi_rmnet_all_flows_enabled(struct net_device *dev) #endif #ifdef CONFIG_QCOM_QMI_DFC -void *qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id); +void *qmi_rmnet_qos_init(struct net_device *real_dev, + struct net_device *vnd_dev, u8 mux_id); void qmi_rmnet_qos_exit_pre(void *qos); void qmi_rmnet_qos_exit_post(void); void qmi_rmnet_burst_fc_check(struct net_device *dev, @@ -60,7 +61,8 @@ void qmi_rmnet_burst_fc_check(struct net_device *dev, int qmi_rmnet_get_queue(struct net_device *dev, struct sk_buff *skb); #else static inline void * -qmi_rmnet_qos_init(struct net_device *real_dev, u8 mux_id) +qmi_rmnet_qos_init(struct net_device *real_dev, + struct net_device *vnd_dev, u8 mux_id) { return NULL; } diff --git a/include/trace/events/dfc.h b/include/trace/events/dfc.h index cd53ba83e897..e94e7438396e 100644 --- a/include/trace/events/dfc.h +++ b/include/trace/events/dfc.h @@ -291,6 +291,28 @@ TRACE_EVENT(dfc_adjust_grant, __entry->rx_bytes, __entry->inflight, __entry->a_grant) ); +TRACE_EVENT(dfc_watchdog, + + TP_PROTO(u8 mux_id, u8 bearer_id, u8 event), + + TP_ARGS(mux_id, bearer_id, event), + + TP_STRUCT__entry( + __field(u8, mux_id) + __field(u8, bearer_id) + __field(u8, event) + ), + + TP_fast_assign( + __entry->mux_id = mux_id; + __entry->bearer_id = bearer_id; + __entry->event = event; + ), + + TP_printk("mid=%u bid=%u event=%u", + __entry->mux_id, __entry->bearer_id, __entry->event) +); + #endif /* _TRACE_DFC_H */ /* This part must be outside protection */ -- GitLab From 52e7a7d9557af1020aaf9e93c38e16a900b20139 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Thu, 18 Jun 2020 14:57:21 -0700 Subject: [PATCH 0926/1055] dfc: fix null pointer access Fix a null pointer dereference issue when data packets trigger the queuing of powersave work before the powersave workqueue is initialized. Change-Id: Ia3515a7aaa47cb41568c39462bca73ceae11ea9c Acked-by: Weiyi Chen Signed-off-by: Subash Abhinov Kasiviswanathan --- drivers/soc/qcom/qmi_rmnet.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/qmi_rmnet.c b/drivers/soc/qcom/qmi_rmnet.c index 8a88865e6e0b..3ff4f8d94c02 100644 --- a/drivers/soc/qcom/qmi_rmnet.c +++ b/drivers/soc/qcom/qmi_rmnet.c @@ -1056,6 +1056,7 @@ EXPORT_SYMBOL(qmi_rmnet_qos_exit_post); static struct workqueue_struct *rmnet_ps_wq; static struct rmnet_powersave_work *rmnet_work; static bool rmnet_work_quit; +static bool rmnet_work_inited; static LIST_HEAD(ps_list); struct rmnet_powersave_work { @@ -1286,6 +1287,7 @@ void qmi_rmnet_work_init(void *port) rmnet_work_quit = false; qmi_rmnet_work_set_active(rmnet_work->port, 1); queue_delayed_work(rmnet_ps_wq, &rmnet_work->work, PS_INTERVAL); + rmnet_work_inited = true; } EXPORT_SYMBOL(qmi_rmnet_work_init); @@ -1294,7 +1296,7 @@ void qmi_rmnet_work_maybe_restart(void *port) struct qmi_info *qmi; qmi = (struct qmi_info *)rmnet_get_qmi_pt(port); - if (unlikely(!qmi)) + if (unlikely(!qmi || !rmnet_work_inited)) return; if (!test_and_set_bit(PS_WORK_ACTIVE_BIT, &qmi->ps_work_active)) @@ -1310,6 +1312,7 @@ void qmi_rmnet_work_exit(void *port) rmnet_work_quit = true; synchronize_rcu(); + rmnet_work_inited = false; alarm_cancel(&rmnet_work->atimer); cancel_delayed_work_sync(&rmnet_work->work); destroy_workqueue(rmnet_ps_wq); -- GitLab From c816ae601343e8479bd00ef847bc327a7c482258 Mon Sep 17 00:00:00 2001 From: Ashish Kori Date: Fri, 29 May 2020 10:19:05 +0530 Subject: [PATCH 0927/1055] platform: msm: qcom-geni-se: Enable SSC QUP SE clks before SCM call Add logic to do clock on before calling scm call for firmware load after SSR UP and clock off after SCM call. This will prevent any unclocked access for TZ. TZ doesn't have any frmework support for clock enable count. It is expected from HLOS driver to turn on required clk before making SCM call to TZ. This is required for SSC QUP SSR case firmware load. Change-Id: I0d0d28230fdd9c0e97d194d1cdc2bf0b5a6b0488 Signed-off-by: Ashish Kori --- drivers/platform/msm/qcom-geni-se.c | 62 +++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c index a88a292b261f..d2b8a8d75099 100644 --- a/drivers/platform/msm/qcom-geni-se.c +++ b/drivers/platform/msm/qcom-geni-se.c @@ -50,6 +50,12 @@ static unsigned long default_bus_bw_set[] = {0, 19200000, 50000000, #define TZ_PIL_AUTH_GSI_QUP_PROC 0x13 #define SSR_SCM_CMD 0x2 +enum ssc_core_clocks { + SSC_CORE_CLK, + SSC_CORE2X_CLK, + SSC_NUM_CLKS +}; + struct bus_vectors { int src; int dst; @@ -133,6 +139,7 @@ struct geni_se_device { int update; bool vote_for_bw; struct ssc_qup_ssr ssr; + struct clk_bulk_data *ssc_clks; }; #define HW_VER_MAJOR_MASK GENMASK(31, 28) @@ -375,10 +382,17 @@ static void geni_se_ssc_qup_down(struct geni_se_device *dev) struct se_geni_rsc *rsc = NULL; dev->ssr.is_ssr_down = true; + if (list_empty(&dev->ssr.active_list_head)) { + GENI_SE_ERR(dev->log_ctx, false, NULL, + "%s: No Active usecase\n", __func__); + return; + } + list_for_each_entry(rsc, &dev->ssr.active_list_head, rsc_ssr.active_list) { rsc->rsc_ssr.force_suspend(rsc->ctrl_dev); } + clk_bulk_disable_unprepare(SSC_NUM_CLKS, dev->ssc_clks); } static void geni_se_ssc_qup_up(struct geni_se_device *dev) @@ -391,16 +405,39 @@ static void geni_se_ssc_qup_up(struct geni_se_device *dev) desc.args[1] = TZ_SCM_CALL_FROM_HLOS; desc.arginfo = SCM_ARGS(2, SCM_VAL); + if (list_empty(&dev->ssr.active_list_head)) { + GENI_SE_ERR(dev->log_ctx, false, NULL, + "%s: No Active usecase\n", __func__); + return; + } + /* Enable core/2x clk before TZ SCM call */ + ret = clk_bulk_prepare_enable(SSC_NUM_CLKS, dev->ssc_clks); + if (ret) { + GENI_SE_ERR(dev->log_ctx, false, NULL, + "%s: corex/2x clk enable failed ret:%d\n", + __func__, ret); + return; + } + + list_for_each_entry(rsc, &dev->ssr.active_list_head, + rsc_ssr.active_list) + se_geni_clks_on(rsc); + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, SSR_SCM_CMD), &desc); if (ret) { - dev_err(dev->dev, "Unable to load firmware after SSR\n"); + GENI_SE_ERR(dev->log_ctx, false, NULL, + "%s: Unable to load firmware after SSR ret:%d\n", + __func__, ret); return; } list_for_each_entry(rsc, &dev->ssr.active_list_head, - rsc_ssr.active_list) { + rsc_ssr.active_list) + se_geni_clks_off(rsc); + + list_for_each_entry(rsc, &dev->ssr.active_list_head, + rsc_ssr.active_list) rsc->rsc_ssr.force_resume(rsc->ctrl_dev); - } dev->ssr.is_ssr_down = false; } @@ -1974,6 +2011,25 @@ static int geni_se_probe(struct platform_device *pdev) ret = of_property_read_string(geni_se_dev->dev->of_node, "qcom,subsys-name", &geni_se_dev->ssr.subsys_name); if (!ret) { + + geni_se_dev->ssc_clks = devm_kcalloc(dev, SSC_NUM_CLKS, + sizeof(*geni_se_dev->ssc_clks), GFP_KERNEL); + if (!geni_se_dev->ssc_clks) { + ret = -ENOMEM; + dev_err(dev, "%s: Unable to allocate memmory ret:%d\n", + __func__, ret); + return ret; + } + + geni_se_dev->ssc_clks[SSC_CORE_CLK].id = "corex"; + geni_se_dev->ssc_clks[SSC_CORE2X_CLK].id = "core2x"; + ret = devm_clk_bulk_get(dev, SSC_NUM_CLKS, + geni_se_dev->ssc_clks); + if (ret) { + dev_err(dev, "%s: Err getting core/2x clk:%d\n", ret); + return ret; + } + INIT_LIST_HEAD(&geni_se_dev->ssr.active_list_head); ret = geni_se_ssc_qup_ssr_reg(geni_se_dev); if (ret) { -- GitLab From be2a6eeabafe1365ceedd26440170995d97ac311 Mon Sep 17 00:00:00 2001 From: Anurag Chouhan Date: Fri, 19 Jun 2020 12:04:21 +0530 Subject: [PATCH 0928/1055] ARM: dts: msm: Add support for DT overlay QCS410 For supporting device tree overlay on QCS410, need to align overlay device tree with normal device tree changes. Change-Id: I6687b96e884b81667a6dc2ab7dd195dd930df418 Signed-off-by: Anurag Chouhan --- arch/arm64/boot/dts/qcom/qcs410-iot-overlay.dts | 4 ++-- arch/arm64/boot/dts/qcom/qcs410-iot.dtsi | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs410-iot-overlay.dts b/arch/arm64/boot/dts/qcom/qcs410-iot-overlay.dts index 327744a101c1..fc4c9f6cc431 100644 --- a/arch/arm64/boot/dts/qcom/qcs410-iot-overlay.dts +++ b/arch/arm64/boot/dts/qcom/qcs410-iot-overlay.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, 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 @@ -16,7 +16,7 @@ #include "qcs410-iot.dtsi" / { - model = "IOT"; + model = "Qualcomm Technologies, Inc. QCS410 IOT Overlay"; compatible = "qcom,qcs410-iot", "qcom,qcs410", "qcom,iot"; qcom,msm-id = <406 0x0>; qcom,board-id = <32 0>; diff --git a/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi b/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi index cda7be55677b..275b237c4ebd 100644 --- a/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi @@ -13,7 +13,13 @@ #include #include #include -#include "qcs410.dtsi" +#include +#include +#include +#include +#include +#include + #include "qcs610-camera-sensor-idp.dtsi" / { -- GitLab From 6c162f39212a22abe43f9d95324ca8358133bf59 Mon Sep 17 00:00:00 2001 From: Dmitry Bogdanov Date: Wed, 6 May 2020 14:52:28 +0300 Subject: [PATCH 0929/1055] atlantic forwarding driver v1.1.7 [ATLDRV-1469] - AQ083: After suspend resume EAPOL frames is not received [ATLDRV-1497] - Incorrect temperature is displayed in hwmon [ATLDRV-1519] - AQ086: Configuring default ring size Change-Id: I014526fb6010f9fa8a4dd663303b3f63f15aec76 Signed-off-by: Dmitry Bogdanov Signed-off-by: Nikita Danilov Co-authored-by: Nikita Danilov Git-commit: 683002bd1eefbaf23af264878f3409e79ba0b522 Git-repo: https://github.com/aquantia/linux-4.14-atlantic-forwarding Signed-off-by: Jinesh K. Jayakumar --- .../Documentation/networking/atlantic.txt | 283 ++++++++++++++++++ .../ethernet/aquantia/atlantic-fwd/atl2_fw.c | 2 +- .../aquantia/atlantic-fwd/atl_common.h | 2 +- .../ethernet/aquantia/atlantic-fwd/atl_fw.c | 2 +- .../ethernet/aquantia/atlantic-fwd/atl_hw.c | 13 +- .../aquantia/atlantic-fwd/atl_macsec.c | 39 +-- .../ethernet/aquantia/atlantic-fwd/atl_main.c | 25 +- .../ethernet/aquantia/atlantic-fwd/atl_ring.c | 5 +- .../aquantia/atlantic-fwd/release_notes.txt | 7 + 9 files changed, 350 insertions(+), 28 deletions(-) create mode 100644 drivers/net/ethernet/aquantia/atlantic-fwd/Documentation/networking/atlantic.txt diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/Documentation/networking/atlantic.txt b/drivers/net/ethernet/aquantia/atlantic-fwd/Documentation/networking/atlantic.txt new file mode 100644 index 000000000000..5956851c04ed --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/Documentation/networking/atlantic.txt @@ -0,0 +1,283 @@ + + + +Supported hardware +------------------ + +AQC-107 / -108 / -109, revisions B0 / B1. FW versions 1.x / 2.x / 3.x +supported + + + +Features / acceleration +----------------------- + + - Message-signalled interrupts + - Hardware VLAN tag offloads + - Hardware checksum offloads: + - IPv4 header checksums + - UDP / TCP checksums with IPv4 and IPv6 + - Hardware LSO for TCP v4/v6 + - Hardware LRO for TCP v4/v6 + - Coalescing TCP segments with TCP options not supported due to a + HW limitation + - Software GRO using the Linux NAPI GRO interface + - Hardware Rx header splitting + - RSS over up to 8 queues using MSI-X + - Linear skb receive mode + - N-tuple Rx filters + - Runtime power management + - Hardware MACSEC offload + + +Building and installation +------------------------- + +1. Unpack the archive into a directory of your choice. + +2. Change to that directory and compile the module: + $ make [KDIR=] + + Explicitly specifying KDIR is only necessary when the headers can't + be found automatically via the + /lib/modules/`uname -r`/{build,source} symlinks + +3. Load the module + # insmod atlnew.ko [] + +4. Unload the module + # rmmod atlnew + + + +Device configuration +-------------------- + + # ip link set up dev + # ip addr add / brd + dev + +Add a VLAN ID: + # ip link add link name . type vlan id + # ip link set up dev . + +Remove a VLAN ID: + # ip link del dev . + + + +Module parameters +----------------- + +Module parameters may be specified at module load time on the insmod +command line or via modprobe.conf files. Some parameters marked as +[RW] below can also be changed at run time via files in +/sys/module/atlnew/parameters directory + + - msi = < 1 | 0 > (default: 1) [RO] + Enable use of MSI interrupts. + + - rx_refill_batch = (default: 16) [RW] + Number of cleaned Rx ring descriptors to trigger Rx refill + + - tx_clean_budget = (default: 256) [RW] + Max number of processed Tx descriptors to clean in one pass of + NAPI poll + + - max_queues = (default: 8) [RO] + Max number of RSS queues. The actual number of queues will the + minimum of this parameter and the number of logical CPUs in + the system. + + - rx_linear = <0 | 1> (default: 0) + Enables linear skb receive mode. Frames larger than + ATL_RX_BUF_SIZE defined in atl_ring.h will be dropped. + + - min_intr_delay (default: 10) [RW] + When an interrupt is about to be asserted on an LRO-enabled + queue, LRO requires some lead time to close and flush + in-progress flows. This parameter sets the LRO interrupt delay + and provides the lower boundary for interrupt coalescing + delays settable via ethtool. When modified, the new value + takes effect on interface down/up cycle or on setting an + interrupt coalescing delay via ethtool. + + - rx_mod_hyst (default: 10) [RW] + - tx_mod_hyst (default: 10) [RW] + Each ring has two interrupt coalescing timers. When an + interrupt-causing event happens, they're initialized with + values called minimum and maximum respectively. The former + timer is restarted each time another such event happens, while + the latter keeps running. When either timer reaches zero, the + interrupt is reported to the host. The minimum value is set + via ethtool. These module parameters set the difference + between the maximum and minimum values for Rx and Tx + paths. When modified, the new max values go into effect upon + interface down/up cycle or upon modifying ethtool interrupt + coalescing settings. + +- keep_link = < 1 | 0 > (default: 0) [RO] + When set to 1, the ethernet link is established at PCI probe + time, and is not dropped on ifdown. This allows the rings + allocated to forwarding engines to handle traffic even when + linux network interface is down. + +- sleep_delay = (default: 10000) [RW] + Delay in ms after link goes down to suspend the device if runtime power + management is turned on. + +- macsec_bridge = < 1 | 0 > (default: 1) [RO] + When set to 0, several SecY can be created, macsec will filter by source mac + address to apply apropriate SecY. + By default, only 1 SecY can be created, macsec will handle all packets. + +- rx/tx_ring_size = <8..8184> (default: 4096) [RO] + Default size for the rings. + +VLAN filters +------------ + +Sixteen VLAN filters are programmable via the ethtool -N interface using +locations 0 through 15. The only flow-type supported is ether and only +VLAN id can be matched. + +For VLAN filters only, it's possible not to specify an explicit +filter location. In this case an appropriate location will be assigned +automatically. + +These filters are also used for HW filter acceleration for Linux VLAN +subdevices. Filters automatically added by Linux VLAN code can be +overridden using ethtool subject to restrictions described below: + +* A special ring number 32 is used in ethtool interface to signify + 'any ring'. An ethtool filter rule with ring set to 32 accepts a + packet leaving the ring to be determined using the standard RSS + mechanism. VLAN code adds rules in this manner. Such a rule can be + modified using ethool to set a specific destination ring. + +* There can't be two filters with the same VID. An attempt to add a + duplicate filter using an explicit location different from the + location of existing filter with the same VID will fail. When the + location is not specified, the existing filter will be modified. + +* An attempt to change the VID of a filter added by VLAN code using an + explicit location will fail. Either use a different explicit + location or no location. + +* An attempt to delete a rule created by VLAN code will return + success, but the rule will remain in place. If a specific ring was + set in the rule, it will be reset to 'any ring'. + +* If a VLAN sub-device is added when there're no unused filters, VLAN + promiscuous mode will be enabled. This will result in all VIDs being + accepted. Filters can still be used to direct specific VIDs to + specific rings. + +* Even when all 16 filters are used, attempting to add a rule with a + new VID via ethtool will succeed as long as at least one existing + filter was set by VLAN code and still has 'any ring' as + destination. This filter will be re-used for the new rule and VLAN + promiscuous mode will be enabled. + +* When a filter becomes available as a result of a deletion of a VLAN + subdevice or a deletion of an ethtool filter rule, and a VLAN + promiscuous mode is enabled, the vacated filter will be re-used for + another enabled VLAN subdevice. This may result in VLAN promiscuous + mode being turned off if that VLAN subdevice was the last one with + no filter allocated. + +Ethertype filters +----------------- + +Fifteen ethertype filters are programmable via the ethtool -N +interface using locations 16 through 30. The only flow-type supported +is ether and only the ethertype field can be matched. + +N-tuple filters +--------------- + +Eight IPv4 n-tuple filters are supported, programmable using ethtool +-N command with filter locations 32 through 39. + +Fields that can be matched are source / destination IP addresses, and, +for TCP / UDP / SCTP protocols, additionally source / destination +ports can be matched. Partial (masked) matches are not supported, a +mask for each field must consist of either all ones or all zeroes. + +Each aligned group of four filters (locations 32 through 35 or 36 +through 39) can alternatively be used as one IPv6 filter, using filter +locations 32 or 36. + + + +Testing forwarding performance +------------------------------ + +Since this is a design for a router, the best way to test would be +between our aquantia port and another high speed port on the same +DUT. However, in the situation where the Aquantia interface is the +only high speed one, we have devised the following testing strategy +to emulate these two ports on same DUT. + +One of the simplest ways is to set up two VLAN interfaces and forward +traffic between them as in the following example: + +Set up two VLANs with examlple ids 42 and 43 on the Aquantia +interface, assign the switch port connected to it to both of those +VLANs. +# ip link set up dev +# ip link add link name .42 type vlan id 42 +# ip link add link name .43 type vlan id 43 +# ip link set up dev .42 +# ip link set up dev .43 +# ip addr add 10.42.42.1/24 brd + dev .42 +# ip addr add 10.42.43.1/24 brd + dev .43 +# sysctl net.ipv4.ip_forward=1 + +This sets up two VLAN interfaces with VLAN ids 42 and 43 and enables +IP routing. Two hosts should be set up to generate and terminate the +traffic: + +On a host on the 42 VLAN with IP 10.42.42.xx run + $ iperf3 -s +On a host on the 43 VLAN run + $ iperf3 -c 10.42.42.xx + +Another possibility is to use a single host running Linux as a link +partner both generating and terminating the traffic. Two VLAN +sub-interfaces should be configured on a high-speed port on that host, +belonging to VLAN 42 / IP network 10.42.42/24 and VLAN 43 / IP network +10.42.43/24 respectively. + +Since, by default, traffic addressed to one of the local IPs is +received locally, a special configuration of Linux policy routing is +required to make such traffic actually go out on the wire to the DUT, +as described below, where stands for the chosen network interface: + +# ip rule add table local prio 100 +# ip rule del table local prio 0 +# ip rule add iif lo table 42 prio 42 +# ip link set up dev + +# ip link add link name .42 type vlan id 42 +# ip link add link name .43 type vlan id 43 +# ip link set up dev .42 +# ip link set up dev .43 +# ip addr add 10.42.42.10/24 brd + dev .42 +# ip addr add 10.42.43.10/24 brd + dev .43 + +# ip route add 10.42.42.10 via 10.42.43.1 table 42 +# ip route add 10.42.43.10 via 10.42.42.1 table 42 + +This routes the locally-originated traffic, that is addressed to the local IP +of one of the VLAN interfaces, out via the other VLAN interface, instead of +being immediately looped back locally. + + +$ iperf3 -s + +$ iperf3 -c 10.42.42.10 + +The following command can be used to restore the default routing +behavior: + +# ip route flush table 42 diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c index b5b0c20336ec..7aee0e1e63da 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c @@ -578,7 +578,7 @@ static int atl2_fw_get_phy_temperature(struct atl_hw *hw, int *temp) ret = atl2_shared_buffer_read_safe(hw, phy_health_monitor, &phy_health_monitor); - *temp = (phy_health_monitor.phy_temperature & 0xffff) * 1000; + *temp = (int8_t)(phy_health_monitor.phy_temperature) * 1000; atl_unlock_fw(hw); diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h index aca28a972909..7476d093ffdd 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h @@ -20,7 +20,7 @@ #include #include -#define ATL_VERSION "1.1.6" +#define ATL_VERSION "1.1.7" struct atl_nic; diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c index 7ebddca7f857..b04ec5090bd3 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c @@ -535,7 +535,7 @@ static int __atl_fw2_get_phy_temperature(struct atl_hw *hw, int *temp) if (ret) return ret; - *temp = (res & 0xffff) * 1000 / 256; + *temp = (int16_t)(res & 0xFFFF) * 1000 / 256; return ret; } diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c index 06a46226cbef..2761411995d7 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c @@ -473,7 +473,14 @@ void atl_refresh_link(struct atl_nic *nic) netif_carrier_on(nic->ndev); pm_runtime_get_sync(&nic->hw.pdev->dev); #if IS_ENABLED(CONFIG_MACSEC) && defined(NETIF_F_HW_MACSEC) - atl_init_macsec(hw); + { + int ret; + + ret = atl_init_macsec(hw); + + if (ret) + atl_dev_err("atl_init_macsec failed with %d", ret); + } #endif } } else { @@ -549,8 +556,8 @@ int atl_alloc_link_intr(struct atl_nic *nic) int ret; if (nic->flags & ATL_FL_MULTIPLE_VECTORS) { - ret = request_irq(pci_irq_vector(pdev, 0), atl_link_irq, 0, - nic->ndev->name, nic); + ret = request_irq(pci_irq_vector(pdev, 0), atl_link_irq, + IRQF_NO_SUSPEND, nic->ndev->name, nic); if (ret) atl_nic_err("request MSI link vector failed: %d\n", -ret); diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c index 763f1f611e85..b2b3cfb4bfc6 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c @@ -551,6 +551,15 @@ static int atl_set_txsc(struct atl_hw *hw, int txsc_idx) sc_rec.fresh = 1; if (atl_macsec_bridge) { + struct aq_mss_ingress_prectlf_record rx_prectlf_rec; + + memset(&rx_prectlf_rec, 0, sizeof(rx_prectlf_rec)); + ret = aq_mss_set_ingress_prectlf_record(hw, &rx_prectlf_rec, 0); + if (ret) + return ret; + ret = aq_mss_set_packet_edit_control(hw, 0); + if (ret) + return ret; ret = aq_mss_set_drop_igprc_miss_packets(hw, 1); if (ret) return ret; @@ -719,7 +728,19 @@ static int atl_clear_txsc(struct atl_nic *nic, const int txsc_idx, if (ret) return ret; + /* if last txsc is removed then pass macsec packets to host */ if (atl_macsec_bridge) { + struct aq_mss_ingress_prectlf_record rx_prectlf; + + memset(&rx_prectlf, 0, sizeof(rx_prectlf)); + rx_prectlf.match_type = 4; /* Match eth_type only */ + rx_prectlf.action = 0; + ret = aq_mss_set_ingress_prectlf_record(hw, &rx_prectlf, 0); + if (ret) + return ret; + ret = aq_mss_set_packet_edit_control(hw, 0xb068); + if (ret) + return ret; ret = aq_mss_set_drop_igprc_miss_packets(hw, 0); if (ret) return ret; @@ -911,7 +932,6 @@ static int atl_set_rxsc(struct atl_hw *hw, const u32 rxsc_idx) &hw->macsec_cfg.atl_rxsc[rxsc_idx]; struct aq_mss_ingress_preclass_record pre_class_record; const struct macsec_rx_sc *rx_sc = atl_rxsc->sw_rxsc; - struct aq_mss_ingress_prectlf_record rx_prectlf_rec; const struct macsec_secy *secy = atl_rxsc->sw_secy; const u32 hw_sc_idx = atl_rxsc->hw_sc_idx; struct aq_mss_ingress_sc_record sc_record; @@ -921,12 +941,6 @@ static int atl_set_rxsc(struct atl_hw *hw, const u32 rxsc_idx) atl_dev_dbg("set rx_sc: rxsc_idx=%d, sci %#llx, hw_sc_idx=%d\n", rxsc_idx, rx_sc->sci, hw_sc_idx); - if (atl_macsec_bridge) { - memset(&rx_prectlf_rec, 0, sizeof(rx_prectlf_rec)); - aq_mss_set_ingress_prectlf_record(hw, &rx_prectlf_rec, 0); - aq_mss_set_packet_edit_control(hw, 0); - } - memset(&pre_class_record, 0, sizeof(pre_class_record)); nsci = cpu_to_be64((__force u64)rx_sc->sci); memcpy(pre_class_record.sci, &nsci, sizeof(nsci)); @@ -1060,19 +1074,8 @@ static int atl_clear_rxsc(struct atl_nic *nic, const int rxsc_idx, if (clear_type & ATL_CLEAR_HW) { struct aq_mss_ingress_preclass_record pre_class_record; - struct aq_mss_ingress_prectlf_record rx_prectlf; struct aq_mss_ingress_sc_record sc_record; - /* if last rxsc is removed then pass macsec packets to host */ - if (atl_macsec_bridge && - hweight_long(hw->macsec_cfg.rxsc_idx_busy) == 1) { - memset(&rx_prectlf, 0, sizeof(rx_prectlf)); - rx_prectlf.match_type = 4; /* Match eth_type only */ - rx_prectlf.action = 0; - aq_mss_set_ingress_prectlf_record(hw, &rx_prectlf, 0); - aq_mss_set_packet_edit_control(hw, 0xb068); - } - memset(&pre_class_record, 0, sizeof(pre_class_record)); memset(&sc_record, 0, sizeof(sc_record)); diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c index 554ba012db10..b68d83d2a6f3 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c @@ -36,6 +36,11 @@ module_param_named(keep_link, atl_keep_link, uint, 0644); static unsigned int atl_sleep_delay = 10000; module_param_named(sleep_delay, atl_sleep_delay, uint, 0644); +static unsigned int atl_rx_ring_size = ATL_RING_SIZE; +static unsigned int atl_tx_ring_size = ATL_RING_SIZE; +module_param_named(rx_ring_size, atl_rx_ring_size, uint, 0444); +module_param_named(tx_ring_size, atl_tx_ring_size, uint, 0444); + static void atl_start_link(struct atl_nic *nic) { struct atl_hw *hw = &nic->hw; @@ -64,6 +69,7 @@ static int atl_start(struct atl_nic *nic) int ret = 0; atl_start_hw_global(nic); + atl_set_rx_mode(nic->ndev); if (atl_keep_link || netif_running(nic->ndev)) atl_start_link(nic); @@ -527,8 +533,8 @@ static int atl_probe(struct pci_dev *pdev, const struct pci_device_id *id) atl_dev_dbg("got MAC address: %pM\n", hw->mac_addr); nic->requested_nvecs = atl_max_queues; - nic->requested_tx_size = ATL_RING_SIZE; - nic->requested_rx_size = ATL_RING_SIZE; + nic->requested_tx_size = (atl_tx_ring_size & ~7); + nic->requested_rx_size = (atl_rx_ring_size & ~7); nic->rx_intr_delay = atl_rx_mod; nic->tx_intr_delay = atl_tx_mod; @@ -678,6 +684,8 @@ static int atl_suspend_common(struct device *dev, unsigned int wol_mode) atl_stop(nic, true); + atl_intr_disable_non_ring(nic); + atl_clear_rdm_cache(nic); atl_clear_tdm_cache(nic); @@ -863,6 +871,19 @@ static int __init atl_module_init(void) struct atl_hw *hw = NULL; int ret; + if ((atl_tx_ring_size < 8) || (atl_tx_ring_size > ATL_MAX_RING_SIZE)) { + atl_dev_init_err( + "Bad atl_tx_ring_size value %d, must be between 8 and %d inclusive\n", + atl_tx_ring_size, ATL_MAX_RING_SIZE); + return -EINVAL; + } + if ((atl_rx_ring_size < 8) || (atl_rx_ring_size > ATL_MAX_RING_SIZE)) { + atl_dev_init_err( + "Bad atl_rx_ring_size value %d, must be between 8 and %d inclusive\n", + atl_rx_ring_size, ATL_MAX_RING_SIZE); + return -EINVAL; + } + atl_def_thermal.flags = atl_def_thermal_monitor << atl_thermal_monitor_shift | atl_def_thermal_throttle << atl_thermal_throttle_shift | diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c index 2ae71c5d18b3..93d99db69178 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c @@ -444,7 +444,7 @@ static bool atl_checksum_workaround(struct sk_buff *skb, break; case atl_rx_pkt_type_ipv6: ipv6 = (struct ipv6hdr *) &skb->data[ip_header_offset]; - l4_header_offset = ip_header_offset + sizeof(struct ipv6hdr); + l4_header_offset = sizeof(struct ipv6hdr); /* padding inside Ethernet frame */ if (ip_header_offset + sizeof(struct ipv6hdr) + ntohs(ipv6->payload_len) < desc->pkt_len) @@ -1512,7 +1512,8 @@ static int atl_alloc_qvec_intr(struct atl_queue_vec *qvec) return 0; vector = pci_irq_vector(nic->hw.pdev, atl_qvec_intr(qvec)); - ret = request_irq(vector, atl_ring_irq, 0, qvec->name, &qvec->napi); + ret = request_irq(vector, atl_ring_irq, IRQF_NO_SUSPEND, + qvec->name, &qvec->napi); if (ret) { atl_nic_err("request MSI ring vector failed: %d\n", -ret); return ret; diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt b/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt index 382fe9fd1bd1..5fac6ea6eb45 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt @@ -1,3 +1,10 @@ +Version 1.1.7 +============= + + [ATLDRV-1469] - AQ083: After suspend resume EAPOL frames is not received + [ATLDRV-1497] - Incorrect temperature is displayed in hwmon + [ATLDRV-1519] - AQ086: Configuring default ring size + Version 1.1.6 ============= [ATLDRV-1355] - Sporadically unable to set EEE -- GitLab From 5b66fcdf9e5ae869794dae5666778f560d5612b2 Mon Sep 17 00:00:00 2001 From: Yadu MG Date: Tue, 16 Jun 2020 02:29:17 +0530 Subject: [PATCH 0930/1055] soc: qcom: dcc_v2: Add PM callbacks to support hibernation Add freeze and restore callbacks to pm ops. Change-Id: I129b0b8a57093c512409d221804a9a49105df20b Signed-off-by: Yadu MG --- drivers/soc/qcom/dcc_v2.c | 149 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c index e408cc4b087e..d7cd6e074db6 100644 --- a/drivers/soc/qcom/dcc_v2.c +++ b/drivers/soc/qcom/dcc_v2.c @@ -114,6 +114,22 @@ struct rpm_trig_req { uint32_t reserved; }; +/** + * struct dcc_save_state - state to be preserved when dcc is without power + */ +struct dcc_save_state { + uint32_t dcc_exec_ctrl; + uint32_t dcc_cfg; + uint32_t dcc_ll_lock[DCC_MAX_LINK_LIST]; + uint32_t dcc_ll_cfg[DCC_MAX_LINK_LIST]; + uint32_t dcc_ll_base[DCC_MAX_LINK_LIST]; + uint32_t dcc_fd_base[DCC_MAX_LINK_LIST]; + uint32_t dcc_ll_timeout[DCC_MAX_LINK_LIST]; + uint32_t dcc_ll_int_enable[DCC_MAX_LINK_LIST]; + uint32_t dcc_ll_int_status[DCC_MAX_LINK_LIST]; + uint32_t dcc_ll_sw_trigger[DCC_MAX_LINK_LIST]; +}; + struct dcc_config_entry { uint32_t base; uint32_t offset; @@ -150,6 +166,8 @@ struct dcc_drvdata { uint8_t curr_list; uint8_t cti_trig; uint8_t loopoff; + struct dcc_save_state *reg_save_state; + void *sram_save_state; }; static int dcc_sram_writel(struct dcc_drvdata *drvdata, @@ -1843,6 +1861,136 @@ static int dcc_remove(struct platform_device *pdev) return 0; } +static int dcc_v2_freeze(struct device *dev) +{ + int i; + struct dcc_save_state *state; + struct dcc_drvdata *drvdata = dev_get_drvdata(dev); + + if (!drvdata) + return -EINVAL; + + drvdata->reg_save_state = kmalloc(sizeof(struct dcc_save_state), + GFP_KERNEL); + if (!drvdata->reg_save_state) + return -ENOMEM; + + state = drvdata->reg_save_state; + + mutex_lock(&drvdata->mutex); + + state->dcc_exec_ctrl = dcc_readl(drvdata, DCC_EXEC_CTRL); + state->dcc_cfg = dcc_readl(drvdata, DCC_CFG); + + for (i = 0; i < DCC_MAX_LINK_LIST; i++) { + state->dcc_ll_lock[i] = dcc_readl(drvdata, + DCC_LL_LOCK(i)); + state->dcc_ll_cfg[i] = dcc_readl(drvdata, + DCC_LL_CFG(i)); + state->dcc_ll_base[i] = dcc_readl(drvdata, + DCC_LL_BASE(i)); + state->dcc_fd_base[i] = dcc_readl(drvdata, + DCC_FD_BASE(i)); + state->dcc_ll_timeout[i] = dcc_readl(drvdata, + DCC_LL_TIMEOUT(i)); + state->dcc_ll_int_enable[i] = dcc_readl(drvdata, + DCC_LL_INT_ENABLE(i)); + state->dcc_ll_int_status[i] = dcc_readl(drvdata, + DCC_LL_INT_STATUS(i)); + } + + mutex_unlock(&drvdata->mutex); + + drvdata->sram_save_state = kmalloc(drvdata->ram_size, GFP_KERNEL); + if (!drvdata->sram_save_state) + return -ENOMEM; + + if (dcc_sram_memcpy(drvdata->sram_save_state, drvdata->ram_base, + drvdata->ram_size)) { + dev_info(dev, "Failed to copy DCC SRAM contents\n"); + } + + if (drvdata->enable[drvdata->curr_list]) + drvdata->enable[drvdata->curr_list] = 0; + + return 0; +} + +static int dcc_v2_restore(struct device *dev) +{ + int i; + int *data; + struct dcc_save_state *state; + struct dcc_drvdata *drvdata = dev_get_drvdata(dev); + + if (!drvdata && !drvdata->sram_save_state && !drvdata->reg_save_state) + return -EINVAL; + + data = drvdata->sram_save_state; + + for (i = 0; i < drvdata->ram_size / 4; i++) + __raw_writel_no_log(data[i], + drvdata->ram_base + (i * 4)); + + state = drvdata->reg_save_state; + + mutex_lock(&drvdata->mutex); + + dcc_writel(drvdata, state->dcc_exec_ctrl, DCC_EXEC_CTRL); + dcc_writel(drvdata, state->dcc_cfg, DCC_CFG); + + for (i = 0; i < DCC_MAX_LINK_LIST; i++) { + + if (dcc_valid_list(drvdata, i)) + continue; + + dcc_writel(drvdata, BIT(0), DCC_LL_LOCK(i)); + dcc_writel(drvdata, state->dcc_ll_base[i], DCC_LL_BASE(i)); + dcc_writel(drvdata, state->dcc_fd_base[i], DCC_FD_BASE(i)); + dcc_writel(drvdata, state->dcc_ll_timeout[i], + DCC_LL_TIMEOUT(i)); + dcc_writel(drvdata, state->dcc_ll_int_enable[i], + DCC_LL_INT_ENABLE(i)); + dcc_writel(drvdata, state->dcc_ll_int_status[i], + DCC_LL_INT_STATUS(i)); + /* Make sure all config is written in sram */ + mb(); + dcc_writel(drvdata, state->dcc_ll_cfg[i], DCC_LL_CFG(i)); + } + + mutex_unlock(&drvdata->mutex); + + if (drvdata->enable[drvdata->curr_list]) + drvdata->enable[drvdata->curr_list] = 1; + + kfree(drvdata->sram_save_state); + kfree(drvdata->reg_save_state); + + return 0; +} + +static int dcc_v2_thaw(struct device *dev) +{ + struct dcc_drvdata *drvdata = dev_get_drvdata(dev); + + if (!drvdata) + return -EINVAL; + + if (drvdata->enable[drvdata->curr_list]) + drvdata->enable[drvdata->curr_list] = 1; + + kfree(drvdata->sram_save_state); + kfree(drvdata->reg_save_state); + + return 0; +} + +static const struct dev_pm_ops dcc_v2_pm_ops = { + .freeze = dcc_v2_freeze, + .restore = dcc_v2_restore, + .thaw = dcc_v2_thaw, +}; + static const struct of_device_id msm_dcc_match[] = { { .compatible = "qcom,dcc-v2"}, {} @@ -1854,6 +2002,7 @@ static struct platform_driver dcc_driver = { .driver = { .name = "msm-dcc", .owner = THIS_MODULE, + .pm = &dcc_v2_pm_ops, .of_match_table = msm_dcc_match, }, }; -- GitLab From 0a7ac54ace2b4e9d6281702b3cae59e15097837b Mon Sep 17 00:00:00 2001 From: Venkata Rao Kakani Date: Mon, 8 Jun 2020 18:35:06 +0530 Subject: [PATCH 0931/1055] Early Services: init: fs: synchronize Early Services with init Add synchonization between early-init and android init. Change-Id: I347645c648964252b80182eb4328859e4a94d7eb Signed-off-by: Venkata Rao Kakani --- fs/filesystems.c | 19 +++++++++++++++++ include/linux/fs.h | 1 + include/linux/init.h | 5 ++++- init/do_mounts.c | 51 +++++++++++++++++++++++++++++++++++--------- init/main.c | 14 +++++++++++- 5 files changed, 78 insertions(+), 12 deletions(-) diff --git a/fs/filesystems.c b/fs/filesystems.c index f2728a4a03a1..931925d6aeed 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -221,6 +221,25 @@ int __init get_filesystem_list(char *buf) return len; } +#ifdef CONFIG_EARLY_SERVICES +int get_filesystem_list_runtime(char *buf) +{ + int len = 0; + struct file_system_type *tmp; + + read_lock(&file_systems_lock); + tmp = file_systems; + while (tmp && len < PAGE_SIZE - 80) { + len += scnprintf(buf+len, PAGE_SIZE, "%s\t%s\n", + (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev", + tmp->name); + tmp = tmp->next; + } + read_unlock(&file_systems_lock); + return len; +} +#endif + #ifdef CONFIG_PROC_FS static int filesystems_proc_show(struct seq_file *m, void *v) { diff --git a/include/linux/fs.h b/include/linux/fs.h index a9556d1115ef..9948a8fdde3f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3357,6 +3357,7 @@ int proc_nr_dentry(struct ctl_table *table, int write, int proc_nr_inodes(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); int __init get_filesystem_list(char *buf); +int get_filesystem_list_runtime(char *buf); #define __FMODE_EXEC ((__force int) FMODE_EXEC) #define __FMODE_NONOTIFY ((__force int) FMODE_NONOTIFY) diff --git a/include/linux/init.h b/include/linux/init.h index f00665ba66fc..a55e03e9703b 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -133,7 +133,10 @@ extern unsigned int reset_devices; /* used by init/main.c */ void setup_arch(char **); void prepare_namespace(void); -void __init launch_early_services(void); +void launch_early_services(void); +#ifdef CONFIG_EARLY_SERVICES +int get_early_services_status(void); +#endif void __init load_default_modules(void); int __init init_rootfs(void); diff --git a/init/do_mounts.c b/init/do_mounts.c index fa23cf487f4e..f1645f4ece5e 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -43,10 +43,11 @@ static char * __initdata root_device_name; static char __initdata saved_root_name[64]; static int root_wait; #ifdef CONFIG_EARLY_SERVICES -static char saved_modem_name[64] __initdata; -static char saved_early_userspace[64] __initdata; +static char saved_modem_name[64]; +static char saved_early_userspace[64]; static char init_prog[128] = "/early_services/init_early"; static char *init_prog_argv[2] = { init_prog, NULL }; +static int es_status; /*1= es mount is success 0= es failed to run*/ #define EARLY_SERVICES_MOUNT_POINT "/early_services" #endif dev_t ROOT_DEV; @@ -383,6 +384,26 @@ static void __init get_fs_names(char *page) *s = '\0'; } +#ifdef CONFIG_EARLY_SERVICES +static void get_fs_names_runtime(char *page) +{ + char *s = page; + int len = get_filesystem_list_runtime(page); + char *p, *next; + + page[len] = '\0'; + + for (p = page-1; p; p = next) { + next = strnchr(++p, len, '\n'); + if (*p++ != '\t') + continue; + while ((*s++ = *p++) != '\n') + ; + s[-1] = '\0'; + } + *s = '\0'; +} +#endif static int __init do_mount_root(char *name, char *fs, int flags, void *data) { struct super_block *s; @@ -410,7 +431,7 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data) return 0; } #ifdef CONFIG_EARLY_SERVICES -static int __init do_mount_part(char *name, char *fs, int flags, +static int do_mount_part(char *name, char *fs, int flags, void *data, char *mnt_point) { int err; @@ -590,14 +611,24 @@ void __init mount_root(void) } #ifdef CONFIG_EARLY_SERVICES -static int __init mount_partition(char *part_name, char *mnt_point) +int get_early_services_status(void) +{ + return es_status; +} + +static int mount_partition(char *part_name, char *mnt_point) { struct page *page = alloc_page(GFP_KERNEL); char *fs_names = page_address(page); char *p; int err = -EPERM; - get_fs_names(fs_names); + if (!part_name[0]) { + pr_err("Unknown partition\n"); + return -ENOENT; + } + + get_fs_names_runtime(fs_names); for (p = fs_names; *p; p += strlen(p)+1) { err = do_mount_part(part_name, p, root_mountflags, NULL, mnt_point); @@ -608,12 +639,11 @@ static int __init mount_partition(char *part_name, char *mnt_point) case -EINVAL: continue; } - printk_all_partitions(); return err; } return err; } -void __init launch_early_services(void) +void launch_early_services(void) { int rc = 0; @@ -622,14 +652,15 @@ void __init launch_early_services(void) if (!rc) { place_marker("Early Services Partition ready"); rc = call_usermodehelper(init_prog, init_prog_argv, NULL, 0); - if (!rc) + if (!rc) { + es_status = 1; pr_info("early_init launched\n"); - else + } else pr_err("early_init failed\n"); } } #else -void __init launch_early_services(void) { } +void launch_early_services(void) { } #endif /* * Prepare the namespace - decide what/where to mount, load ramdisks, etc. diff --git a/init/main.c b/init/main.c index aed0801c3197..22f1c5b9e8e5 100644 --- a/init/main.c +++ b/init/main.c @@ -96,6 +96,8 @@ #include #include +#include "do_mounts.h" + static int kernel_init(void *); extern void init_IRQ(void); @@ -1019,7 +1021,9 @@ static inline void mark_readonly(void) static int __ref kernel_init(void *unused) { int ret; - +#ifdef CONFIG_EARLY_SERVICES + int status = get_early_services_status(); +#endif kernel_init_freeable(); /* need to finish all async __init code before freeing the memory */ async_synchronize_full(); @@ -1032,6 +1036,14 @@ static int __ref kernel_init(void *unused) rcu_end_inkernel_boot(); place_marker("M - DRIVER Kernel Boot Done"); +#ifdef CONFIG_EARLY_SERVICES + if (status) { + struct kstat stat; + /* Wait for early services SE policy load completion signal */ + while (vfs_stat("/dev/sedone", &stat) != 0) + ; + } +#endif if (ramdisk_execute_command) { ret = run_init_process(ramdisk_execute_command); if (!ret) -- GitLab From 03d895716d85acfe25536e85cf80f703e2009cbd Mon Sep 17 00:00:00 2001 From: Gopala Krishna Nuthaki Date: Fri, 26 Jun 2020 12:15:24 +0530 Subject: [PATCH 0932/1055] drivers: thermal: Re-initialize TSENS controller interrupt configuration If TSENS controller goes to bad state while reading temperature, it invokes TSENS controller re-init code.After controller re-init,it disable all interrupts and reset TSENS critical interrupt related settings. It causes no threshold interrupt or critical interrupt on post controller re-init and it might lead to thermal run away issues. Re-initialize TSENS controller interrupt configuration to enable threshold interrupts and critical interrupt as part of TSENS controller re-init routine. Change-Id: I84b1218ce90ce8e4ae530f93db7c2b4277469781 Signed-off-by: Gopala Krishna Nuthaki --- drivers/thermal/tsens2xxx.c | 122 +++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 52 deletions(-) diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c index 29aca6f3d2d8..209ba04bcc8c 100644 --- a/drivers/thermal/tsens2xxx.c +++ b/drivers/thermal/tsens2xxx.c @@ -83,12 +83,70 @@ static void msm_tsens_convert_temp(int last_temp, int *temp) *temp = last_temp * TSENS_TM_SCALE_DECI_MILLIDEG; } +static int __tsens2xxx_hw_init(struct tsens_device *tmdev) +{ + void __iomem *srot_addr; + void __iomem *sensor_int_mask_addr; + unsigned int srot_val, crit_mask, crit_val; + void __iomem *int_mask_addr; + + srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4); + srot_val = readl_relaxed(srot_addr); + if (!(srot_val & TSENS_EN)) { + pr_err("TSENS device is not enabled\n"); + return -ENODEV; + } + + if (tmdev->ctrl_data->cycle_monitor) { + sensor_int_mask_addr = + TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr); + crit_mask = readl_relaxed(sensor_int_mask_addr); + crit_val = TSENS_TM_CRITICAL_CYCLE_MONITOR; + if (tmdev->ctrl_data->cycle_compltn_monitor_mask) + writel_relaxed((crit_mask | crit_val), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_tm_addr))); + else + writel_relaxed((crit_mask & ~crit_val), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_tm_addr))); + /*Update critical cycle monitoring*/ + mb(); + } + + if (tmdev->ctrl_data->wd_bark) { + sensor_int_mask_addr = + TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr); + crit_mask = readl_relaxed(sensor_int_mask_addr); + crit_val = TSENS_TM_CRITICAL_WD_BARK; + if (tmdev->ctrl_data->wd_bark_mask) + writel_relaxed((crit_mask | crit_val), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_tm_addr))); + else + writel_relaxed((crit_mask & ~crit_val), + (TSENS_TM_CRITICAL_INT_MASK + (tmdev->tsens_tm_addr))); + /*Update watchdog monitoring*/ + mb(); + } + + int_mask_addr = TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_tm_addr); + writel_relaxed(TSENS_TM_UPPER_LOWER_INT_DISABLE, int_mask_addr); + + writel_relaxed(TSENS_TM_CRITICAL_INT_EN | + TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN, + TSENS_TM_INT_EN(tmdev->tsens_tm_addr)); + + return 0; +} + static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp) { struct tsens_device *tmdev = NULL, *tmdev_itr; unsigned int code, ret, tsens_ret; void __iomem *sensor_addr, *trdy; - int last_temp = 0, last_temp2 = 0, last_temp3 = 0, count = 0; + int rc = 0, last_temp = 0, last_temp2 = 0, last_temp3 = 0, count = 0; static atomic_t in_tsens_reinit; if (!sensor) @@ -173,6 +231,13 @@ static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp) /* Notify thermal fwk */ list_for_each_entry(tmdev_itr, &tsens_device_list, list) { + rc = __tsens2xxx_hw_init(tmdev_itr); + if (rc) { + pr_err( + "%s: Failed to re-initialize TSENS controller\n", + __func__); + BUG(); + } queue_work(tmdev_itr->tsens_reinit_work, &tmdev_itr->therm_fwk_notify); } @@ -620,58 +685,11 @@ static int tsens2xxx_hw_sensor_en(struct tsens_device *tmdev, static int tsens2xxx_hw_init(struct tsens_device *tmdev) { - void __iomem *srot_addr; - void __iomem *sensor_int_mask_addr; - unsigned int srot_val, crit_mask, crit_val; - void __iomem *int_mask_addr; - - srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr + 0x4); - srot_val = readl_relaxed(srot_addr); - if (!(srot_val & TSENS_EN)) { - pr_err("TSENS device is not enabled\n"); - return -ENODEV; - } - - if (tmdev->ctrl_data->cycle_monitor) { - sensor_int_mask_addr = - TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr); - crit_mask = readl_relaxed(sensor_int_mask_addr); - crit_val = TSENS_TM_CRITICAL_CYCLE_MONITOR; - if (tmdev->ctrl_data->cycle_compltn_monitor_mask) - writel_relaxed((crit_mask | crit_val), - (TSENS_TM_CRITICAL_INT_MASK - (tmdev->tsens_tm_addr))); - else - writel_relaxed((crit_mask & ~crit_val), - (TSENS_TM_CRITICAL_INT_MASK - (tmdev->tsens_tm_addr))); - /*Update critical cycle monitoring*/ - mb(); - } - - if (tmdev->ctrl_data->wd_bark) { - sensor_int_mask_addr = - TSENS_TM_CRITICAL_INT_MASK(tmdev->tsens_tm_addr); - crit_mask = readl_relaxed(sensor_int_mask_addr); - crit_val = TSENS_TM_CRITICAL_WD_BARK; - if (tmdev->ctrl_data->wd_bark_mask) - writel_relaxed((crit_mask | crit_val), - (TSENS_TM_CRITICAL_INT_MASK - (tmdev->tsens_tm_addr))); - else - writel_relaxed((crit_mask & ~crit_val), - (TSENS_TM_CRITICAL_INT_MASK - (tmdev->tsens_tm_addr))); - /*Update watchdog monitoring*/ - mb(); - } - - int_mask_addr = TSENS_TM_UPPER_LOWER_INT_MASK(tmdev->tsens_tm_addr); - writel_relaxed(TSENS_TM_UPPER_LOWER_INT_DISABLE, int_mask_addr); + int rc = 0; - writel_relaxed(TSENS_TM_CRITICAL_INT_EN | - TSENS_TM_UPPER_INT_EN | TSENS_TM_LOWER_INT_EN, - TSENS_TM_INT_EN(tmdev->tsens_tm_addr)); + rc = __tsens2xxx_hw_init(tmdev); + if (rc) + return rc; spin_lock_init(&tmdev->tsens_crit_lock); spin_lock_init(&tmdev->tsens_upp_low_lock); -- GitLab From 39174fe35f802031b03e3c933d8cbc7b4c4e83ec Mon Sep 17 00:00:00 2001 From: "Gautham R. Shenoy" Date: Tue, 7 Nov 2017 13:39:29 +0530 Subject: [PATCH 0933/1055] cpufreq: stats: Handle the case when trans_table goes beyond PAGE_SIZE On platforms with large number of Pstates, the transition table, which is a NxN matrix, can overflow beyond the PAGE_SIZE boundary. This can be seen on POWER9 which has 100+ Pstates. As a result, each time the trans_table is read for any of the CPUs, we will get the following error. --------------------------------------------------- fill_read_buffer: show+0x0/0xa0 returned bad count --------------------------------------------------- This patch ensures that in case of an overflow, we print a warning once in the dmesg and return FILE TOO LARGE error for this and all subsequent accesses of trans_table. Change-Id: I4d22a81fcad037e887b4ddf2999904b321401441 Signed-off-by: Gautham R. Shenoy Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki Git-repo: https://android.googlesource.com/kernel/common/ Git-commit: f7bc9b209e27c0b617378400136cc663a6314d0c Signed-off-by: Rahul Shahare --- Documentation/cpu-freq/cpufreq-stats.txt | 3 +++ drivers/cpufreq/cpufreq_stats.c | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/cpu-freq/cpufreq-stats.txt b/Documentation/cpu-freq/cpufreq-stats.txt index 2bbe207354ed..a873855c811d 100644 --- a/Documentation/cpu-freq/cpufreq-stats.txt +++ b/Documentation/cpu-freq/cpufreq-stats.txt @@ -90,6 +90,9 @@ Freq_i to Freq_j. Freq_i is in descending order with increasing rows and Freq_j is in descending order with increasing columns. The output here also contains the actual freq values for each row and column for better readability. +If the transition table is bigger than PAGE_SIZE, reading this will +return an -EFBIG error. + -------------------------------------------------------------------------------- :/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table From : To diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 16d123001b5c..0e361b66a669 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -113,8 +113,11 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) break; len += snprintf(buf + len, PAGE_SIZE - len, "\n"); } - if (len >= PAGE_SIZE) - return PAGE_SIZE; + + if (len >= PAGE_SIZE) { + pr_warn_once("cpufreq transition table exceeds PAGE_SIZE. Disabling\n"); + return -EFBIG; + } return len; } cpufreq_freq_attr_ro(trans_table); -- GitLab From 5271c8ae25d42eedb8d0174c2df7d4a612ef501b Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 4 Jan 2018 08:53:54 +0530 Subject: [PATCH 0934/1055] cpufreq: stats: Change return type of cpufreq_stats_update() as void It always returns 0 and none of its callers check its return value. Make it return void. Change-Id: I1fca4f037bac103602c43c05b0bab4a518469160 Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki Git-repo: https://android.googlesource.com/kernel/common/ Git-commit: d476ec4f7f5aba47b0a570cbf659d7330d7e71c Signed-off-by: Rahul Shahare --- drivers/cpufreq/cpufreq_stats.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 16d123001b5c..ca91481e63cd 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -27,7 +27,7 @@ struct cpufreq_stats { unsigned int *trans_table; }; -static int cpufreq_stats_update(struct cpufreq_stats *stats) +static void cpufreq_stats_update(struct cpufreq_stats *stats) { unsigned long long cur_time = get_jiffies_64(); unsigned long flags; @@ -36,7 +36,6 @@ static int cpufreq_stats_update(struct cpufreq_stats *stats) stats->time_in_state[stats->last_index] += cur_time - stats->last_time; stats->last_time = cur_time; spin_unlock_irqrestore(&cpufreq_stats_lock, flags); - return 0; } static void cpufreq_stats_clear_table(struct cpufreq_stats *stats) -- GitLab From 8bae2033ccfcf922873fc47d3bb970f0ebdda920 Mon Sep 17 00:00:00 2001 From: Vipin Deep Kaur Date: Mon, 18 May 2020 12:54:47 +0530 Subject: [PATCH 0935/1055] spi: spi-geni-qcom: Reset the dma engine on failure On a DMA transfer timeout failure, reset the TX/RX DMA engines to avoid any SMMU fault caused as a consequence of the DMA engine getting restarted and trying to access the unmapped buffer addresses. Change-Id: Ic2f637b3a90dc63a27d2b2f53442ac071a56337c Signed-off-by: Vipin Deep Kaur --- drivers/spi/spi-geni-qcom.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 27aebbc4d5c4..c7c4ddaa6754 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -1226,12 +1226,30 @@ static void handle_fifo_timeout(struct spi_master *spi, } dma_unprep: if (mas->cur_xfer_mode == SE_DMA) { - if (xfer->tx_buf) + if (xfer->tx_buf) { + reinit_completion(&mas->xfer_done); + writel_relaxed(1, mas->base + + SE_DMA_TX_FSM_RST); + timeout = + wait_for_completion_timeout(&mas->xfer_done, HZ); + if (!timeout) + dev_err(mas->dev, + "DMA TX RESET failed\n"); geni_se_tx_dma_unprep(mas->wrapper_dev, - xfer->tx_dma, xfer->len); - if (xfer->rx_buf) + xfer->tx_dma, xfer->len); + } + if (xfer->rx_buf) { + reinit_completion(&mas->xfer_done); + writel_relaxed(1, mas->base + + SE_DMA_RX_FSM_RST); + timeout = + wait_for_completion_timeout(&mas->xfer_done, HZ); + if (!timeout) + dev_err(mas->dev, + "DMA RX RESET failed\n"); geni_se_rx_dma_unprep(mas->wrapper_dev, - xfer->rx_dma, xfer->len); + xfer->rx_dma, xfer->len); + } } if (spi->slave && !mas->dis_autosuspend) pm_runtime_put_sync_suspend(mas->dev); -- GitLab From e9debf86483409a99eff0bd046e518c2d176e8d7 Mon Sep 17 00:00:00 2001 From: Vipin Deep Kaur Date: Fri, 22 May 2020 19:04:20 +0530 Subject: [PATCH 0936/1055] spi: spi-geni-qcom: Check for zero length transfer A new reported scenario in whch spi slave is able to send data into RX fifo though spi master schedules a rx transfer of 0 byte. This is a workaround to reject the zeo length rx transfers from software side till issue is debugged from HW side. Change-Id: I975d8a6aa6720a9b9a98345f37505e8c4e40e451 Signed-off-by: Vipin Deep Kaur --- drivers/spi/spi-geni-qcom.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 27aebbc4d5c4..9fb327bcd417 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -1257,6 +1257,12 @@ static int spi_geni_transfer_one(struct spi_master *spi, return -EINVAL; } + /* Check for zero length transfer */ + if (xfer->len < 1) { + dev_err(mas->dev, "Zero length transfer\n"); + return -EINVAL; + } + if (mas->cur_xfer_mode != GSI_DMA) { reinit_completion(&mas->xfer_done); setup_fifo_xfer(xfer, mas, slv->mode, spi); -- GitLab From 11e601043d294377db6c9572d01aa66170d7238d Mon Sep 17 00:00:00 2001 From: Jeya R Date: Tue, 23 Jun 2020 21:32:18 +0530 Subject: [PATCH 0937/1055] msm: set config for ADSPRPC and add dtsi node Set config for ADSPRPC and add dtsi node related to fastrpc. Add backward compatibility in adsprpc driver code to probe legacy dtsi entries. Change-Id: Ibadfb3031ea491c8782c78d351d93f7dd45ad755 Signed-off-by: Jeya R --- .../configs/vendor/sdm429-bg-perf_defconfig | 1 + arch/arm/configs/vendor/sdm429-bg_defconfig | 1 + arch/arm64/boot/dts/qcom/sdm429.dtsi | 16 ++++ drivers/char/Kconfig | 2 +- drivers/char/adsprpc.c | 92 ++++++++++++++++++- 5 files changed, 110 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig index 5cc7ceccabe6..bbb2fd33d4b7 100644 --- a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig @@ -331,6 +331,7 @@ CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_SMD_PKT=y CONFIG_DIAG_CHAR=y +CONFIG_MSM_ADSPRPC=y CONFIG_MSM_RDBG=m CONFIG_I2C_CHARDEV=y CONFIG_I2C_MSM_V2=y diff --git a/arch/arm/configs/vendor/sdm429-bg_defconfig b/arch/arm/configs/vendor/sdm429-bg_defconfig index 1260c94b7cf8..be3c1cb8ed7b 100644 --- a/arch/arm/configs/vendor/sdm429-bg_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg_defconfig @@ -342,6 +342,7 @@ CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_SMD_PKT=y CONFIG_DIAG_CHAR=y +CONFIG_MSM_ADSPRPC=y CONFIG_MSM_RDBG=m CONFIG_I2C_CHARDEV=y CONFIG_I2C_MSM_V2=y diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 0391e6bcacd4..312466d1880d 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -783,6 +783,22 @@ }; }; + qcom,adsprpc-mem { + compatible = "qcom,msm-adsprpc-mem-region"; + memory-region = <&adsp_mem>; + restrict-access; + }; + + qcom,msm_fastrpc { + compatible ="qcom,msm-fastrpc-legacy-compute"; + qcom,msm_fastrpc_compute_cb1 { + compatible = "qcom,msm-fastrpc-legacy-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_iommu 0x2008 0x7>; + sids = <0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf>; + }; + }; + wcnss-smp2p { compatible = "qcom,smp2p"; qcom,smem = <451>, <431>; diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index e92667284635..b92228b9851d 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -609,7 +609,7 @@ config MSM_FASTCVPD config MSM_ADSPRPC tristate "QTI ADSP RPC driver" - depends on QCOM_GLINK + depends on QCOM_GLINK || RPMSG_QCOM_SMD help Provides a communication mechanism that allows for clients to make remote method invocations across processor boundary to diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index c3823ec9bf85..8ed94351e897 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -4002,6 +4002,92 @@ static int fastrpc_cb_probe(struct device *dev) return err; } + +static int fastrpc_cb_legacy_probe(struct device *dev) +{ + struct fastrpc_channel_ctx *chan; + struct fastrpc_session_ctx *first_sess = NULL, *sess = NULL; + const char *name; + unsigned int *sids = NULL, sids_size = 0; + int err = 0, ret = 0, i; + + unsigned int start = 0x80000000; + + VERIFY(err, NULL != (name = of_get_property(dev->of_node, + "label", NULL))); + if (err) + goto bail; + + for (i = 0; i < NUM_CHANNELS; i++) { + if (!gcinfo[i].name) + continue; + if (!strcmp(name, gcinfo[i].name)) + break; + } + VERIFY(err, i < NUM_CHANNELS); + if (err) + goto bail; + + chan = &gcinfo[i]; + VERIFY(err, chan->sesscount < NUM_SESSIONS); + if (err) + goto bail; + + first_sess = &chan->session[chan->sesscount]; + + VERIFY(err, NULL != of_get_property(dev->of_node, + "sids", &sids_size)); + if (err) + goto bail; + + VERIFY(err, NULL != (sids = kzalloc(sids_size, GFP_KERNEL))); + if (err) + goto bail; + ret = of_property_read_u32_array(dev->of_node, "sids", sids, + sids_size/sizeof(unsigned int)); + if (ret) + goto bail; + + VERIFY(err, !IS_ERR_OR_NULL(first_sess->smmu.mapping = + arm_iommu_create_mapping(&platform_bus_type, + start, 0x78000000))); + if (err) + goto bail; + + VERIFY(err, !arm_iommu_attach_device(dev, first_sess->smmu.mapping)); + if (err) { + pr_err("adsprpc: %s: attaching iommu device failed for %s with err %d", + __func__, dev_name(dev), err); + goto bail; + } + + + for (i = 0; i < sids_size/sizeof(unsigned int); i++) { + VERIFY(err, chan->sesscount < NUM_SESSIONS); + if (err) + goto bail; + sess = &chan->session[chan->sesscount]; + sess->smmu.cb = sids[i]; + sess->smmu.dev = dev; + sess->smmu.dev_name = dev_name(dev); + sess->smmu.mapping = first_sess->smmu.mapping; + sess->smmu.enabled = 1; + sess->used = 0; + sess->smmu.coherent = false; + sess->smmu.secure = false; + chan->sesscount++; + if (!sess->smmu.dev->dma_parms) + sess->smmu.dev->dma_parms = devm_kzalloc(sess->smmu.dev, + sizeof(*sess->smmu.dev->dma_parms), GFP_KERNEL); + dma_set_max_seg_size(sess->smmu.dev, DMA_BIT_MASK(32)); + dma_set_seg_boundary(sess->smmu.dev, + (unsigned long)DMA_BIT_MASK(64)); + } +bail: + kfree(sids); + return err; +} + static void init_secure_vmid_list(struct device *dev, char *prop_name, struct secure_vm *destvm) { @@ -4097,6 +4183,10 @@ static int fastrpc_probe(struct platform_device *pdev) "qcom,msm-fastrpc-compute-cb")) return fastrpc_cb_probe(dev); + if (of_device_is_compatible(dev->of_node, + "qcom,msm-fastrpc-legacy-compute-cb")) + return fastrpc_cb_legacy_probe(dev); + if (of_device_is_compatible(dev->of_node, "qcom,msm-adsprpc-mem-region")) { me->dev = dev; @@ -4291,7 +4381,7 @@ static struct platform_driver fastrpc_driver = { static const struct rpmsg_device_id fastrpc_rpmsg_match[] = { { FASTRPC_GLINK_GUID }, - { }, + { FASTRPC_SMD_GUID }, }; static const struct of_device_id fastrpc_rpmsg_of_match[] = { -- GitLab From 1cfdc30c3fb0c87a8a27facad7de474897fde2d0 Mon Sep 17 00:00:00 2001 From: Gopala Krishna Nuthaki Date: Fri, 26 Jun 2020 12:02:03 +0530 Subject: [PATCH 0938/1055] drivers: thermal: Force notify thermal to re-evaluate TSENS sensors If TSENS controller went to bad state while reading temperature of a sensor, TSENS invokes controller re-init code for all controller and then notifies the thermal framework to re-evaluate thermal for each sensor.But there is a chance that current notification API can bail out without re-evaluating the thermal zone if none of the trips are violated. Notify the thermal framework with proper notification API to force re-evaluate thermal zone and make sure that all sensors are re-enabled next active trips. Change-Id: I0686fabba1ee17de1e859e6fcd3b0af7f40c8e73 Signed-off-by: Gopala Krishna Nuthaki --- drivers/thermal/msm-tsens.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c index 7db6a4b9aa2d..fc50f2b684eb 100644 --- a/drivers/thermal/msm-tsens.c +++ b/drivers/thermal/msm-tsens.c @@ -253,7 +253,7 @@ static void tsens_therm_fwk_notify(struct work_struct *work) } TSENS_DBG(tmdev, "Calling trip_temp for sensor %d\n", i); - of_thermal_handle_trip_temp(tmdev->sensor[i].tzd, temp); + of_thermal_handle_trip(tmdev->sensor[i].tzd); } } } -- GitLab From dfb13a1639bb9f3d457dc273445bb13978ec8f35 Mon Sep 17 00:00:00 2001 From: Vishwanath Raju K Date: Sat, 27 Jun 2020 13:18:14 +0530 Subject: [PATCH 0939/1055] ARM: dts: msm: Disable the secure mem region for SDM429 Secure Video and secure GFX use case occupies ~100MB memory. On low memory devices this have drastic on impact page frame reclaim, so disable secure CMA on SDM429 and enable on specific targets only when requested. Change-Id: I0629afeb6ca52a714b38c4e959609b8490311249 Signed-off-by: Sunil Khatri Signed-off-by: Vishwanath Raju K --- arch/arm64/boot/dts/qcom/sdm429-ion.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429-ion.dtsi b/arch/arm64/boot/dts/qcom/sdm429-ion.dtsi index 9456915bb884..7d41a0a14982 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-ion.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-ion.dtsi @@ -23,6 +23,7 @@ }; qcom,ion-heap@8 { /* CP_MM HEAP */ + status = "disabled"; reg = <8>; memory-region = <&secure_mem>; qcom,ion-heap-type = "SECURE_DMA"; -- GitLab From 9c27858d90d2224765eeca2acb1f9268e9cbfb00 Mon Sep 17 00:00:00 2001 From: Vishwanath Raju K Date: Wed, 17 Jun 2020 02:37:40 +0530 Subject: [PATCH 0940/1055] ARM: dts: msm: enable smmu for sdm429 Enabled apps smmu and kgsl smmu for sdm429. Change-Id: I10d518e858ccbff1f6bfd7ee8c4bc0b3a782235e Signed-off-by: Vishwanath Raju K --- arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm429.dtsi | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm429.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm429.dtsi index f722c473bd27..7851eb3cdfee 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm429.dtsi @@ -14,7 +14,7 @@ &soc { kgsl_smmu: arm,smmu-kgsl@1c40000 { - status = "disabled"; + status = "ok"; compatible = "qcom,smmu-v2"; qcom,tz-device-id = "GPU"; reg = <0x1c40000 0x10000>; @@ -26,8 +26,9 @@ ; qcom,dynamic; qcom,use-3-lvl-tables; - qcom,enable-smmu-halt; qcom,skip-init; + qcom,deferred-regulator-disable-delay = <80>; + qcom,enable-static-cb; vdd-supply = <&oxili_cx_gdsc>; qcom,regulator-names = "vdd"; clocks = <&gcc GCC_OXILI_AHB_CLK>, @@ -46,7 +47,7 @@ }; apps_iommu: qcom,iommu@1e00000 { - status = "disabled"; + status = "ok"; compatible = "qcom,qsmmu-v500"; reg = <0x1e00000 0x40000>, <0x1ee2000 0x20>; -- GitLab From a631906b441f07654598b3e72aaf93c5ee1d855a Mon Sep 17 00:00:00 2001 From: Vishwanath Raju K Date: Sat, 27 Jun 2020 16:33:01 +0530 Subject: [PATCH 0941/1055] ARM: msm: Hardware name correction for SDM429W Corrected board config hardware name for SDM429W. Change-Id: Ib0ce42cfc894c34afe5aa5a78a377aa8200c25f7 Signed-off-by: Vishwanath Raju K --- arch/arm/mach-qcom/board-sdm429w.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-qcom/board-sdm429w.c b/arch/arm/mach-qcom/board-sdm429w.c index 7fd0ea6e62f0..22a5fe6e5613 100644 --- a/arch/arm/mach-qcom/board-sdm429w.c +++ b/arch/arm/mach-qcom/board-sdm429w.c @@ -29,7 +29,7 @@ static void __init sdm429w_init(void) } DT_MACHINE_START(SDM429W_DT, - "Qualcomm Technologies, Inc. QCS403 (Flattened Device Tree)") + "Qualcomm Technologies, Inc. SDM429W (Flattened Device Tree)") .init_machine = sdm429w_init, .dt_compat = sdm429w_dt_match, MACHINE_END -- GitLab From 30f7edaa2728b14ef954f2ceb51ef0871395e94e Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Sat, 27 Jun 2020 17:11:32 +0530 Subject: [PATCH 0942/1055] ARM: dts: msm: Add support for various subtype of IDP board for QCM/S6125 Adding and enabling support for various subtype of IDP board to boot with IOT specific QCM6125 and QCS6125 SOC's. Change-Id: I796311f8ac9589fa5a62b0c90fcd89c07dc730b9 Signed-off-by: Avaneesh Kumar Dwivedi --- .../devicetree/bindings/arm/msm/msm.txt | 2 + arch/arm64/boot/dts/qcom/Makefile | 28 +++++++++- .../dts/qcom/qcm6125-iot-dp-idp-overlay.dts | 51 +++++++++++++++++++ .../boot/dts/qcom/qcm6125-iot-dp-idp.dts | 44 ++++++++++++++++ ...qcm6125-iot-external-codec-idp-overlay.dts | 31 +++++++++++ .../qcom/qcm6125-iot-external-codec-idp.dts | 24 +++++++++ ...25-iot-usbc-external-codec-idp-overlay.dts | 29 +++++++++++ .../qcm6125-iot-usbc-external-codec-idp.dts | 22 ++++++++ .../dts/qcom/qcm6125-iot-usbc-idp-overlay.dts | 30 +++++++++++ .../boot/dts/qcom/qcm6125-iot-usbc-idp.dts | 23 +++++++++ .../boot/dts/qcom/qcm6125-iot-usbc-idp.dtsi | 19 +++++++ .../dts/qcom/qcs6125-iot-dp-idp-overlay.dts | 51 +++++++++++++++++++ .../boot/dts/qcom/qcs6125-iot-dp-idp.dts | 44 ++++++++++++++++ ...qcs6125-iot-external-codec-idp-overlay.dts | 31 +++++++++++ .../qcom/qcs6125-iot-external-codec-idp.dts | 24 +++++++++ ...25-iot-usbc-external-codec-idp-overlay.dts | 29 +++++++++++ .../qcs6125-iot-usbc-external-codec-idp.dts | 22 ++++++++ .../dts/qcom/qcs6125-iot-usbc-idp-overlay.dts | 30 +++++++++++ .../boot/dts/qcom/qcs6125-iot-usbc-idp.dts | 23 +++++++++ .../boot/dts/qcom/qcs6125-iot-usbc-idp.dtsi | 19 +++++++ 20 files changed, 574 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp.dts create mode 100644 arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp.dts create mode 100644 arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp.dts create mode 100644 arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dts create mode 100644 arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dtsi create mode 100644 arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp.dts create mode 100644 arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp.dts create mode 100644 arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp.dts create mode 100644 arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dts create mode 100644 arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dtsi diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 76026a75d0cf..2f70a74ddd54 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -307,3 +307,5 @@ compatible = "qcom,sdm429w-wdp" compatible = "qcom,sdm429-wdp" compatible = "qcom,qcm6125" compatible = "qcom,qcs6125" +compatible = "qcom,qcm6125-idp" +compatible = "qcom,qcs6125-idp" diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index fdaf15bda642..5ab6d3af953e 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -321,7 +321,15 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) trinket-usbc-idp-overlay.dtbo \ trinket-dp-idp-overlay.dtbo \ qcm6125-iot-idp-overlay.dtbo \ - qcs6125-iot-idp-overlay.dtbo + qcs6125-iot-idp-overlay.dtbo \ + qcm6125-iot-external-codec-idp-overlay.dtbo \ + qcs6125-iot-external-codec-idp-overlay.dtbo \ + qcm6125-iot-usbc-external-codec-idp-overlay.dtbo \ + qcs6125-iot-usbc-external-codec-idp-overlay.dtbo \ + qcm6125-iot-usbc-idp-overlay.dtbo \ + qcs6125-iot-usbc-idp-overlay.dtbo \ + qcm6125-iot-dp-idp-overlay.dtbo \ + qcs6125-iot-dp-idp-overlay.dtbo trinket-rumi-overlay.dtbo-base := trinket.dtb trinket-idp-overlay.dtbo-base := trinket.dtb @@ -332,6 +340,14 @@ trinket-usbc-idp-overlay.dtbo-base := trinket.dtb trinket-dp-idp-overlay.dtbo-base := trinket.dtb qcm6125-iot-idp-overlay.dtbo-base := qcm6125.dtb qcs6125-iot-idp-overlay.dtbo-base := qcs6125.dtb +qcm6125-iot-external-codec-idp-overlay.dtbo-base := qcm6125.dtb +qcs6125-iot-external-codec-idp-overlay.dtbo-base := qcs6125.dtb +qcm6125-iot-usbc-external-codec-idp-overlay.dtbo-base := qcm6125.dtb +qcs6125-iot-usbc-external-codec-idp-overlay.dtbo-base := qcs6125.dtb +qcm6125-iot-usbc-idp-overlay.dtbo-base := qcm6125.dtb +qcs6125-iot-usbc-idp-overlay.dtbo-base := qcs6125.dtb +qcm6125-iot-dp-idp-overlay.dtbo-base := qcm6125.dtb +qcs6125-iot-dp-idp-overlay.dtbo-base := qcs6125.dtb else dtb-$(CONFIG_ARCH_TRINKET) += trinket-rumi.dtb \ trinket-idp.dtb \ @@ -341,7 +357,15 @@ dtb-$(CONFIG_ARCH_TRINKET) += trinket-rumi.dtb \ trinket-usbc-idp.dtb \ trinket-dp-idp.dtb \ qcm6125-iot-idp.dtb \ - qcs6125-iot-idp.dtb + qcs6125-iot-idp.dtb \ + qcm6125-iot-external-codec-idp.dtb \ + qcs6125-iot-external-codec-idp.dtb \ + qcm6125-iot-usbc-external-codec-idp.dtb \ + qcs6125-iot-usbc-external-codec-idp.dtb \ + qcm6125-iot-usbc-idp.dtb \ + qcs6125-iot-usbc-idp.dtb \ + qcm6125-iot-dp-idp.dtb \ + qcs6125-iot-dp-idp.dtb endif ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp-overlay.dts new file mode 100644 index 000000000000..96696b0399be --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp-overlay.dts @@ -0,0 +1,51 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include "qcm6125-iot-idp.dtsi" +#include "trinket-audio-overlay.dtsi" + +/ { + model = "Display Port Enable IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,msm-id = <467 0x10000>; + qcom,board-id = <34 4>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; + +&sde_dp { + status = "ok"; + qcom,dp-hpd-gpio = <&tlmm 100 0>; + qcom,dp-low-power-hw-hpd; +}; + +&mdss_dp_pll { + status = "ok"; +}; + +&usb0 { + dwc3@4e00000 { + usb-phy = <&qusb_phy0>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi &sde_dp>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp.dts new file mode 100644 index 000000000000..2a0232f76173 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-dp-idp.dts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcm6125.dtsi" +#include "qcm6125-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM6125 IOT Disp. Port Enable IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,board-id = <34 4>; +}; + +&sde_dp { + status = "ok"; + qcom,dp-hpd-gpio = <&tlmm 100 0>; + qcom,dp-low-power-hw-hpd; +}; + +&mdss_dp_pll { + status = "ok"; +}; + +&usb0 { + dwc3@4e00000 { + usb-phy = <&qusb_phy0>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi &sde_dp>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp-overlay.dts new file mode 100644 index 000000000000..c8a93d2e1cc4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "qcm6125-iot-idp.dtsi" +#include "trinket-tasha-codec-audio-overlay.dtsi" +#include "trinket-tasha-codec.dtsi" + +/ { + model = "Ext Audio Codec IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,msm-id = <467 0x10000>; + qcom,board-id = <34 1>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp.dts new file mode 100644 index 000000000000..586d54193c07 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-external-codec-idp.dts @@ -0,0 +1,24 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcm6125.dtsi" +#include "qcm6125-iot-idp.dtsi" +#include "trinket-tasha-codec-audio-overlay.dtsi" +#include "trinket-tasha-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM6125 IOT Ext Audio Codec IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp-overlay.dts new file mode 100644 index 000000000000..2c9d5820eccb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp-overlay.dts @@ -0,0 +1,29 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "qcm6125-iot-idp.dtsi" + +/ { + model = "USB-C Ext Audio Codec IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,msm-id = <467 0x10000>; + qcom,board-id = <34 3>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp.dts new file mode 100644 index 000000000000..a3c69c31f734 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-external-codec-idp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcm6125.dtsi" +#include "qcm6125-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies,Inc. QCM6125 IOT USBC Ext Aud Codec IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,board-id = <34 3>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp-overlay.dts new file mode 100644 index 000000000000..ef7a24aeb2bf --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp-overlay.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "qcm6125-iot-idp.dtsi" +#include "qcm6125-iot-usbc-idp.dtsi" + +/ { + model = "USBC Audio IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,msm-id = <467 0x10000>; + qcom,board-id = <34 2>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dts b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dts new file mode 100644 index 000000000000..73f65a9fc2d6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcm6125.dtsi" +#include "qcm6125-iot-idp.dtsi" +#include "qcm6125-iot-usbc-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM6125 IOT USBC Audio IDP"; + compatible = "qcom,qcm6125-idp", "qcom,qcm6125", "qcom,idp"; + qcom,board-id = <34 2>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dtsi b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dtsi new file mode 100644 index 000000000000..faafcf82f5e3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6125-iot-usbc-idp.dtsi @@ -0,0 +1,19 @@ +/* Copyright (c) 2020, 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 "trinket-audio-overlay.dtsi" + +&sm6150_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp-overlay.dts new file mode 100644 index 000000000000..2830ca6cfde8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp-overlay.dts @@ -0,0 +1,51 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include "qcs6125-iot-idp.dtsi" +#include "trinket-audio-overlay.dtsi" + +/ { + model = "Display Port Enable IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,msm-id = <468 0x10000>; + qcom,board-id = <34 4>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; + +&sde_dp { + status = "ok"; + qcom,dp-hpd-gpio = <&tlmm 100 0>; + qcom,dp-low-power-hw-hpd; +}; + +&mdss_dp_pll { + status = "ok"; +}; + +&usb0 { + dwc3@4e00000 { + usb-phy = <&qusb_phy0>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi &sde_dp>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp.dts new file mode 100644 index 000000000000..69bf2c2be9d8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-dp-idp.dts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcs6125.dtsi" +#include "qcs6125-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCM6125 IOT Disp. Port Enable IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,board-id = <34 4>; +}; + +&sde_dp { + status = "ok"; + qcom,dp-hpd-gpio = <&tlmm 100 0>; + qcom,dp-low-power-hw-hpd; +}; + +&mdss_dp_pll { + status = "ok"; +}; + +&usb0 { + dwc3@4e00000 { + usb-phy = <&qusb_phy0>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&mdss_mdp { + connectors = <&sde_wb &sde_dsi &sde_dp>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp-overlay.dts new file mode 100644 index 000000000000..d5c75339ba9d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "qcs6125-iot-idp.dtsi" +#include "trinket-tasha-codec-audio-overlay.dtsi" +#include "trinket-tasha-codec.dtsi" + +/ { + model = "Ext Audio Codec IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,msm-id = <468 0x10000>; + qcom,board-id = <34 1>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp.dts new file mode 100644 index 000000000000..7d75678fd29a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-external-codec-idp.dts @@ -0,0 +1,24 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcs6125.dtsi" +#include "qcs6125-iot-idp.dtsi" +#include "trinket-tasha-codec-audio-overlay.dtsi" +#include "trinket-tasha-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS6125 IOT Ext Audio Codec IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,board-id = <34 1>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp-overlay.dts new file mode 100644 index 000000000000..8fb605f7dac8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp-overlay.dts @@ -0,0 +1,29 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "qcs6125-iot-idp.dtsi" + +/ { + model = "USB-C Ext Audio Codec IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,msm-id = <468 0x10000>; + qcom,board-id = <34 3>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp.dts new file mode 100644 index 000000000000..8a47d58bc4d1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-external-codec-idp.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcs6125.dtsi" +#include "qcs6125-iot-idp.dtsi" + +/ { + model = "Qualcomm Technologies,Inc. QCS6125IOT USBC Ext AudioCodec IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,board-id = <34 3>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp-overlay.dts new file mode 100644 index 000000000000..3428c7b93bc4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp-overlay.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; +/plugin/; + +#include + +#include "qcs6125-iot-idp.dtsi" +#include "qcs6125-iot-usbc-idp.dtsi" + +/ { + model = "USBC Audio IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,msm-id = <468 0x10000>; + qcom,board-id = <34 2>; +}; + +&dsi_td4330_truly_cmd_display { + qcom,dsi-display-active; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dts b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dts new file mode 100644 index 000000000000..a33a34046fdc --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dts @@ -0,0 +1,23 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "qcs6125.dtsi" +#include "qcs6125-iot-idp.dtsi" +#include "qcs6125-iot-usbc-idp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QCS6125 IOT USBC Audio IDP"; + compatible = "qcom,qcs6125-idp", "qcom,qcs6125", "qcom,idp"; + qcom,board-id = <34 2>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dtsi b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dtsi new file mode 100644 index 000000000000..faafcf82f5e3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6125-iot-usbc-idp.dtsi @@ -0,0 +1,19 @@ +/* Copyright (c) 2020, 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 "trinket-audio-overlay.dtsi" + +&sm6150_snd { + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; +}; -- GitLab From a9df292c64d9c52175585ff0325403bbd7ddde9d Mon Sep 17 00:00:00 2001 From: AnilKumar Chimata Date: Thu, 25 Jun 2020 23:03:43 +0530 Subject: [PATCH 0943/1055] ARM: dts: msm: Fix crypto tests Disable smmu s1 mapping to avoid crypto driver issues. Change-Id: I19291eecc59399c4722bc40ab2a4c9e4df0940c8 Signed-off-by: AnilKumar Chimata --- arch/arm64/boot/dts/qcom/sdxprairie.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index 8548d20c3808..3b65fa169b0f 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -845,7 +845,6 @@ <125 512 0 0>, <125 512 393600 393600>; qcom,no-clock-support; - qcom,smmu-s1-enable; iommus = <&apps_smmu 0x0066 0x0011>, <&apps_smmu 0x0076 0x0011>; }; @@ -874,7 +873,6 @@ qcom,use-sw-ahash-algo; qcom,use-sw-hmac-algo; qcom,no-clock-support; - qcom,smmu-s1-enable; iommus = <&apps_smmu 0x0064 0x0011>, <&apps_smmu 0x0074 0x0011>; }; -- GitLab From 561fd03778a168d4b789d6585ce7050479b3857e Mon Sep 17 00:00:00 2001 From: Chandrasekhar Mattaparthy Date: Sun, 28 Jun 2020 11:32:34 +0530 Subject: [PATCH 0944/1055] msm: kernel: add bgcom interface header file add bgcom_interface header file in the list for the sake of apps. Change-Id: I91ea97e4a03513b5521ce8173d726a4f42e8a41c Signed-off-by: Chandrasekhar Mattaparthy --- gen_headers_arm.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/gen_headers_arm.bp b/gen_headers_arm.bp index 3328f0946807..32c29ce167e0 100644 --- a/gen_headers_arm.bp +++ b/gen_headers_arm.bp @@ -146,6 +146,7 @@ gen_headers_out_arm = [ "linux/bcache.h", "linux/bcm933xx_hcs.h", "linux/bfs_fs.h", + "linux/bgcom_interface.h", "linux/binfmts.h", "linux/blkpg.h", "linux/blktrace_api.h", -- GitLab From 5f8afbea3dcad56ff05e2e06116ec81a32b5d43d Mon Sep 17 00:00:00 2001 From: Yadu MG Date: Mon, 22 Jun 2020 00:41:31 +0530 Subject: [PATCH 0945/1055] ARM: dts: msm: Enable CTIs and TPDMs for sdmshrike Enable Cross Trigger interface for dlct, turing, titan, venus, dlmm, ddr, swao and TPDMs prng, vsense, npu on sdmshrike target. Change-Id: I6a312f0ede5d2fc3150973613216572a2d863140 Signed-off-by: Yadu MG --- .../boot/dts/qcom/sdmshrike-coresight.dtsi | 409 +++++++++++++++++- 1 file changed, 408 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi index 9305469824e9..916e61052242 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi @@ -1138,6 +1138,234 @@ clock-names = "apb_pclk"; }; + cti0_dlct: cti@6c29000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c29000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlct: cti@6c2a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c2a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_mss_q6: cti@683b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x683b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-mss-q6"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_turing: cti@6867000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6867000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_aop_m3: cti@6b21000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b21000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-aop-m3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_titan: cti@6c13000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c13000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-titan"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti_venus_arm9: cti@6c20000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c20000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-venus-arm9"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlmm: cti@6c09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c09000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlmm: cti@6c0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c0a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlct: cti@6c29000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c29000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_dlct: cti@6c2a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6c2a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlct_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_swao:cti@6b04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b04000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_swao: cti@6b05000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b05000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti2_swao: cti@6b06000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b06000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti3_swao: cti@6b07000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b07000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti3"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr0: cti@6a02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a02000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr0: cti@6a03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a03000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr1: cti@6a10000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a10000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr1: cti@6a11000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6a11000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + hwevent: hwevent@91866f0 { compatible = "qcom,coresight-hwevent"; reg = <0x091866f0 0x4>, @@ -1232,10 +1460,27 @@ remote-endpoint = <&funnel_qatb_in_tpda>; }; - }; port@1 { + reg = <2>; + tpda_in_tpdm_center: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_center_out_tpda>; + }; + }; + + port@2 { + reg = <3>; + tpda_in_tpdm_npu: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_npu_out_tpda>; + }; + }; + + port@3 { reg = <5>; tpda_in_funnel_ddr_0: endpoint { slave-mode; @@ -1243,6 +1488,33 @@ <&funnel_ddr_0_out_tpda>; }; }; + + port@4 { + reg = <11>; + tpda_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda>; + }; + }; + + port@5 { + reg = <13>; + tpda_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda>; + }; + }; + + port@6 { + reg = <16>; + tpda_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda>; + }; + }; }; }; @@ -1301,6 +1573,125 @@ }; }; + tpdm_center: tpdm@6c28000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c28000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-center"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_center_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_center>; + }; + }; + }; + + tpdm_prng: tpdm@684c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x684c000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-prng"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_prng_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_prng>; + }; + }; + }; + + tpdm_vsense: tpdm@6840000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6840000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-vsense"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port{ + tpdm_vsense_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_vsense>; + }; + }; + }; + + tpdm_npu: tpdm@6980000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6980000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-npu"; + + clocks = <&clock_aop QDSS_CLK>, + <&clock_gcc GCC_NPU_TRIG_CLK>, + <&clock_gcc GCC_NPU_AT_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_APB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_ATB_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_CLK>, + <&clock_npucc NPU_CC_NPU_CORE_CLK_SRC>, + <&clock_npucc NPU_CC_NPU_CORE_CTI_CLK>; + + clock-names = "apb_pclk", + "gcc_npu_trig_clk", + "gcc_npu_at_clk", + "npu_core_apb_clk", + "npu_core_atb_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_core_cti_clk"; + + qcom,tpdm-clks = "gcc_npu_trig_clk", + "gcc_npu_at_clk", + "npu_core_apb_clk", + "npu_core_atb_clk", + "npu_core_clk", + "npu_core_clk_src", + "npu_core_cti_clk"; + + vdd-supply = <&npu_core_gdsc>; + vdd_cx-supply = <&VDD_CX_LEVEL>; + qcom,tpdm-regs = "vdd", "vdd_cx"; + + port{ + tpdm_npu_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_npu>; + }; + }; + }; + + tpdm_pimem: tpdm@6850000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6850000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-pimem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_pimem_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_pimem>; + }; + }; + }; + stm: stm@6002000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b962>; @@ -1321,4 +1712,20 @@ }; }; }; + + ipcb_tgu: tgu@6b0c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b999>; + reg = <0x06B0C000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <4>; + tgu-timer-counters = <8>; + + coresight-name = "coresight-tgu-ipcb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; }; -- GitLab From 674ea5853437c1f8c95613c18e350f97d02342fe Mon Sep 17 00:00:00 2001 From: Yadu MG Date: Mon, 22 Jun 2020 01:38:10 +0530 Subject: [PATCH 0946/1055] ARM: dts: msm: Add trace source coresight nodes for sdmshrike Enable coresight components for the ATB/TPDM sources swao, modem, wcss, qm, audio, turing and multimedia for sdmshrike. Change-Id: Ide396a21f4742f5ab838423459458dd09ad9a00a Signed-off-by: Yadu MG --- .../boot/dts/qcom/sdmshrike-coresight.dtsi | 947 +++++++++++++++++- 1 file changed, 926 insertions(+), 21 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi index 916e61052242..8a3da7c6b69d 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-coresight.dtsi @@ -24,6 +24,20 @@ qcom,blk-size = <1>; }; + swao_csr: csr@6b0e000 { + compatible = "qcom,coresight-csr"; + reg = <0x6b0e000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-swao-csr"; + qcom,timestamp-support; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,blk-size = <1>; + }; + replicator_qdss: replicator@6046000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b909>; @@ -48,6 +62,14 @@ }; }; + port@1 { + reg = <1>; + replicator0_out_replicator1_in: endpoint { + remote-endpoint= + <&replicator1_in_replicator0_out>; + }; + }; + port@2 { reg = <0>; replicator0_in_tmc_etf: endpoint { @@ -59,6 +81,41 @@ }; }; + replicator_qdss1: replicator@604a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x604a000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-qdss1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <1>; + replicator1_out_funnel_swao: endpoint { + remote-endpoint= + <&funnel_swao_in_replicator1_out>; + }; + }; + + port@1 { + reg = <1>; + replicator1_in_replicator0_out: endpoint { + slave-mode; + remote-endpoint= + <&replicator0_out_replicator1_in>; + }; + }; + }; + }; + tmc_etr: tmc@6048000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b961>; @@ -210,51 +267,618 @@ }; }; - port@2 { - reg = <7>; - funnel_in0_in_stm: endpoint { - slave-mode; - remote-endpoint = <&stm_out_funnel_in0>; - }; + port@2 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = <&stm_out_funnel_in0>; + }; + }; + }; + }; + + funnel_in1: funnel@0x6042000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6042000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in1_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in1>; + }; + }; + + port@1 { + reg = <0>; + funnel_in1_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_in1>; + }; + }; + + port@2 { + reg = <1>; + funnel_in1_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_funnel_in1>; + }; + }; + + port@3 { + reg = <4>; + funnel_in1_in_funnel_apss_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merg_out_funnel_in1>; + }; + }; + + port@4 { + reg = <6>; + funnel_in1_in_tpda_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpda_modem_in_tpdm_modem>; + }; + }; + }; + }; + + replicator_swao: replicator@6b0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6b0a000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator-swao"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* Always have EUD before funnel leading to ETR. If both + * sink are active we need to give preference to EUD + * over ETR + */ + port@0 { + reg = <1>; + replicator_swao_out_eud: endpoint { + remote-endpoint = + <&dummy_eud_in_replicator_swao>; + }; + }; + + port@1 { + reg = <0>; + replicator_swao_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_replicator_swao>; + }; + }; + + port@2 { + reg = <0>; + replicator_swao_in_tmc_etf_swao: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_swao_out_replicator_swao>; + }; + }; + }; + }; + + dummy_eud: dummy_sink { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-eud"; + + qcom,dummy-sink; + port { + dummy_eud_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_eud>; + }; + }; + }; + + tmc_etf_swao: tmc@6b09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6b09000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf-swao"; + coresight-csr = <&csr>; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_swao_out_replicator_swao: endpoint { + remote-endpoint= + <&replicator_swao_in_tmc_etf_swao>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_swao_in_funnel_swao: endpoint { + slave-mode; + remote-endpoint= + <&funnel_swao_out_tmc_etf_swao>; + }; + }; + }; + }; + + funnel_swao:funnel@6b08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6b08000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-swao"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_swao_out_tmc_etf_swao: endpoint { + remote-endpoint = + <&tmc_etf_swao_in_funnel_swao>; + }; + }; + + port@1 { + reg = <5>; + funnel_swao_in_ssc_etm0: endpoint { + slave-mode; + remote-endpoint= + <&ssc_etm0_out_funnel_swao>; + }; + }; + + port@2 { + reg = <6>; + funnel_swao_in_replicator1_out: endpoint { + slave-mode; + remote-endpoint= + <&replicator1_out_funnel_swao>; + }; + }; + + port@3 { + reg = <7>; + funnel_swao_in_tpda_swao: endpoint { + slave-mode; + remote-endpoint= + <&tpda_swao_out_funnel_swao>; + }; + }; + }; + }; + + tpda_swao: tpda@6b01000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6b01000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-swao"; + + qcom,tpda-atid = <71>; + qcom,dsb-elem-size = <1 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_swao_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_tpda_swao>; + }; + + }; + + port@1 { + reg = <0>; + tpda_swao_in_tpdm_swao0: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao0_out_tpda_swao>; + }; + }; + + port@2 { + reg = <1>; + tpda_swao_in_tpdm_swao1: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_swao1_out_tpda_swao>; + }; + }; + }; + }; + + tpdm_swao0: tpdm@6b02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + + reg = <0x6b02000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-swao-0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_swao0_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao0>; + }; + }; + }; + + tpdm_swao1: tpdm@6b03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b03000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name="coresight-tpdm-swao-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_swao1_out_tpda_swao: endpoint { + remote-endpoint = <&tpda_swao_in_tpdm_swao1>; + }; + }; + }; + + ssc_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-ssc-etm0"; + qcom,inst-id = <8>; + + port { + ssc_etm0_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_ssc_etm0>; + }; + }; + }; + + tpda_modem: tpda@6832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6832000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-modem"; + + qcom,tpda-atid = <67>; + qcom,dsb-elem-size = <0 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tpda_modem_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_tpda_modem>; + }; + }; + + port@1 { + reg = <0>; + tpda_modem_in_tpdm_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_modem_out_tpda_modem>; + }; + }; + }; + }; + + tpdm_modem: tpdm@6830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-modem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_modem_out_tpda_modem: endpoint { + remote-endpoint = <&tpda_modem_in_tpdm_modem>; + }; + }; + }; + + modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-modem-etm0"; + qcom,inst-id = <2>; + + port { + modem_etm0_out_funnel_in1: endpoint { + remote-endpoint = + <&funnel_in1_in_modem_etm0>; + }; + }; + }; + + funnel_dl_mm: funnel@6c0b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6c0b000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-mm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_dl_mm_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_dl_mm>; + }; + }; + + port@1 { + reg = <0>; + funnel_dl_mm_in_tpdm_qm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_qm_out_funnel_dl_mm>; + }; + }; + }; + }; + + tpdm_qm: tpdm@69d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69d0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-qm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_qm_out_funnel_dl_mm: endpoint { + remote-endpoint = <&funnel_dl_mm_in_tpdm_qm>; + }; + }; + }; + + funnel_dl_mm1: funnel_1@6c0b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6867000 0x10>, + <0x6c0b000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-dl-mm1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_dl_mm1_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_dl_mm1>; + }; + }; + + port@1 { + reg = <1>; + funnel_dl_mm1_in_tpdm_mm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mm_out_funnel_dl_mm1>; + }; + }; + }; + }; + + tpdm_mm: tpdm@6c08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c08000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-mm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_mm_out_funnel_dl_mm1: endpoint { + remote-endpoint = <&funnel_dl_mm1_in_tpdm_mm>; + }; + }; + }; + + funnel_turing: funnel@6861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6861000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_turing_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_turing>; + }; + }; + + port@1 { + reg = <0>; + funnel_turing_in_tpdm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_out_funnel_turing>; + }; + }; + }; + }; + + tpdm_turing: tpdm@6860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6860000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-turing"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_turing_out_funnel_turing: endpoint { + remote-endpoint = + <&funnel_turing_in_tpdm_turing>; }; }; }; - funnel_in1: funnel@0x6042000 { + funnel_turing_1: funnel_1@6861000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b908>; - reg = <0x6042000 0x1000>; - reg-names = "funnel-base"; + reg = <0x6867010 0x10>, + <0x6861000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; - coresight-name = "coresight-funnel-in1"; + coresight-name = "coresight-funnel-turing-1"; clocks = <&clock_aop QDSS_CLK>; clock-names = "apb_pclk"; + qcom,duplicate-funnel; + ports { #address-cells = <1>; #size-cells = <0>; port@0 { reg = <0>; - funnel_in1_out_funnel_merg: endpoint { + funnel_turing_1_out_funnel_qatb: endpoint { remote-endpoint = - <&funnel_merg_in_funnel_in1>; + <&funnel_qatb_in_funnel_turing_1>; }; }; - port@3 { - reg = <4>; - funnel_in1_in_funnel_apss_merg: endpoint { + port@1 { + reg = <1>; + funnel_turing_1_in_turing_etm0: endpoint { slave-mode; remote-endpoint = - <&funnel_apss_merg_out_funnel_in1>; + <&turing_etm0_out_funnel_turing_1>; }; }; }; }; + turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-turing-etm0"; + qcom,inst-id = <13>; + + port{ + turing_etm0_out_funnel_turing_1: endpoint { + remote-endpoint = + <&funnel_turing_1_in_turing_etm0>; + }; + }; + }; + funnel_apss_merg: funnel@7810000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b908>; @@ -1420,6 +2044,24 @@ <&tpda_out_funnel_qatb>; }; }; + + port@2 { + reg = <5>; + funnel_qatb_in_funnel_turing_1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_1_out_funnel_qatb>; + }; + }; + + port@3 { + reg = <6>; + funnel_qatb_in_funnel_lpass_1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_lpass_1_out_funnel_qatb>; + }; + }; }; }; @@ -1445,6 +2087,7 @@ <13 32>; qcom,cmb-elem-size = <3 64>, <7 64>, + <10 64>, <13 64>; clocks = <&clock_aop QDSS_CLK>; @@ -1463,6 +2106,24 @@ }; port@1 { + reg = <0>; + tpda_in_funnel_dl_mm: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_mm_out_tpda>; + }; + }; + + port@2 { + reg = <1>; + tpda_in_funnel_dl_mm1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_mm1_out_tpda>; + }; + }; + + port@3 { reg = <2>; tpda_in_tpdm_center: endpoint { slave-mode; @@ -1471,7 +2132,7 @@ }; }; - port@2 { + port@4 { reg = <3>; tpda_in_tpdm_npu: endpoint { slave-mode; @@ -1480,7 +2141,7 @@ }; }; - port@3 { + port@5 { reg = <5>; tpda_in_funnel_ddr_0: endpoint { slave-mode; @@ -1489,7 +2150,35 @@ }; }; - port@4 { + port@6 { + reg = <8>; + tpda_in_funnel_dl_south: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_south_out_tpda>; + }; + }; + + port@7 { + reg = <9>; + tpda_in_funnel_lpass: endpoint { + slave-mode; + remote-endpoint = + <&funnel_lpass_out_tpda>; + }; + }; + + port@8 { + reg = <10>; + tpda_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_tpda>; + }; + }; + + + port@9 { reg = <11>; tpda_in_tpdm_vsense: endpoint { slave-mode; @@ -1498,7 +2187,7 @@ }; }; - port@5 { + port@10 { reg = <13>; tpda_in_tpdm_prng: endpoint { slave-mode; @@ -1507,7 +2196,7 @@ }; }; - port@6 { + port@11 { reg = <16>; tpda_in_tpdm_pimem: endpoint { slave-mode; @@ -1518,6 +2207,222 @@ }; }; + funnel_lpass: funnel@6846000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6846000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-lpass"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_lpass_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_lpass>; + }; + }; + + port@1 { + reg = <0>; + funnel_lpass_in_tpdm_lpass: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_lpass_out_funnel_lpass>; + }; + }; + }; + }; + + tpdm_lpass: tpdm@6844000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6844000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-lpass"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_lpass_out_funnel_lpass: endpoint { + remote-endpoint = <&funnel_lpass_in_tpdm_lpass>; + }; + }; + }; + + funnel_lpass_1: funnel_1@6846000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6867020 0x10>, + <0x6846000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-lpass-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_lpass_1_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_lpass_1>; + }; + }; + + port@1 { + reg = <2>; + funnel_lpass_1_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_lpass_1>; + }; + }; + }; + }; + + audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-audio-etm0"; + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_lpass_1: endpoint { + remote-endpoint = + <&funnel_lpass_1_in_audio_etm0>; + }; + }; + }; + + funnel_dl_south: funnel@69c2000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x69c2000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-dl-south"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + funnel_dl_south_out_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_dl_south>; + }; + }; + + port@1 { + reg = <1>; + funnel_dl_south_in_tpdm_dl_south: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dl_south_out_funnel_dl_south>; + }; + }; + + port@2 { + reg = <3>; + funnel_dl_south_in_funnel_wcss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_wcss_out_funnel_dl_south>; + }; + }; + }; + }; + + tpdm_dl_south: tpdm@69c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69c0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dl-south"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_dl_south_out_funnel_dl_south: endpoint { + remote-endpoint = + <&funnel_dl_south_in_tpdm_dl_south>; + }; + }; + }; + + funnel_wcss: funnel@6ac2000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6ac2000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-wcss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_wcss_out_funnel_dl_south: endpoint { + remote-endpoint = + <&funnel_dl_south_in_funnel_wcss>; + }; + }; + + port@2 { + reg = <1>; + funnel_wcss_in_tpdm_wcss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_wcss_out_funnel_wcss>; + }; + }; + }; + }; + + tpdm_wcss: tpdm@699c000 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-tpdm-wcss"; + qcom,dummy-source; + + port { + tpdm_wcss_out_funnel_wcss: endpoint { + remote-endpoint = <&funnel_wcss_in_tpdm_wcss>; + }; + }; + }; + funnel_ddr_0: funnel@6a05000 { compatible = "arm,primecell"; arm,primecell-periphid = <0x0003b908>; -- GitLab From a7d112d9e59ec07fb5842e58364df54bc78740e4 Mon Sep 17 00:00:00 2001 From: Chandrasekhar Mattaparthy Date: Sun, 28 Jun 2020 17:30:21 +0530 Subject: [PATCH 0947/1055] msm: kernel: add bgcom interface header file add bgcom_interface header file in the list for arm64 also for the sake of apps. Change-Id: Ie7dfbd9b9fdc36bba70d806197dca164b8272c96 Signed-off-by: Chandrasekhar Mattaparthy --- gen_headers_arm64.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/gen_headers_arm64.bp b/gen_headers_arm64.bp index 59e3ed2c3c50..f3e6a91973b0 100644 --- a/gen_headers_arm64.bp +++ b/gen_headers_arm64.bp @@ -142,6 +142,7 @@ gen_headers_out_arm64 = [ "linux/bcache.h", "linux/bcm933xx_hcs.h", "linux/bfs_fs.h", + "linux/bgcom_interface.h", "linux/binfmts.h", "linux/blkpg.h", "linux/blktrace_api.h", -- GitLab From ec8d33c43ee7d555bb3ba109103b10956f5e11df Mon Sep 17 00:00:00 2001 From: Archit Saxena Date: Tue, 2 Jun 2020 21:34:06 +0530 Subject: [PATCH 0948/1055] ARM: dts: msm: Add pil nodes to sdm429 Add pil nodes for sdm429 bringup. Change-Id: I3d92564ec751eb317cebe68daf8cd875d352f794 Signed-off-by: Archit Saxena --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 167 ++++++++++++++++++++++++++- 1 file changed, 162 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 0391e6bcacd4..3fce67f8a4ce 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -16,6 +16,7 @@ #include #include #include +#include / { model = "Qualcomm Technologies, Inc. SDM429"; @@ -122,11 +123,11 @@ }; gpu_mem: gpu_region@0 { - compatible = "shared-dma-pool"; - reusable; - alloc-ranges = <0x0 0x80000000 0x0 0x10000000>; - alignment = <0 0x400000>; - size = <0 0x800000>; + compatible = "shared-dma-pool"; + reusable; + alloc-ranges = <0x0 0x80000000 0x0 0x10000000>; + alignment = <0 0x400000>; + size = <0 0x800000>; }; linux,cma { @@ -505,6 +506,162 @@ }; }; + qcom,lpass@c000000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xc000000 0x00100>; + + vdd_cx-supply = <&pm660_s2_level>; + qcom,proxy-reg-names = "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + + clocks = <&rpmcc CXO_SMD_PIL_LPASS_CLK>, + <&gcc GCC_CRYPTO_CLK>, + <&gcc GCC_CRYPTO_AHB_CLK>, + <&gcc GCC_CRYPTO_AXI_CLK>, + <&gcc CRYPTO_CLK_SRC>; + + qcom,scm_core_clk_src-freq = <80000000>; + clock-names = "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,proxy-clock-names = "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + + qcom,pas-id = <1>; + qcom,mas-crypto = <&mas_crypto>; + qcom,complete-ramdump; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <423>; + qcom,sysmon-id = <1>; + qcom,ssctl-instance-id = <0x14>; + qcom,firmware-name = "adsp"; + + /* GPIO inputs from lpass */ + interrupts-extended = <&intc 0 293 1>, + <&adsp_smp2p_in 0 0>, + <&adsp_smp2p_in 2 0>, + <&adsp_smp2p_in 1 0>, + <&adsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; + /* GPIO output to lpass */ + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + memory-region = <&adsp_fw_mem>; + }; + + qcom,pronto@a21b000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x0a21b000 0x3000>; + + vdd_pronto_pll-supply = <&pm660_l12>; + qcom,proxy-reg-names = "vdd_pronto_pll"; + qcom,vdd_cx-uV-uA = ; + + clocks = <&rpmcc CXO_SMD_PIL_PRONTO_CLK>, + <&gcc GCC_CRYPTO_CLK>, + <&gcc GCC_CRYPTO_AHB_CLK>, + <&gcc GCC_CRYPTO_AXI_CLK>, + <&gcc CRYPTO_CLK_SRC>; + clock-names = "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,proxy-clock-names = "xo", "scm_core_clk", "scm_iface_clk", + "scm_bus_clk", "scm_core_clk_src"; + qcom,pas-id = <6>; + qcom,mas-crypto = <&mas_crypto>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <422>; + qcom,sysmon-id = <6>; + qcom,ssctl-instance-id = <0x13>; + qcom,firmware-name = "wcnss"; + + /* GPIO inputs from wcnss */ + interrupts-extended = <&intc 0 149 1>, + <&wcnss_smp2p_in 0 0>, + <&wcnss_smp2p_in 2 0>, + <&wcnss_smp2p_in 1 0>, + <&wcnss_smp2p_in 3 0>, + <&wcnss_smp2p_in 7 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack", + "qcom,shutdown-ack"; + + /* GPIO output to wcnss */ + qcom,smem-states = <&wcnss_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + memory-region = <&wcnss_fw_mem>; + }; + + pil_modem: qcom,mss@4080000 { + compatible = "qcom,pil-q6v55-mss"; + reg = <0x4080000 0x100>, + <0x0194f000 0x010>, + <0x01950000 0x008>, + <0x01951000 0x008>, + <0x04020000 0x040>, + <0x01871000 0x004>; + reg-names = "qdsp6_base", "halt_q6", "halt_modem", + "halt_nc", "rmb_base", "restart_reg", + "cxip_lm_vote_clear"; + + clocks = <&rpmcc CXO_SMD_PIL_MSS_CLK>, + <&gcc GCC_MSS_CFG_AHB_CLK>, + <&gcc GCC_MSS_Q6_BIMC_AXI_CLK>, + <&gcc GCC_BOOT_ROM_AHB_CLK>; + clock-names = "xo", "iface_clk", "bus_clk", "mem_clk"; + qcom,proxy-clock-names = "xo"; + qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk"; + + vdd_mss-supply = <&S6A>; + vdd_cx-supply = <&pm660_s1_level_ao>; + vdd_cx-voltage = ; + vdd_mx-supply = <&pm660_s2_level_ao>; + vdd_mx-uV = ; + vdd_pll-supply = <&L12A>; + qcom,vdd_pll = <1800000>; + vdd_mss-uV = ; + + qcom,pas-id = <5>; + qcom,pil-mss-memsetup; + qcom,firmware-name = "modem"; + qcom,pil-self-auth; + qcom,sequential-fw-load; + qcom,override-acc-1 = <0x80800000>; + qcom,sysmon-id = <0>; + qcom,ssctl-instance-id = <0x12>; + memory-region = <&modem_mem>; + qcom,qdsp6v56-1-8-inrush-current; + qcom,reset-clk; + + /* Inputs from mss */ + interrupts-extended = <&intc 0 24 1>, + <&modem_smp2p_in 0 0>, + <&modem_smp2p_in 2 0>, + <&modem_smp2p_in 1 0>, + <&modem_smp2p_in 3 0>, + <&modem_smp2p_in 7 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack", + "qcom,shutdown-ack"; + + /* Outputs to mss */ + qcom,smem-states = <&modem_smp2p_out 0>; + qcom,smem-state-names = "qcom,force-stop"; + + status = "ok"; + }; + rpm_bus: qcom,rpm-smd { }; usb_otg: usb@78db000 { -- GitLab From 4bf3e5dce0e12f24ceae1071906af0c780310535 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Mon, 29 Jun 2020 10:36:02 +0530 Subject: [PATCH 0949/1055] usb: misc: Add support for diag bridging over mdm_data_bridge Add support for bridging diag messages over mdm_data_bridge instead of the traditional diag_bridge and char drivers. This simplifies the design and helps with better handling of diag EP polling in throughput intensive cases on telematics platforms. Change-Id: I6e6f3259cb6371796d9b6a9f2d824dca5576ed4a Signed-off-by: Ajay Agarwal --- drivers/usb/misc/diag_bridge.c | 26 -------------------------- drivers/usb/misc/mdm_data_bridge.c | 26 ++++++++++++++++++++++++++ include/linux/usb/usb_bridge.h | 5 +++++ 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c index f54e3aa1ca67..5a0dc78be31f 100644 --- a/drivers/usb/misc/diag_bridge.c +++ b/drivers/usb/misc/diag_bridge.c @@ -588,34 +588,8 @@ static int diag_bridge_resume(struct usb_interface *ifc) static const struct usb_device_id diag_bridge_ids[] = { { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x901F, 0), .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90EF, 4), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90F0, 4), - .driver_info = DEV_ID(0), }, { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90F3, 0), .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x90FD, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9102, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9103, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9104, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9105, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9106, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x9107, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x910A, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x910B, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x910C, 0), - .driver_info = DEV_ID(0), }, - { USB_DEVICE_INTERFACE_NUMBER(0x5c6, 0x910D, 0), - .driver_info = DEV_ID(0), }, {} /* terminating entry */ }; diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c index 427d41193ca8..9bd5a1f00d3f 100644 --- a/drivers/usb/misc/mdm_data_bridge.c +++ b/drivers/usb/misc/mdm_data_bridge.c @@ -970,34 +970,60 @@ static void bridge_disconnect(struct usb_interface *intf) static const struct usb_device_id bridge_ids[] = { { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9008, 0), .driver_info = (kernel_ulong_t)("edl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x90EF, 4), + .driver_info = (kernel_ulong_t)("diag"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x90F0, 4), + .driver_info = (kernel_ulong_t)("diag"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x90FD, 0), + .driver_info = (kernel_ulong_t)("diag"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9102, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9102, 6), .driver_info = (kernel_ulong_t)("qdss"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9102, 7), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9103, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9103, 6), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9104, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9104, 1), .driver_info = (kernel_ulong_t)("qdss"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9104, 2), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9105, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9105, 1), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9106, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9106, 5), .driver_info = (kernel_ulong_t)("qdss"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9106, 6), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9107, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x9107, 5), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910A, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910A, 2), .driver_info = (kernel_ulong_t)("dpl"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910A, 3), .driver_info = (kernel_ulong_t)("qdss"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910B, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910B, 2), .driver_info = (kernel_ulong_t)("dpl"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910C, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910C, 1), .driver_info = (kernel_ulong_t)("dpl"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910C, 2), .driver_info = (kernel_ulong_t)("qdss"), }, + { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910D, 0), + .driver_info = (kernel_ulong_t)("diag"), }, { USB_DEVICE_INTERFACE_NUMBER(0x05c6, 0x910D, 1), .driver_info = (kernel_ulong_t)("dpl"), }, diff --git a/include/linux/usb/usb_bridge.h b/include/linux/usb/usb_bridge.h index a48c180d236b..af25b51071a8 100644 --- a/include/linux/usb/usb_bridge.h +++ b/include/linux/usb/usb_bridge.h @@ -23,6 +23,7 @@ enum bridge_id { USB_BRIDGE_QDSS, USB_BRIDGE_DPL, USB_BRIDGE_EDL, + USB_BRIDGE_DIAG, MAX_BRIDGE_DEVICES, }; @@ -37,6 +38,8 @@ static int bridge_name_to_id(const char *name) return USB_BRIDGE_DPL; if (!strncasecmp(name, "edl", MAX_INST_NAME_LEN)) return USB_BRIDGE_EDL; + if (!strncasecmp(name, "diag", MAX_INST_NAME_LEN)) + return USB_BRIDGE_DIAG; fail: return -EINVAL; @@ -51,6 +54,8 @@ static int bridge_id_to_protocol(enum bridge_id id) return 0x80; case USB_BRIDGE_EDL: return 0x10; + case USB_BRIDGE_DIAG: + return 0x30; default: return -EINVAL; } -- GitLab From be6b935c1cd966122ff9bbaa3365ff29e299a574 Mon Sep 17 00:00:00 2001 From: Asha Magadi Venkateshamurthy Date: Mon, 29 Jun 2020 10:42:44 +0530 Subject: [PATCH 0950/1055] clk: qcom: rcg2: Fix possible null pointer dereference The commit 966bfec0a5ee ("clk: qcom: rcg2: set default freq to clk_gfx3d_src") opens a possibility for NULL pointer dereference, fix this. Change-Id: I5053c3aec17e37656091dfe07af78269bcdab56e Signed-off-by: Asha Magadi Venkateshamurthy --- drivers/clk/qcom/clk-rcg2.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 29e7034a1db3..9fc98819321a 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -1472,7 +1472,11 @@ static int clk_gfx3d_src_determine_rate(struct clk_hw *hw, } f = qcom_find_freq(rcg->freq_tbl, req->rate); - if (!f || (req->rate != f->freq)) + + if (!f) + return -EINVAL; + + if (req->rate != f->freq) req->rate = f->freq; /* Indexes of source from the parent map */ -- GitLab From 31c8fd0a1af95dda7addda4c3de30f25cc0f514e Mon Sep 17 00:00:00 2001 From: Archit Saxena Date: Wed, 8 Apr 2020 23:59:27 +0530 Subject: [PATCH 0951/1055] drivers: soc: qcom: Add bg pil driver to 4.14 The change is to bring bg pil driver to 4.14 which is taken from snapshot of the same driver on 4.9 commit "43ff8774753d32a76f62160f0ad1cecf69fb56e4". ("soc: qcom: Add BG PIL and feature drivers for msm8909w"). Change-Id: I430101cb1c0a4448d77e4315f3bbcf101dadb774 Signed-off-by: Archit Saxena --- .../bindings/pil/pil-blackghost.txt | 33 + drivers/soc/qcom/Kconfig | 8 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/pil_bg_intf.h | 45 + drivers/soc/qcom/subsys-pil-bg.c | 840 ++++++++++++++++++ 5 files changed, 927 insertions(+) create mode 100644 Documentation/devicetree/bindings/pil/pil-blackghost.txt create mode 100644 drivers/soc/qcom/pil_bg_intf.h create mode 100644 drivers/soc/qcom/subsys-pil-bg.c diff --git a/Documentation/devicetree/bindings/pil/pil-blackghost.txt b/Documentation/devicetree/bindings/pil/pil-blackghost.txt new file mode 100644 index 000000000000..94232036acf4 --- /dev/null +++ b/Documentation/devicetree/bindings/pil/pil-blackghost.txt @@ -0,0 +1,33 @@ +Qualcomm Technologies Inc Blackghost(BG) PIL driver: + +Blackghost(BG) PIL driver provide interface to load and boot Blackghost(BG) +SOC. Blackghost(BG) SOC is an external SOC which communicate to MSM via +SPI. The PIL driver loads firmware into memory and invoke secure app via +qseecom to transfer and handshake the boot process. Once Blackghost(BG) SOC +is booted it raises ready interrupt which is handled by BG PIL driver, and +this event is informed to other MSM drivers, other remote subsystem via +notifier framework. The PIL driver also handles interrupt for the BG SOC +crash upon arrival of which it reset and initiates ramdump collection for BG +SOC. + +Required properties: +- compatible: Must be "qcom,pil-blackghost" +- qcom,firmware-name: Base name of the firmware image. +- qcom,bg2ap-status-gpio: GPIO used by the blackghost to indicate status to the apps. +- qcom,bg2ap-errfatal-gpio: GPIO used by the blackghost to indicate software error to the apps. +- qcom,ap2bg-status-gpio: GPIO used by the apps to indicate its status to blackghost. +- qcom,ap2bg-errfatal-gpio: GPIO used by the apps to indicate blackghost about apps reset. + +Example: + + qcom,blackghost { + compatible = "qcom,pil-blackghost"; + qcom,firmware-name = "bgelf"; + + /* GPIO inputs from blackghost */ + qcom,bg2ap-status-gpio = <&msm_gpio 97 0>; + qcom,bg2ap-errfatal-gpio = <&msm_gpio 95 0>; + /* GPIO output to blackghost */ + qcom,ap2bg-status-gpio = <&msm_gpio 17 0>; + qcom,ap2bg-errfatal-gpio = <&msm_gpio 23 0>; + }; diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index d68383deb3f4..ecc947fdaa6c 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -1022,6 +1022,14 @@ config MSM_BAM_DMUX communication between G-Link/bg_com_dev and BG processor over SPI. This handle the interrupts raised by BG and notify the G-link with interrupt event and event data. +config MSM_PIL_SSR_BG + tristate "MSM Subsystem Blackghost(BG) Support" + depends on MSM_PIL && MSM_SUBSYSTEM_RESTART + help + Support for booting and shutting down Blackghost(BG) SOC which is + an external SOC. This driver communicates with Blackghost(BG) SOC + via pair of IPC GPIOs for inward and outward signals between MSM + and Blackghost(BG) SOC. config QCOM_SOC_INFO bool "Chip information for QTI SoCs" diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 45b3a90ec21c..64316c5dfe17 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_MSM_JTAGV8) += jtagv8.o jtagv8-etm.o obj-$(CONFIG_MSM_CDSP_LOADER) += qdsp6v2/ obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o obj-$(CONFIG_SDX_EXT_IPC) += sdx_ext_ipc.o +obj-$(CONFIG_MSM_PIL_SSR_BG) += subsys-pil-bg.o ifdef CONFIG_MSM_SUBSYSTEM_RESTART obj-y += subsystem_notif.o diff --git a/drivers/soc/qcom/pil_bg_intf.h b/drivers/soc/qcom/pil_bg_intf.h new file mode 100644 index 000000000000..d0781d5f5f32 --- /dev/null +++ b/drivers/soc/qcom/pil_bg_intf.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2017-2018, 2020, 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 __BG_INTF_H_ +#define __BG_INTF_H_ + +#define MAX_APP_NAME_SIZE 100 +#define RESULT_SUCCESS 0 +#define RESULT_FAILURE -1 + +/* tzapp command list.*/ +enum bg_tz_commands { + BGPIL_RAMDUMP, + BGPIL_IMAGE_LOAD, + BGPIL_AUTH_MDT, + BGPIL_DLOAD_CONT, + BGPIL_GET_BG_VERSION, +}; + +/* tzapp bg request.*/ +struct tzapp_bg_req { + uint8_t tzapp_bg_cmd; + uint8_t padding[3]; + phys_addr_t address_fw; + size_t size_fw; +} __attribute__ ((__packed__)); + +/* tzapp bg response.*/ +struct tzapp_bg_rsp { + uint32_t tzapp_bg_cmd; + uint32_t bg_info_len; + int32_t status; + uint32_t bg_info[100]; +} __attribute__ ((__packed__)); + +#endif diff --git a/drivers/soc/qcom/subsys-pil-bg.c b/drivers/soc/qcom/subsys-pil-bg.c new file mode 100644 index 000000000000..464fa1273505 --- /dev/null +++ b/drivers/soc/qcom/subsys-pil-bg.c @@ -0,0 +1,840 @@ +/* Copyright (c) 2020, 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 +#include +#include +#include +#include +#include +#include +#include + +#include "peripheral-loader.h" +#include "../../misc/qseecom_kernel.h" +#include "pil_bg_intf.h" +#include "bgcom_interface.h" + +#define INVALID_GPIO -1 +#define NUM_GPIOS 4 +#define SECURE_APP "bgapp" +#define desc_to_data(d) container_of(d, struct pil_bg_data, desc) +#define subsys_to_data(d) container_of(d, struct pil_bg_data, subsys_desc) +#define BG_RAMDUMP_SZ 0x00102000 +#define BG_VERSION_SZ 32 +#define BG_CRASH_IN_TWM -2 +/** + * struct pil_bg_data + * @qseecom_handle: handle of TZ app + * @bg_queue: private queue to schedule worker threads for bottom half + * @restart_work: work struct for executing ssr + * @reboot_blk: notification block for reboot event + * @subsys_desc: subsystem descriptor + * @subsys: subsystem device pointer + * @gpios: array to hold all gpio handle + * @desc: PIL descriptor + * @address_fw: address where firmware binaries loaded + * @ramdump_dev: ramdump device pointer + * @size_fw: size of bg firmware binaries + * @errfatal_irq: irq number to indicate bg crash or shutdown + * @status_irq: irq to indicate bg status + * @app_status: status of tz app loading + * @is_ready: Is BG chip up + * @err_ready: The error ready signal + */ + +struct pil_bg_data { + struct qseecom_handle *qseecom_handle; + struct workqueue_struct *bg_queue; + struct work_struct restart_work; + struct notifier_block reboot_blk; + struct subsys_desc subsys_desc; + struct subsys_device *subsys; + unsigned int gpios[NUM_GPIOS]; + int errfatal_irq; + int status_irq; + struct pil_desc desc; + phys_addr_t address_fw; + void *ramdump_dev; + u32 cmd_status; + size_t size_fw; + int app_status; + bool is_ready; + struct completion err_ready; +}; + +static irqreturn_t bg_status_change(int irq, void *dev_id); + +/** + * bg_app_shutdown_notify() - Toggle AP2BG err fatal gpio when + * called by SSR framework. + * @subsys: struct containing private BG data. + * + * Return: none. + */ +static void bg_app_shutdown_notify(const struct subsys_desc *subsys) +{ + struct pil_bg_data *bg_data = subsys_to_data(subsys); + + /* Disable irq if already BG is up */ + if (bg_data->is_ready) { + disable_irq(bg_data->status_irq); + disable_irq(bg_data->errfatal_irq); + bg_data->is_ready = false; + } + /* Toggle AP2BG err fatal gpio here to inform apps err fatal event */ + if (gpio_is_valid(bg_data->gpios[2])) { + pr_debug("Sending Apps shutdown signal\n"); + gpio_set_value(bg_data->gpios[2], 1); + } +} + +/** + * bg_app_reboot_notify() - Toggle AP2BG err fatal gpio. + * @nb: struct containing private BG data. + * + * Return: NOTIFY_DONE indicating success. + */ +static int bg_app_reboot_notify(struct notifier_block *nb, + unsigned long code, void *unused) +{ + struct pil_bg_data *bg_data = container_of(nb, + struct pil_bg_data, reboot_blk); + + /* Disable irq if already BG is up */ + if (bg_data->is_ready) { + disable_irq(bg_data->status_irq); + disable_irq(bg_data->errfatal_irq); + bg_data->is_ready = false; + } + /* Toggle AP2BG err fatal gpio here to inform apps err fatal event */ + if (gpio_is_valid(bg_data->gpios[2])) { + pr_debug("Sending reboot signal\n"); + gpio_set_value(bg_data->gpios[2], 1); + } + return NOTIFY_DONE; +} + +/** + * get_cmd_rsp_buffers() - Function sets cmd & rsp buffer pointers and + * aligns buffer lengths + * @hdl: index of qseecom_handle + * @cmd: req buffer - set to qseecom_handle.sbuf + * @cmd_len: ptr to req buffer len + * @rsp: rsp buffer - set to qseecom_handle.sbuf + offset + * @rsp_len: ptr to rsp buffer len + * + * Return: Success always . + */ +static int get_cmd_rsp_buffers(struct qseecom_handle *handle, void **cmd, + uint32_t *cmd_len, void **rsp, uint32_t *rsp_len) +{ + *cmd = handle->sbuf; + if (*cmd_len & QSEECOM_ALIGN_MASK) + *cmd_len = QSEECOM_ALIGN(*cmd_len); + + *rsp = handle->sbuf + *cmd_len; + if (*rsp_len & QSEECOM_ALIGN_MASK) + *rsp_len = QSEECOM_ALIGN(*rsp_len); + + return 0; +} + +/** + * pil_load_bg_tzapp() - Called to load TZ app. + * @pbd: struct containing private BG data. + * + * Return: 0 on success. Error code on failure. + */ +static int pil_load_bg_tzapp(struct pil_bg_data *pbd) +{ + int rc; + + /* return success if already loaded */ + if (pbd->qseecom_handle && !pbd->app_status) + return 0; + /* Load the APP */ + rc = qseecom_start_app(&pbd->qseecom_handle, SECURE_APP, SZ_4K); + if (rc < 0) { + dev_err(pbd->desc.dev, "BG TZ app load failure\n"); + pbd->app_status = RESULT_FAILURE; + return -EIO; + } + pbd->app_status = RESULT_SUCCESS; + return 0; +} + +/** + * bgpil_tzapp_comm() - Function called to communicate with TZ APP. + * @req: struct containing command and parameters. + * + * Return: 0 on success. Error code on failure. + */ +static long bgpil_tzapp_comm(struct pil_bg_data *pbd, + struct tzapp_bg_req *req) +{ + struct tzapp_bg_req *bg_tz_req; + struct tzapp_bg_rsp *bg_tz_rsp; + int rc, req_len, rsp_len; + unsigned char *ascii; + char fiwmare_version[100] = {'\0'}; + char ascii_string[5]; + + /* Fill command structure */ + req_len = sizeof(struct tzapp_bg_req); + rsp_len = sizeof(struct tzapp_bg_rsp); + rc = get_cmd_rsp_buffers(pbd->qseecom_handle, + (void **)&bg_tz_req, &req_len, + (void **)&bg_tz_rsp, &rsp_len); + if (rc) + goto end; + + bg_tz_req->tzapp_bg_cmd = req->tzapp_bg_cmd; + bg_tz_req->address_fw = req->address_fw; + bg_tz_req->size_fw = req->size_fw; + rc = qseecom_send_command(pbd->qseecom_handle, + (void *)bg_tz_req, req_len, (void *)bg_tz_rsp, rsp_len); + pr_debug("BG PIL qseecom returned with value 0x%x and status 0x%x\n", + rc, bg_tz_rsp->status); + if (rc || bg_tz_rsp->status) + pbd->cmd_status = bg_tz_rsp->status; + else + pbd->cmd_status = 0; + /* if last command sent was BG_VERSION print the version*/ + if (req->tzapp_bg_cmd == BGPIL_GET_BG_VERSION) { + int i; + + pr_info("BG FW version "); + for (i = 0; i < bg_tz_rsp->bg_info_len; i++) { + pr_info("0x%08x ", bg_tz_rsp->bg_info[i]); + ascii = (unsigned char *)&bg_tz_rsp->bg_info[i]; + snprintf(ascii_string, PAGE_SIZE, "%c%c%c%c", ascii[0], + ascii[1], ascii[2], ascii[3]); + strlcat(fiwmare_version, ascii_string, + PAGE_SIZE); + } + pr_info("%s\n", fiwmare_version); + } +end: + return rc; +} + +/** + * wait_for_err_ready() - Called in power_up to wait for error ready. + * Signal waiting function. + * @bg_data: BG PIL private structure. + * + * Return: 0 on success. Error code on failure. + */ +static int wait_for_err_ready(struct pil_bg_data *bg_data) +{ + int ret; + + if ((!bg_data->status_irq)) + return 0; + + ret = wait_for_completion_timeout(&bg_data->err_ready, + msecs_to_jiffies(10000)); + if (!ret) { + pr_err("[%s]: Error ready timed out\n", bg_data->desc.name); + return -ETIMEDOUT; + } + return 0; +} + +/** + * bg_powerup() - Called by SSR framework on userspace invocation. + * does load tz app and call peripheral loader. + * @subsys: struct containing private BG data. + * + * Return: 0 on success. Error code on failure. + */ +static int bg_powerup(const struct subsys_desc *subsys) +{ + struct pil_bg_data *bg_data = subsys_to_data(subsys); + int ret; + + if (is_bg_running()) { + pr_debug("bg is already up\n"); + return 0; + } + + init_completion(&bg_data->err_ready); + if (!bg_data->qseecom_handle) { + ret = pil_load_bg_tzapp(bg_data); + if (ret) { + dev_err(bg_data->desc.dev, + "%s: BG TZ app load failure\n", + __func__); + return ret; + } + } + pr_debug("bgapp loaded\n"); + bg_data->desc.fw_name = subsys->fw_name; + + ret = devm_request_irq(bg_data->desc.dev, bg_data->status_irq, + bg_status_change, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "bg2ap_status", bg_data); + if (ret < 0) { + dev_err(bg_data->desc.dev, + "%s: BG2AP_STATUS IRQ#%d re registration failed, err=%d", + __func__, bg_data->status_irq, ret); + return ret; + } + + /* Enable status and err fatal irqs */ + ret = pil_boot(&bg_data->desc); + if (ret) { + dev_err(bg_data->desc.dev, + "%s: BG PIL Boot failed\n", __func__); + return ret; + } + ret = wait_for_err_ready(bg_data); + if (ret) { + dev_err(bg_data->desc.dev, + "[%s:%d]: Timed out waiting for error ready: %s!\n", + current->comm, current->pid, bg_data->desc.name); + return ret; + } + return ret; +} + +/** + * bg_shutdown() - Called by SSR framework on userspace invocation. + * disable status interrupt to avoid spurious signal during PRM exit. + * @subsys: struct containing private BG data. + * @force_stop: unused + * + * Return: always success + */ +static int bg_shutdown(const struct subsys_desc *subsys, bool force_stop) +{ + struct pil_bg_data *bg_data = subsys_to_data(subsys); + + if (bg_data->is_ready) { + disable_irq(bg_data->status_irq); + devm_free_irq(bg_data->desc.dev, bg_data->status_irq, bg_data); + disable_irq(bg_data->errfatal_irq); + bg_data->is_ready = false; + } + return 0; +} + +/** + * bg_auth_metadata() - Called by Peripheral loader framework + * send command to tz app for authentication of metadata. + * @pil: pil descriptor. + * @metadata: metadata load address + * @size: size of metadata + * + * Return: 0 on success. Error code on failure. + */ +static int bg_auth_metadata(struct pil_desc *pil, + const u8 *metadata, size_t size) +{ + struct pil_bg_data *bg_data = desc_to_data(pil); + struct tzapp_bg_req bg_tz_req; + void *mdata_buf; + dma_addr_t mdata_phys; + unsigned long attrs = 0; + struct device dev = {0}; + int ret; + + arch_setup_dma_ops(&dev, 0, 0, NULL, 0); + + dev.coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8); + attrs |= DMA_ATTR_STRONGLY_ORDERED; + mdata_buf = dma_alloc_attrs(&dev, size, + &mdata_phys, GFP_KERNEL, attrs); + + if (!mdata_buf) { + pr_err("BG_PIL: Allocation for metadata failed.\n"); + return -ENOMEM; + } + + /* Make sure there are no mappings in PKMAP and fixmap */ + kmap_flush_unused(); + kmap_atomic_flush_unused(); + + memcpy(mdata_buf, metadata, size); + + bg_tz_req.tzapp_bg_cmd = BGPIL_AUTH_MDT; + bg_tz_req.address_fw = (phys_addr_t)mdata_phys; + bg_tz_req.size_fw = size; + + ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); + if (ret || bg_data->cmd_status) { + dev_err(pil->dev, + "%s: BGPIL_AUTH_MDT qseecom call failed\n", + __func__); + return bg_data->cmd_status; + } + dma_free_attrs(&dev, size, mdata_buf, mdata_phys, attrs); + pr_debug("BG MDT Authenticated\n"); + return 0; +} + +/** + * bg_get_firmware_addr() - Called by Peripheral loader framework + * to get address and size of bg firmware binaries. + * @pil: pil descriptor. + * @addr: fw load address + * @size: size of fw + * + * Return: 0 on success. + */ +static int bg_get_firmware_addr(struct pil_desc *pil, + phys_addr_t addr, size_t size) +{ + struct pil_bg_data *bg_data = desc_to_data(pil); + + bg_data->address_fw = addr; + bg_data->size_fw = size; + pr_debug("BG PIL loads firmware blobs at 0x%x with size 0x%x\n", + addr, size); + return 0; +} + +static int bg_get_version(const struct subsys_desc *subsys) +{ + struct pil_bg_data *bg_data = subsys_to_data(subsys); + struct pil_desc desc = bg_data->desc; + struct tzapp_bg_req bg_tz_req; + int ret; + struct device dev = {NULL}; + + arch_setup_dma_ops(&dev, 0, 0, NULL, 0); + + desc.attrs = 0; + desc.attrs |= DMA_ATTR_SKIP_ZEROING; + desc.attrs |= DMA_ATTR_STRONGLY_ORDERED; + + + bg_tz_req.tzapp_bg_cmd = BGPIL_GET_BG_VERSION; + + ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); + if (ret || bg_data->cmd_status) { + dev_dbg(desc.dev, "%s: BG PIL get BG version failed error %d\n", + __func__, bg_data->cmd_status); + return bg_data->cmd_status; + } + + return 0; +} + +/** + * bg_auth_and_xfer() - Called by Peripheral loader framework + * to signal tz app to authenticate and boot bg chip. + * @pil: pil descriptor. + * + * Return: 0 on success. Error code on failure. + */ +static int bg_auth_and_xfer(struct pil_desc *pil) +{ + struct pil_bg_data *bg_data = desc_to_data(pil); + struct tzapp_bg_req bg_tz_req; + int ret; + + bg_tz_req.tzapp_bg_cmd = BGPIL_IMAGE_LOAD; + bg_tz_req.address_fw = bg_data->address_fw; + bg_tz_req.size_fw = bg_data->size_fw; + + ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); + if (bg_data->cmd_status == BG_CRASH_IN_TWM) { + /* Do ramdump and resend boot cmd */ + if (is_twm_exit()) + bg_data->subsys_desc.ramdump(true, + &bg_data->subsys_desc); + + bg_tz_req.tzapp_bg_cmd = BGPIL_DLOAD_CONT; + ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); + } + if (ret || bg_data->cmd_status) { + dev_err(pil->dev, + "%s: BGPIL_IMAGE_LOAD qseecom call failed\n", + __func__); + pil_free_memory(&bg_data->desc); + return bg_data->cmd_status; + } + ret = bg_get_version(&bg_data->subsys_desc); + /* BG Transfer of image is complete, free up the memory */ + pr_debug("BG Firmware authentication and transfer done\n"); + pil_free_memory(&bg_data->desc); + return 0; +} + +/** + * bg_ramdump() - Called by SSR framework to save dump of BG internal + * memory, BG PIL does allocate region from dynamic memory and pass this + * region to tz to dump memory content of BG. + * @subsys: subsystem descriptor. + * + * Return: 0 on success. Error code on failure. + */ +static int bg_ramdump(int enable, const struct subsys_desc *subsys) +{ + struct pil_bg_data *bg_data = subsys_to_data(subsys); + struct pil_desc desc = bg_data->desc; + struct ramdump_segment *ramdump_segments; + struct tzapp_bg_req bg_tz_req; + phys_addr_t start_addr; + void *region; + int ret; + struct device dev = {0}; + + arch_setup_dma_ops(&dev, 0, 0, NULL, 0); + + desc.attrs = 0; + desc.attrs |= DMA_ATTR_SKIP_ZEROING; + desc.attrs |= DMA_ATTR_STRONGLY_ORDERED; + + region = dma_alloc_attrs(desc.dev, BG_RAMDUMP_SZ, + &start_addr, GFP_KERNEL, desc.attrs); + + if (region == NULL) { + dev_dbg(desc.dev, + "BG PIL failure to allocate ramdump region of size %zx\n", + BG_RAMDUMP_SZ); + return -ENOMEM; + } + + ramdump_segments = kcalloc(1, sizeof(*ramdump_segments), GFP_KERNEL); + if (!ramdump_segments) + return -ENOMEM; + + bg_tz_req.tzapp_bg_cmd = BGPIL_RAMDUMP; + bg_tz_req.address_fw = start_addr; + bg_tz_req.size_fw = BG_RAMDUMP_SZ; + + ret = bgpil_tzapp_comm(bg_data, &bg_tz_req); + if (ret || bg_data->cmd_status) { + dev_dbg(desc.dev, "%s: BG PIL ramdump collection failed\n", + __func__); + return bg_data->cmd_status; + } + + ramdump_segments->address = start_addr; + ramdump_segments->size = BG_RAMDUMP_SZ; + + do_ramdump(bg_data->ramdump_dev, ramdump_segments, 1); + kfree(ramdump_segments); + dma_free_attrs(desc.dev, BG_RAMDUMP_SZ, region, + start_addr, desc.attrs); + return 0; +} + +static struct pil_reset_ops pil_ops_trusted = { + .init_image = bg_auth_metadata, + .mem_setup = bg_get_firmware_addr, + .auth_and_reset = bg_auth_and_xfer, + .shutdown = NULL, + .proxy_vote = NULL, + .proxy_unvote = NULL, +}; + +/** + * bg_restart_work() - scheduled by interrupt handler to carry + * out ssr sequence + * @work: work struct. + * + * Return: none. + */ +static void bg_restart_work(struct work_struct *work) +{ + struct pil_bg_data *drvdata = + container_of(work, struct pil_bg_data, restart_work); + subsystem_restart_dev(drvdata->subsys); +} + +static irqreturn_t bg_errfatal(int irq, void *dev_id) +{ + struct pil_bg_data *drvdata = (struct pil_bg_data *)dev_id; + + if (!drvdata) + return IRQ_HANDLED; + + dev_dbg(drvdata->desc.dev, "BG s/w err fatal\n"); + + queue_work(drvdata->bg_queue, &drvdata->restart_work); + + return IRQ_HANDLED; +} + +static irqreturn_t bg_status_change(int irq, void *dev_id) +{ + bool value; + struct pil_bg_data *drvdata = (struct pil_bg_data *)dev_id; + + if (!drvdata) + return IRQ_HANDLED; + + value = gpio_get_value(drvdata->gpios[0]); + if (value == true && !drvdata->is_ready) { + dev_info(drvdata->desc.dev, + "BG services are up and running: irq state changed 0->1\n"); + drvdata->is_ready = true; + complete(&drvdata->err_ready); + } else if (value == false && drvdata->is_ready) { + dev_err(drvdata->desc.dev, + "BG got unexpected reset: irq state changed 1->0\n"); + queue_work(drvdata->bg_queue, &drvdata->restart_work); + } else { + dev_err(drvdata->desc.dev, + "BG status irq: unknown status\n"); + } + + return IRQ_HANDLED; +} + +/** + * setup_bg_gpio_irq() - called in probe to configure input/ + * output gpio. + * @drvdata: private data struct for BG. + * + * Return: 0 on success. Error code on failure. + */ +static int setup_bg_gpio_irq(struct platform_device *pdev, + struct pil_bg_data *drvdata) +{ + int ret = -1; + int irq, i; + + if (gpio_request(drvdata->gpios[0], "BG2AP_STATUS")) { + dev_err(&pdev->dev, + "%s Failed to configure BG2AP_STATUS gpio\n", + __func__); + goto err; + } + if (gpio_request(drvdata->gpios[1], "BG2AP_ERRFATAL")) { + dev_err(&pdev->dev, + "%s Failed to configure BG2AP_ERRFATAL gpio\n", + __func__); + goto err; + } + gpio_direction_input(drvdata->gpios[0]); + gpio_direction_input(drvdata->gpios[1]); + /* BG2AP STATUS IRQ */ + irq = gpio_to_irq(drvdata->gpios[0]); + if (irq < 0) { + dev_err(&pdev->dev, + "%s: bad BG2AP_STATUS IRQ resource, err = %d\n", + __func__, irq); + goto err; + } + + drvdata->status_irq = irq; + /* BG2AP ERR_FATAL irq. */ + irq = gpio_to_irq(drvdata->gpios[1]); + if (irq < 0) { + dev_err(&pdev->dev, "bad BG2AP_ERRFATAL IRQ resource\n"); + goto err; + } + ret = request_irq(irq, bg_errfatal, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, "bg2ap_errfatal", drvdata); + if (ret < 0) { + dev_err(&pdev->dev, + "%s: BG2AP_ERRFATAL IRQ#%d request failed,\n", + __func__, irq); + goto err; + } + drvdata->errfatal_irq = irq; + /* Configure outgoing GPIO's */ + if (gpio_request(drvdata->gpios[2], "AP2BG_ERRFATAL")) { + dev_err(&pdev->dev, + "%s Failed to configure AP2BG_ERRFATAL gpio\n", + __func__); + goto err; + } + if (gpio_request(drvdata->gpios[3], "AP2BG_STATUS")) { + dev_err(&pdev->dev, + "%s Failed to configure AP2BG_STATUS gpio\n", + __func__); + goto err; + } + /* + * Put status gpio in default high state which will + * make transition to low on any sudden reset case of msm + */ + gpio_direction_output(drvdata->gpios[2], 0); + gpio_direction_output(drvdata->gpios[3], 1); + /* Inform BG that AP is up */ + gpio_set_value(drvdata->gpios[3], 1); + return 0; +err: + for (i = 0; i < NUM_GPIOS; ++i) { + if (gpio_is_valid(drvdata->gpios[i])) + gpio_free(drvdata->gpios[i]); + } + return ret; +} + +/** + * bg_dt_parse_gpio() - called in probe to parse gpio's + * @drvdata: private data struct for BG. + * + * Return: 0 on success. Error code on failure. + */ +static int bg_dt_parse_gpio(struct platform_device *pdev, + struct pil_bg_data *drvdata) +{ + int i, val; + + for (i = 0; i < NUM_GPIOS; i++) + drvdata->gpios[i] = INVALID_GPIO; + val = of_get_named_gpio(pdev->dev.of_node, + "qcom,bg2ap-status-gpio", 0); + if (val >= 0) + drvdata->gpios[0] = val; + else { + pr_err("BG status gpio not found, error=%d\n", val); + return -EINVAL; + } + val = of_get_named_gpio(pdev->dev.of_node, + "qcom,bg2ap-errfatal-gpio", 0); + if (val >= 0) + drvdata->gpios[1] = val; + else { + pr_err("BG err-fatal gpio not found, error=%d\n", val); + return -EINVAL; + } + val = of_get_named_gpio(pdev->dev.of_node, + "qcom,ap2bg-errfatal-gpio", 0); + if (val >= 0) + drvdata->gpios[2] = val; + else { + pr_err("ap2bg err-fatal gpio not found, error=%d\n", val); + return -EINVAL; + } + val = of_get_named_gpio(pdev->dev.of_node, + "qcom,ap2bg-status-gpio", 0); + if (val >= 0) + drvdata->gpios[3] = val; + else { + pr_err("ap2bg status gpio not found, error=%d\n", val); + return -EINVAL; + } + return 0; +} + +static int pil_bg_driver_probe(struct platform_device *pdev) +{ + struct pil_bg_data *bg_data; + int rc; + + bg_data = devm_kzalloc(&pdev->dev, sizeof(*bg_data), GFP_KERNEL); + if (!bg_data) + return -ENOMEM; + platform_set_drvdata(pdev, bg_data); + rc = of_property_read_string(pdev->dev.of_node, + "qcom,firmware-name", &bg_data->desc.name); + if (rc) + return rc; + bg_data->desc.dev = &pdev->dev; + bg_data->desc.owner = THIS_MODULE; + bg_data->desc.ops = &pil_ops_trusted; + rc = pil_desc_init(&bg_data->desc); + if (rc) + return rc; + /* Read gpio configuration */ + rc = bg_dt_parse_gpio(pdev, bg_data); + if (rc) + return rc; + rc = setup_bg_gpio_irq(pdev, bg_data); + if (rc < 0) + return rc; + bg_data->subsys_desc.name = bg_data->desc.name; + bg_data->subsys_desc.owner = THIS_MODULE; + bg_data->subsys_desc.dev = &pdev->dev; + bg_data->subsys_desc.shutdown = bg_shutdown; + bg_data->subsys_desc.powerup = bg_powerup; + bg_data->subsys_desc.ramdump = bg_ramdump; + bg_data->subsys_desc.free_memory = NULL; + bg_data->subsys_desc.crash_shutdown = bg_app_shutdown_notify; + bg_data->ramdump_dev = + create_ramdump_device(bg_data->subsys_desc.name, &pdev->dev); + if (!bg_data->ramdump_dev) { + rc = -ENOMEM; + goto err_ramdump; + } + bg_data->subsys = subsys_register(&bg_data->subsys_desc); + if (IS_ERR(bg_data->subsys)) { + rc = PTR_ERR(bg_data->subsys); + goto err_subsys; + } + + bg_data->reboot_blk.notifier_call = bg_app_reboot_notify; + register_reboot_notifier(&bg_data->reboot_blk); + + bg_data->bg_queue = alloc_workqueue("bg_queue", 0, 0); + if (!bg_data->bg_queue) { + dev_err(&pdev->dev, "could not create bg_queue\n"); + subsys_unregister(bg_data->subsys); + goto err_subsys; + } + INIT_WORK(&bg_data->restart_work, bg_restart_work); + return 0; +err_subsys: + destroy_ramdump_device(bg_data->ramdump_dev); +err_ramdump: + pil_desc_release(&bg_data->desc); + return rc; +} + +static int pil_bg_driver_exit(struct platform_device *pdev) +{ + struct pil_bg_data *bg_data = platform_get_drvdata(pdev); + + subsys_unregister(bg_data->subsys); + destroy_ramdump_device(bg_data->ramdump_dev); + pil_desc_release(&bg_data->desc); + + return 0; +} + +const struct of_device_id pil_bg_match_table[] = { + {.compatible = "qcom,pil-blackghost"}, + {} +}; + +static struct platform_driver pil_bg_driver = { + .probe = pil_bg_driver_probe, + .remove = pil_bg_driver_exit, + .driver = { + .name = "subsys-pil-bg", + .of_match_table = pil_bg_match_table, + .owner = THIS_MODULE, + }, +}; + +static int __init pil_bg_init(void) +{ + return platform_driver_register(&pil_bg_driver); +} +module_init(pil_bg_init); + +static void __exit pil_bg_exit(void) +{ + platform_driver_unregister(&pil_bg_driver); +} +module_exit(pil_bg_exit); + +MODULE_DESCRIPTION("Support for booting QTI Blackghost SoC"); +MODULE_LICENSE("GPL v2"); -- GitLab From 0c45151d731e84f3ae90ca477db1947854aff58e Mon Sep 17 00:00:00 2001 From: Naitik Bharadiya Date: Mon, 22 Jun 2020 12:09:33 +0530 Subject: [PATCH 0952/1055] defconfig: enable cpufreq stats config Currently, can't get cpufreq stats in sysfs node of cpufreq/stat, and this sysfs is signifcant for debug and test. So enable it for sdmsteppe, atoll, sm8150, trinket targets. Change-Id: I339ec5dc1619d359faa5323708eef9a73ede6adb Signed-off-by: Naitik Bharadiya --- arch/arm64/configs/vendor/atoll-perf_defconfig | 1 + arch/arm64/configs/vendor/atoll_defconfig | 1 + arch/arm64/configs/vendor/sdmsteppe-perf_defconfig | 1 + arch/arm64/configs/vendor/sdmsteppe_defconfig | 1 + arch/arm64/configs/vendor/trinket-perf_defconfig | 1 + arch/arm64/configs/vendor/trinket_defconfig | 1 + 6 files changed, 6 insertions(+) diff --git a/arch/arm64/configs/vendor/atoll-perf_defconfig b/arch/arm64/configs/vendor/atoll-perf_defconfig index 2e005fecf38e..79f67c9a8350 100644 --- a/arch/arm64/configs/vendor/atoll-perf_defconfig +++ b/arch/arm64/configs/vendor/atoll-perf_defconfig @@ -90,6 +90,7 @@ CONFIG_PM_WAKELOCKS_LIMIT=0 CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y diff --git a/arch/arm64/configs/vendor/atoll_defconfig b/arch/arm64/configs/vendor/atoll_defconfig index 868e40ce5ec0..b3b4b1bb63dd 100644 --- a/arch/arm64/configs/vendor/atoll_defconfig +++ b/arch/arm64/configs/vendor/atoll_defconfig @@ -96,6 +96,7 @@ CONFIG_PM_DEBUG=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y diff --git a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig index ace282a41b0b..e2f05898a64f 100644 --- a/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe-perf_defconfig @@ -86,6 +86,7 @@ CONFIG_PM_WAKELOCKS_LIMIT=0 CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y diff --git a/arch/arm64/configs/vendor/sdmsteppe_defconfig b/arch/arm64/configs/vendor/sdmsteppe_defconfig index d796e2fe093e..3af82be958c2 100644 --- a/arch/arm64/configs/vendor/sdmsteppe_defconfig +++ b/arch/arm64/configs/vendor/sdmsteppe_defconfig @@ -92,6 +92,7 @@ CONFIG_PM_DEBUG=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y diff --git a/arch/arm64/configs/vendor/trinket-perf_defconfig b/arch/arm64/configs/vendor/trinket-perf_defconfig index 74a054f6473d..8b34e9fd3e20 100644 --- a/arch/arm64/configs/vendor/trinket-perf_defconfig +++ b/arch/arm64/configs/vendor/trinket-perf_defconfig @@ -89,6 +89,7 @@ CONFIG_PM_WAKELOCKS_LIMIT=0 CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y diff --git a/arch/arm64/configs/vendor/trinket_defconfig b/arch/arm64/configs/vendor/trinket_defconfig index 0e05ff519201..714b5cfa7d80 100644 --- a/arch/arm64/configs/vendor/trinket_defconfig +++ b/arch/arm64/configs/vendor/trinket_defconfig @@ -96,6 +96,7 @@ CONFIG_PM_DEBUG=y CONFIG_CPU_IDLE=y CONFIG_ARM_CPUIDLE=y CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_TIMES=y CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y -- GitLab From 3d8897974e213e179d8d52d92fcab22445e64966 Mon Sep 17 00:00:00 2001 From: Srinivasarao P Date: Mon, 29 Jun 2020 13:00:20 +0530 Subject: [PATCH 0953/1055] Revert "Revert "ANDROID: security,perf: Allow further restriction of perf_event_open"" This reverts commit 44a6aea9c219f55862776435b918c539855a9e69. Change-Id: I6ee8a29e5e784c06c65b65302ad726651ded45b8 Signed-off-by: Srinivasarao P --- Documentation/sysctl/kernel.txt | 4 +++- arch/arm64/configs/cuttlefish_defconfig | 1 + arch/x86/configs/x86_64_cuttlefish_defconfig | 1 + include/linux/perf_event.h | 5 +++++ kernel/events/core.c | 8 ++++++++ security/Kconfig | 9 +++++++++ 6 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 694968c7523c..b757d6eb365b 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -653,7 +653,8 @@ allowed to execute. perf_event_paranoid: Controls use of the performance events system by unprivileged -users (without CAP_SYS_ADMIN). The default value is 2. +users (without CAP_SYS_ADMIN). The default value is 3 if +CONFIG_SECURITY_PERF_EVENTS_RESTRICT is set, or 2 otherwise. -1: Allow use of (almost) all events by all users Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK @@ -661,6 +662,7 @@ users (without CAP_SYS_ADMIN). The default value is 2. Disallow raw tracepoint access by users without CAP_SYS_ADMIN >=1: Disallow CPU event access by users without CAP_SYS_ADMIN >=2: Disallow kernel profiling by users without CAP_SYS_ADMIN +>=3: Disallow all event access by users without CAP_SYS_ADMIN ============================================================== diff --git a/arch/arm64/configs/cuttlefish_defconfig b/arch/arm64/configs/cuttlefish_defconfig index d0a8c06670c1..9441c7e5cbb8 100644 --- a/arch/arm64/configs/cuttlefish_defconfig +++ b/arch/arm64/configs/cuttlefish_defconfig @@ -460,6 +460,7 @@ CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y CONFIG_RCU_CPU_STALL_TIMEOUT=60 CONFIG_ENABLE_DEFAULT_TRACERS=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_LSM_MMAP_MIN_ADDR=65536 diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig index 022325173f80..b45552bbd150 100644 --- a/arch/x86/configs/x86_64_cuttlefish_defconfig +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -488,6 +488,7 @@ CONFIG_IO_DELAY_NONE=y CONFIG_DEBUG_BOOT_PARAMS=y CONFIG_OPTIMIZE_INLINING=y CONFIG_UNWINDER_FRAME_POINTER=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_PATH=y diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index ff924b5fd0b8..5d798eb5ac0a 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1187,6 +1187,11 @@ int perf_event_max_stack_handler(struct ctl_table *table, int write, #define PERF_SECURITY_KERNEL 2 #define PERF_SECURITY_TRACEPOINT 3 +static inline bool perf_paranoid_any(void) +{ + return sysctl_perf_event_paranoid > 2; +} + static inline int perf_is_paranoid(void) { return sysctl_perf_event_paranoid > -1; diff --git a/kernel/events/core.c b/kernel/events/core.c index 32869eafd241..1e22c6eb5fb3 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -397,8 +397,13 @@ static cpumask_var_t perf_online_mask; * 0 - disallow raw tracepoint access for unpriv * 1 - disallow cpu events for unpriv * 2 - disallow kernel profiling for unpriv + * 3 - disallow all unpriv perf event use */ +#ifdef CONFIG_SECURITY_PERF_EVENTS_RESTRICT +int sysctl_perf_event_paranoid __read_mostly = 3; +#else int sysctl_perf_event_paranoid __read_mostly = 2; +#endif /* Minimum for 512 kiB + 1 user control page */ int sysctl_perf_event_mlock __read_mostly = 512 + (PAGE_SIZE / 1024); /* 'free' kiB per user */ @@ -10052,6 +10057,9 @@ SYSCALL_DEFINE5(perf_event_open, if (flags & ~PERF_FLAG_ALL) return -EINVAL; + if (perf_paranoid_any() && !capable(CAP_SYS_ADMIN)) + return -EACCES; + /* Do we allow access to perf_event_open(2) ? */ err = security_perf_event_open(&attr, PERF_SECURITY_OPEN); if (err) diff --git a/security/Kconfig b/security/Kconfig index 3a66cd8363c0..8b6c5e9528e0 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -18,6 +18,15 @@ config SECURITY_DMESG_RESTRICT If you are unsure how to answer this question, answer N. +config SECURITY_PERF_EVENTS_RESTRICT + bool "Restrict unprivileged use of performance events" + depends on PERF_EVENTS + help + If you say Y here, the kernel.perf_event_paranoid sysctl + will be set to 3 by default, and no unprivileged use of the + perf_event_open syscall will be permitted unless it is + changed. + config SECURITY bool "Enable different security models" depends on SYSFS -- GitLab From 128ce07d3e709bebb4be383cba9d1ffda2bbbfc3 Mon Sep 17 00:00:00 2001 From: Tengfei Fan Date: Mon, 19 Nov 2018 13:45:29 +0800 Subject: [PATCH 0954/1055] pinctrl: qcom: Clear status bit on irq_unmask The gpio interrupt status bit is getting set after the irq is disabled and causing an immediate interrupt after enablling the irq, so clear status bit on irq_unmask. Change-Id: I89245b90b06b37671369e59c15fb24a991cc114a Signed-off-by: Tengfei Fan --- drivers/pinctrl/qcom/pinctrl-msm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 2eec26f7fbd5..b6a6aa007f19 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -750,6 +750,7 @@ static void msm_gpio_irq_enable(struct irq_data *d) static void msm_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + uint32_t irqtype = irqd_get_trigger_type(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); const struct msm_pingroup *g; unsigned long flags; @@ -761,6 +762,12 @@ static void msm_gpio_irq_unmask(struct irq_data *d) raw_spin_lock_irqsave(&pctrl->lock, flags); + if (irqtype & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) { + val = readl_relaxed(pctrl->regs + g->intr_status_reg); + val &= ~BIT(g->intr_status_bit); + writel_relaxed(val, pctrl->regs + g->intr_status_reg); + } + val = readl(base + g->intr_cfg_reg); val |= BIT(g->intr_enable_bit); writel(val, base + g->intr_cfg_reg); -- GitLab From ad91dd309909603178b0c38c1f5162d844e1d565 Mon Sep 17 00:00:00 2001 From: Chandrasekhar Mattaparthy Date: Mon, 29 Jun 2020 16:31:00 +0530 Subject: [PATCH 0955/1055] sdm429w: modify copy right year as per guidelines modify copy right year as per guidelines in bgcom interface header file. Change-Id: I25564401920bce7237eee021cdf4f700daf03429 Signed-off-by: Chandrasekhar Mattaparthy --- drivers/soc/qcom/bgcom_interface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/bgcom_interface.h b/drivers/soc/qcom/bgcom_interface.h index 7568adca6ce4..198cbb71f183 100644 --- a/drivers/soc/qcom/bgcom_interface.h +++ b/drivers/soc/qcom/bgcom_interface.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2019,2020 The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020 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 -- GitLab From accc87f2c9d62d4fd7b3057708e36ef23c1ddf4c Mon Sep 17 00:00:00 2001 From: Sudarshan Rajagopalan Date: Fri, 10 May 2019 21:34:05 -0700 Subject: [PATCH 0956/1055] dma-mapping-fast: Fix erroneous MAIR idx calculation Fix the erroneous PTE MAIR calculation by using the right operator. Change-Id: I061b4e9f7599d0f43001adfb531b58e3bfd1a3c8 Signed-off-by: Sudarshan Rajagopalan --- drivers/iommu/io-pgtable-fast.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c index 8f26083ba76a..5a5d597a00a6 100644 --- a/drivers/iommu/io-pgtable-fast.c +++ b/drivers/iommu/io-pgtable-fast.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -150,7 +150,7 @@ struct av8l_fast_io_pgtable { #define AV8L_FAST_PAGE_SHIFT 12 #define PTE_MAIR_IDX(pte) \ - ((pte >> AV8L_FAST_PTE_ATTRINDX_SHIFT) && \ + ((pte >> AV8L_FAST_PTE_ATTRINDX_SHIFT) & \ AV8L_FAST_PTE_ATTRINDX_MASK) #define PTE_SH_IDX(pte) (pte & AV8L_FAST_PTE_SH_MASK) -- GitLab From 08c9816bf3c697d3bb211da90e5c00f7ec2598a7 Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Mon, 8 Jun 2020 22:50:35 -0700 Subject: [PATCH 0957/1055] msm: ethernet : smmu: enable qcom smmu Providing client API to attach smmu Change-Id: I97708a58686a1446651d59bb049e300fac3c52c5 Signed-off-by: Sunil Paidimarri --- .../configs/vendor/sdxprairie-perf_defconfig | 1 + arch/arm/configs/vendor/sdxprairie_defconfig | 1 + drivers/platform/msm/Kconfig | 7 + drivers/platform/msm/Makefile | 1 + drivers/platform/msm/ethernet/Makefile | 1 + drivers/platform/msm/ethernet/qcom_eth_smmu.c | 243 ++++++++++++++++++ include/linux/qcom_eth_smmu.h | 24 ++ 7 files changed, 278 insertions(+) create mode 100644 drivers/platform/msm/ethernet/Makefile create mode 100644 drivers/platform/msm/ethernet/qcom_eth_smmu.c create mode 100644 include/linux/qcom_eth_smmu.h diff --git a/arch/arm/configs/vendor/sdxprairie-perf_defconfig b/arch/arm/configs/vendor/sdxprairie-perf_defconfig index 548d0dae0430..6112f6f96f35 100644 --- a/arch/arm/configs/vendor/sdxprairie-perf_defconfig +++ b/arch/arm/configs/vendor/sdxprairie-perf_defconfig @@ -360,6 +360,7 @@ CONFIG_RMNET_IPA3=y CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y +CONFIG_QCOM_ETHERNET_UTIL=y CONFIG_SPMI_PMIC_CLKDIV=y CONFIG_MSM_CLK_AOP_QMP=y CONFIG_MSM_CLK_RPMH=y diff --git a/arch/arm/configs/vendor/sdxprairie_defconfig b/arch/arm/configs/vendor/sdxprairie_defconfig index 50fa20b02e8a..f12f3835088f 100644 --- a/arch/arm/configs/vendor/sdxprairie_defconfig +++ b/arch/arm/configs/vendor/sdxprairie_defconfig @@ -371,6 +371,7 @@ CONFIG_RMNET_IPA3=y CONFIG_ECM_IPA=y CONFIG_RNDIS_IPA=y CONFIG_IPA_UT=y +CONFIG_QCOM_ETHERNET_UTIL=y CONFIG_SPMI_PMIC_CLKDIV=y CONFIG_MSM_CLK_AOP_QMP=y CONFIG_MSM_CLK_RPMH=y diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig index 5b7d70823b2f..25893daa6886 100644 --- a/drivers/platform/msm/Kconfig +++ b/drivers/platform/msm/Kconfig @@ -298,6 +298,13 @@ config IPA3_REGDUMP This option is to be used when the saving of IPA/GSI register state is desired upon system crash. +config QCOM_ETHERNET_UTIL + bool "ethernet utilities" + depends on PCI + help + This module will provide API's for clients to attach smmu & + other functionalities + choice prompt "Platform whose registers are to be dumped/collected" depends on IPA3_REGDUMP diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile index 2bc4e11a77e5..05cf004e10b7 100644 --- a/drivers/platform/msm/Makefile +++ b/drivers/platform/msm/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_MSM_MHI_DEV) += mhi_dev/ obj-$(CONFIG_MSM_11AD) += msm_11ad/ obj-$(CONFIG_SEEMP_CORE) += seemp_core/ obj-$(CONFIG_VETH_IPA) += veth_ipa/ +obj-$(CONFIG_QCOM_ETHERNET_UTIL) += ethernet/ diff --git a/drivers/platform/msm/ethernet/Makefile b/drivers/platform/msm/ethernet/Makefile new file mode 100644 index 000000000000..bda2e6f994c3 --- /dev/null +++ b/drivers/platform/msm/ethernet/Makefile @@ -0,0 +1 @@ +obj-y += qcom_eth_smmu.o diff --git a/drivers/platform/msm/ethernet/qcom_eth_smmu.c b/drivers/platform/msm/ethernet/qcom_eth_smmu.c new file mode 100644 index 000000000000..e42332609cd7 --- /dev/null +++ b/drivers/platform/msm/ethernet/qcom_eth_smmu.c @@ -0,0 +1,243 @@ +/* Copyright (c) 2020 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 + +static int (*vendor_probe_real)(struct pci_dev *, const struct pci_device_id *); +static void (*vendor_remove_real)(struct pci_dev *); + +static int qcom_parse_smmu_attr(struct device *dev, + struct iommu_domain *domain, + const char *key, + enum iommu_attr attr) +{ + int rc = 0; + unsigned int data = 1; + + if (of_find_property(dev->of_node, key, NULL)) { + rc = iommu_domain_set_attr(domain, attr, &data); + if (!rc) + dev_dbg(dev, "enabled SMMU attribute %u\n", attr); + else + dev_err(dev, "failed to set SMMU attribute %u\n", attr); + } + + return rc; +} + +static int qcom_parse_smmu_attrs(struct device *dev, + struct iommu_domain *domain) +{ + int rc = 0; + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-s1-bypass", DOMAIN_ATTR_S1_BYPASS); + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-fastmap", DOMAIN_ATTR_FAST); + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-atomic", DOMAIN_ATTR_ATOMIC); + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-pt-coherent", + DOMAIN_ATTR_PAGE_TABLE_IS_COHERENT); + + rc |= qcom_parse_smmu_attr(dev, domain, + "qcom,smmu-attr-pt-coherent-force", + DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT); + + return rc; +} + +static int __qcom_attach_smmu(struct device *dev) +{ + int rc; + const char *key; + u64 val64; + + dma_addr_t iova_base = 0; + u64 iova_size = 0; + + struct dma_iommu_mapping *mapping = NULL; + + key = "qcom,smmu-iova-base"; + rc = of_property_read_u64(dev->of_node, key, &val64); + if (rc) { + dev_err(dev, "error parsing DT prop %s: %d\n", key, rc); + return rc; + } + + iova_base = (dma_addr_t)val64; + + key = "qcom,smmu-iova-size"; + rc = of_property_read_u64(dev->of_node, key, &val64); + if (rc) { + dev_err(dev, "error parsing DT prop %s: %d\n", key, rc); + return rc; + } + + iova_size = val64; + + dev_dbg(dev, "creating SMMU mapping with base=0x%llx, size=0x%llx\n", + iova_base, iova_size); + + mapping = arm_iommu_create_mapping(dev->bus, iova_base, iova_size); + if (IS_ERR(mapping)) { + dev_err(dev, "failed to create SMMU mapping\n"); + return PTR_ERR(mapping); + } + + rc = qcom_parse_smmu_attrs(dev, mapping->domain); + if (rc) { + dev_err(dev, "error parsing SMMU DT attributes\n"); + goto err_release_mapping; + } + + rc = arm_iommu_attach_device(dev, mapping); + if (rc) { + dev_err(dev, "failed to attach device to smmu\n"); + goto err_release_mapping; + } + + return 0; + +err_release_mapping: + arm_iommu_release_mapping(mapping); + return rc; +} + +static int qcom_attach_smmu(struct device *dev) +{ + bool dt_present = !!of_find_property(dev->of_node, "qcom,smmu", NULL); + bool smmu_attached = !!iommu_get_domain_for_dev(dev); + + if (smmu_attached) { + /* On platforms where IOMMU is attached automatically, we do + * not expect qcom,smmu property to be present in devicetree. + */ + if (dt_present) { + dev_err(dev, "SMMU DT node is not expected\n"); + return -EEXIST; + } + + return 0; + } + + if (!dt_present) { + dev_err(dev, "SMMU DT is required for the device\n"); + return -EFAULT; + } + + return __qcom_attach_smmu(dev); +} + +static void qcom_detach_smmu(struct device *dev) +{ + bool dt_present = !!of_find_property(dev->of_node, "qcom,smmu", NULL); + bool smmu_attached = !!iommu_get_domain_for_dev(dev); + + /* Perform a manual deattach only if we were tasked with doing the + * attach originally. + */ + if (dt_present && smmu_attached) { + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + + if (!mapping) { + dev_err(dev, "Failed to retrieve IOMMU mapping\n"); + return; + } + + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(mapping); + } +} + +static int vendor_qcom_probe( + struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int rc; + + rc = qcom_attach_smmu(&pdev->dev); + if (rc) + return rc; + + rc = vendor_probe_real(pdev, id); + if (rc) { + qcom_detach_smmu(&pdev->dev); + return rc; + } + + return 0; +} + +static void vendor_qcom_remove(struct pci_dev *pdev) +{ + vendor_remove_real(pdev); + qcom_detach_smmu(&pdev->dev); +} + +static int __vendor_qcom_register(struct pci_driver *pdrv) +{ + if (vendor_probe_real || vendor_remove_real) { + pr_warn("%s: Driver already registered\n", __func__); + return -EEXIST; + } + + vendor_probe_real = pdrv->probe; + pdrv->probe = vendor_qcom_probe; + + vendor_remove_real = pdrv->remove; + pdrv->remove = vendor_qcom_remove; + + return 0; +} + +static void __vendor_qcom_unregister(struct pci_driver *pdrv) +{ + if (vendor_probe_real) { + pdrv->probe = vendor_probe_real; + vendor_probe_real = NULL; + } + + if (vendor_remove_real) { + pdrv->remove = vendor_remove_real; + vendor_remove_real = NULL; + } +} + +int qcom_smmu_register(struct pci_driver *pdrv) +{ + int rc; + + rc = __vendor_qcom_register(pdrv); + if (rc) + return rc; + + + return 0; +} +EXPORT_SYMBOL(qcom_smmu_register); + +void qcom_smmu_unregister(struct pci_driver *pdrv) +{ + __vendor_qcom_unregister(pdrv); +} +EXPORT_SYMBOL(qcom_smmu_unregister); + diff --git a/include/linux/qcom_eth_smmu.h b/include/linux/qcom_eth_smmu.h new file mode 100644 index 000000000000..53f0a83c648a --- /dev/null +++ b/include/linux/qcom_eth_smmu.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2020 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 _QCOM_ETH_SMMU_H_ +#define _QCOM_ETH_SMMU_H_ + +#include + + +int qcom_smmu_register(struct pci_driver *pdrv); +void qcom_smmu_unregister(struct pci_driver *pdrv); + + +#endif // _QCOM_ETH_SMMU_H_ + -- GitLab From 6c52efca2d58c5719b339b751db94998cd09a7f9 Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Wed, 17 Jun 2020 12:15:40 -0700 Subject: [PATCH 0958/1055] ARM : dts : support realtek r8125 ethernet driver Adding PCI ID's for realtek r8125B hardware Change-Id: I74634e907ea25e74cf56e4f628f83ec7de4b77d1 Signed-off-by: Sunil Paidimarri --- Documentation/devicetree/bindings/net/r8125 | 33 ++++++++++++++++ .../boot/dts/qcom/sdxprairie-qcom-smmu.dtsi | 38 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sdxprairie.dtsi | 1 + 3 files changed, 72 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/r8125 create mode 100644 arch/arm64/boot/dts/qcom/sdxprairie-qcom-smmu.dtsi diff --git a/Documentation/devicetree/bindings/net/r8125 b/Documentation/devicetree/bindings/net/r8125 new file mode 100644 index 000000000000..d302869dbb4b --- /dev/null +++ b/Documentation/devicetree/bindings/net/r8125 @@ -0,0 +1,33 @@ +Realtek r8125B Ethernet Controller + +Required properties: + +- compatible : should be "realtek,rtl-8125" + +If SMMU is present, also use: + +- qcom,smmu : if present, SMMU attach is performed +- qcom,smmu-iova-base : SMMU IOVA start address the device can access +- qcom,smmu-iova-size : SMMU IOVA size the device can access + +Optional Properties: + +- qcom,smmu-attr-fastmap : Enables SMMU fastmap +- qcom,smmu-attr-atomic : Enables DMA alloc using GFP_ATOMIC + +Example: + +&pcie_rc0 { + + r8125_x1: qcom,r8125@0 { + compatible = realtek,rtl-8125"; + + qcom,smmu; + qcom,smmu-iova-base = /bits/ 64 <0x0>; + qcom,smmu-iova-size = /bits/ 64 <0x100000000>; + + qcom,smmu-attr-atomic; + qcom,smmu-attr-fastmap; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-qcom-smmu.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-qcom-smmu.dtsi new file mode 100644 index 000000000000..931dc712da90 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdxprairie-qcom-smmu.dtsi @@ -0,0 +1,38 @@ +/* Copyright (c) 2020, 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. + */ + + +&pcie0_rp { + realtek,rtl8125@pcie0_rp { + reg = <0 0 0 0 0>; + + compatible = "realtek,rtl-8125"; + + pci-ids = + "10ec:8125", + "10ec:3000"; + + qcom,smmu; + + /* IOVA range is restricted to avoid conflicts with PCI BAR + * space, Q6 SMEM and IOVA spaces used by peripherals that are + * currently attached to IPA. + */ + qcom,smmu-iova-base = /bits/ 64 <0x80000000>; + qcom,smmu-iova-size = /bits/ 64 <0x0FE40000>; + + qcom,smmu-attr-atomic; + qcom,smmu-attr-fastmap; + + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index 3b65fa169b0f..745ac272a475 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -1612,6 +1612,7 @@ #include "sdxprairie-coresight.dtsi" #include "sdxprairie-aqc.dtsi" #include "sdxprairie-thermal.dtsi" +#include "sdxprairie-qcom-smmu.dtsi" &gdsc_usb30 { status = "ok"; -- GitLab From b10eb7e7c908f4fe2b9f1361cbe85e63c7e1ae7f Mon Sep 17 00:00:00 2001 From: YUE CHEN Date: Mon, 15 Jun 2020 14:30:53 +0800 Subject: [PATCH 0959/1055] msm: ais: fix cci read return value issue Return 0 if not waiting timeout for both rd_done ack and reset ack. Change-Id: I1c82908761a8855bdeaa6e24eebeaff991183ce1 Signed-off-by: YUE CHEN --- .../msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c index f30c9e49b0ab..45eb1f449d35 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1513,14 +1513,16 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, } else { //If rd_done is complete with NACK wait until RESET_ACK //is received. + rc = 0; if (cci_dev->cci_master_info[master].status == -EINVAL) { rc = wait_for_completion_timeout( &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); - } - if (rc <= 0) { - CAM_ERR(CAM_CCI, - "wait_for_completion_timeout rc = %d, rc"); + if (rc <= 0) { + CAM_ERR(CAM_CCI, + "wait_for_completion_timeout rc = %d, rc"); + } else + rc = 0; } } -- GitLab From 8ee685bf87b46e8b750cb60afd683aa301cbb54c Mon Sep 17 00:00:00 2001 From: Sayali Lokhande Date: Thu, 9 Jan 2020 14:45:19 +0530 Subject: [PATCH 0960/1055] fs: namespace: Fix use-after-free in unmount During unmount, there is a chance that mntput_no_expire() scheduled delayed_mntput_work() or in case MNT_INTERNAL flag is set it can directly call cleanup_mnt(). This results in use-after-free in umount_end check as mnt is already freed via below path : cleanup_mnt()->delayed_free_mnt()->free_vfsmnt(). Fix this by moving unmount_end() before mntput_no_expire. Change-Id: Ib3468ca3b1b3c137484b70972db5d5569f2f2753 Signed-off-by: Sayali Lokhande --- fs/namespace.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 2279475c6e8a..68549a0d1054 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1778,6 +1778,12 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) dput_and_out: /* we mustn't call path_put() as that would clear mnt_expiry_mark */ dput(path.dentry); + if (user_request && (!retval || (flags & MNT_FORCE))) { + /* filesystem needs to handle unclosed namespaces */ + if (mnt->mnt.mnt_sb->s_op->umount_end) + mnt->mnt.mnt_sb->s_op->umount_end(mnt->mnt.mnt_sb, + flags); + } mntput_no_expire(mnt); if (!user_request) @@ -1794,11 +1800,6 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) /* flush delayed_mntput_work to put sb->s_active */ flush_delayed_mntput_wait(); } - if (!retval || (flags & MNT_FORCE)) { - /* filesystem needs to handle unclosed namespaces */ - if (mnt->mnt.mnt_sb->s_op->umount_end) - mnt->mnt.mnt_sb->s_op->umount_end(mnt->mnt.mnt_sb, flags); - } out: return retval; } -- GitLab From 20cdd1b399d315faa2ab81d1d68e46907c821fbc Mon Sep 17 00:00:00 2001 From: Jiten Patel Date: Mon, 29 Jun 2020 12:41:13 +0530 Subject: [PATCH 0961/1055] ARM: dts: msm: add tzlog device node for sdm429 Enable TZ-log device node on include file to enable the TZ-log driver on sdm429 to access TZ diag area. Change-Id: I335fd2f4e4fbb989ffbf6c5c25692909d81711e8 Signed-off-by: Jiten Patel --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 9e709b8e2c27..7b5d19fc4e46 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -892,6 +892,11 @@ }; }; + qcom_tzlog: tz-log@08600720 { + compatible = "qcom,tz-log"; + reg = <0x08600720 0x2000>; + }; + qcom,bam_dmux@4044000 { compatible = "qcom,bam_dmux"; reg = <0x4044000 0x19000>; -- GitLab From 247b52137a68775411afb8fc2c70ba2dd0743e04 Mon Sep 17 00:00:00 2001 From: Siva Kumar Akkireddi Date: Mon, 2 Mar 2020 16:00:13 +0530 Subject: [PATCH 0962/1055] msm: mhi_dev: Do not flush events to host if channel is stopped Do not flush completion events to host when the channel is stopped or closed as the flush function might use invalid data for the channel. Also add a check for channel state in the write API. Change-Id: I0e882fab4891cac60ddbb17f4be1dfeb502ecf92 Signed-off-by: Siva Kumar Akkireddi --- drivers/platform/msm/mhi_dev/mhi.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index b03135b2c195..6f6bd8c5bc4f 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -444,10 +444,11 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi, struct event_req *flush_ereq; /* - * Channel got closed with transfers pending + * Channel got stopped or closed with transfers pending * Do not send completion events to host */ - if (ch->state == MHI_DEV_CH_CLOSED) { + if (ch->state == MHI_DEV_CH_CLOSED || + ch->state == MHI_DEV_CH_STOPPED) { mhi_log(MHI_MSG_DBG, "Ch %d closed with %d writes pending\n", ch->ch_id, ch->pend_wr_count + 1); return -ENODEV; @@ -2124,12 +2125,14 @@ static void mhi_dev_transfer_completion_cb(void *mreq) req->len, DMA_FROM_DEVICE); /* - * Channel got closed with transfers pending + * Channel got stopped or closed with transfers pending * Do not trigger callback or send cmpl to host */ - if (ch->state == MHI_DEV_CH_CLOSED) { - mhi_log(MHI_MSG_DBG, "Ch %d closed with %d writes pending\n", - ch->ch_id, ch->pend_wr_count + 1); + if (ch->state == MHI_DEV_CH_CLOSED || + ch->state == MHI_DEV_CH_STOPPED) { + mhi_log(MHI_MSG_DBG, + "Ch %d not in started state, %d writes pending\n", + ch->ch_id, ch->pend_wr_count + 1); return; } @@ -2976,6 +2979,7 @@ int mhi_dev_write_channel(struct mhi_req *wreq) size_t bytes_written = 0; uint32_t tre_len = 0, suspend_wait_timeout = 0; bool async_wr_sched = false; + enum mhi_ctrl_info info; if (WARN_ON(!wreq || !wreq->client || !wreq->buf)) { pr_err("%s: invalid parameters\n", __func__); @@ -3024,6 +3028,14 @@ int mhi_dev_write_channel(struct mhi_req *wreq) mutex_lock(&ch->ch_lock); + rc = mhi_ctrl_state_info(ch->ch_id, &info); + if (rc || (info != MHI_STATE_CONNECTED)) { + mhi_log(MHI_MSG_ERROR, "Channel %d not started by host\n", + ch->ch_id); + mutex_unlock(&ch->ch_lock); + return -ENODEV; + } + ch->pend_wr_count++; if (ch->state == MHI_DEV_CH_STOPPED) { mhi_log(MHI_MSG_ERROR, -- GitLab From 880a623b66c915adc2a2d68b4bdb5466d31532ca Mon Sep 17 00:00:00 2001 From: Ajay Prathi Date: Fri, 26 Jun 2020 16:38:28 +0530 Subject: [PATCH 0963/1055] msm: sps: Use iomem attribute for base address Clients may use ioremap api to obtain the bam base address. Add iomem attribute to the base address field in the public SPS structure to avoid type casts. Change-Id: Iba2ec1a9d84c3d57e2ce314ba9dc0b81644db2fb Signed-off-by: Ajay Prathi --- include/linux/msm-sps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/msm-sps.h b/include/linux/msm-sps.h index 5002cbd00d21..138537d923fd 100644 --- a/include/linux/msm-sps.h +++ b/include/linux/msm-sps.h @@ -492,7 +492,7 @@ struct sps_bam_props { * */ struct sps_mem_buffer { - void *base; + void __iomem *base; phys_addr_t phys_base; unsigned long iova; u32 size; -- GitLab From fa80c42a5a59651d0994c5e28237fcfbfe634fbd Mon Sep 17 00:00:00 2001 From: Dhanalakshmi Siddani Date: Tue, 4 Feb 2020 22:16:05 +0530 Subject: [PATCH 0964/1055] ASoC: tfa98xx: Add tfa98xx smart PA driver Add tfa9xx driver from https://source.codeaurora.org/external/mas/tfa98xx/?h=DIN_v6.6.3 and adapt it for the kernel directory structure. It includes the following changes: commit 6886738d7d45d05e829319ac09a353acf4eb39c4 Author: Mehdi Chemsi Updating optimal settings of TFA9878 device to V12 commit 5fcdff3ec68f5f33e10f5ab46dae29f202a550a7 Author: mehdi chemsi correct driver version(v6.6.3) commit 07caf4e3fae931a9115bb5068fa7acb4148360d6 Author: mehdi chemsi v6.3.3 update commit 21a96fc5e79e6a1d361477e8f98c25ca5a65504b Author: mehdi chemsi Pushing V6.6.2 driver that supports TFA9878 project commit 344e6e7a79cd43318f8faec4de615547b4dc4d2f Author: mehdi chemsi Pushing DIN_v6.5.5 to CAF commit 26919699280efb016e467fdf872e0a67bdb7ece0 Author: Johan van Nispen added LICENSE file commit 8fbec820c24d2e2b9f506312dc9be2572166bbcb Author: Johan van Nispen Initial commit for TFA Audio Driver in CAF branch Change-Id: Ib51c11778217c1a5b00624e74e449ce754485a76 Signed-off-by: Dhanalakshmi Siddani --- .../devicetree/bindings/sound/tfa9897.txt | 24 + sound/soc/codecs/Kconfig | 7 + sound/soc/codecs/Makefile | 6 + sound/soc/codecs/config.h | 39 + sound/soc/codecs/dbgprint.h | 179 + sound/soc/codecs/tfa.h | 42 + sound/soc/codecs/tfa1_tfafieldnames.h | 921 ++++ sound/soc/codecs/tfa2_tfafieldnames_N1C.h | 1526 ++++++ sound/soc/codecs/tfa9872_tfafieldnames.h | 1221 +++++ sound/soc/codecs/tfa9874_tfafieldnames.h | 836 ++++ sound/soc/codecs/tfa9878_tfafieldnames.h | 973 ++++ sound/soc/codecs/tfa9887_tfafieldnames.h | 65 + sound/soc/codecs/tfa9890_tfafieldnames.h | 80 + sound/soc/codecs/tfa9891_tfafieldnames.h | 512 ++ sound/soc/codecs/tfa9894_tfafieldnames.h | 1072 +++++ sound/soc/codecs/tfa9894_tfafieldnames_N2.h | 1123 +++++ sound/soc/codecs/tfa9896_tfafieldnames.h | 923 ++++ sound/soc/codecs/tfa98xx.c | 3278 +++++++++++++ sound/soc/codecs/tfa98xx.h | 127 + sound/soc/codecs/tfa98xx_genregs_N1C.h | 3857 +++++++++++++++ sound/soc/codecs/tfa98xx_parameters.h | 724 +++ sound/soc/codecs/tfa98xx_tfafieldnames.h | 142 + sound/soc/codecs/tfa9912_tfafieldnames.h | 1769 +++++++ sound/soc/codecs/tfa_container.c | 2410 ++++++++++ sound/soc/codecs/tfa_container.h | 350 ++ sound/soc/codecs/tfa_device.h | 298 ++ sound/soc/codecs/tfa_dsp.c | 4137 +++++++++++++++++ sound/soc/codecs/tfa_dsp_fw.h | 159 + sound/soc/codecs/tfa_ext.h | 43 + sound/soc/codecs/tfa_init.c | 1783 +++++++ sound/soc/codecs/tfa_internal.h | 34 + sound/soc/codecs/tfa_service.h | 1024 ++++ 32 files changed, 29684 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/tfa9897.txt create mode 100644 sound/soc/codecs/config.h create mode 100644 sound/soc/codecs/dbgprint.h create mode 100644 sound/soc/codecs/tfa.h create mode 100644 sound/soc/codecs/tfa1_tfafieldnames.h create mode 100644 sound/soc/codecs/tfa2_tfafieldnames_N1C.h create mode 100644 sound/soc/codecs/tfa9872_tfafieldnames.h create mode 100644 sound/soc/codecs/tfa9874_tfafieldnames.h create mode 100644 sound/soc/codecs/tfa9878_tfafieldnames.h create mode 100644 sound/soc/codecs/tfa9887_tfafieldnames.h create mode 100644 sound/soc/codecs/tfa9890_tfafieldnames.h create mode 100644 sound/soc/codecs/tfa9891_tfafieldnames.h create mode 100644 sound/soc/codecs/tfa9894_tfafieldnames.h create mode 100644 sound/soc/codecs/tfa9894_tfafieldnames_N2.h create mode 100644 sound/soc/codecs/tfa9896_tfafieldnames.h create mode 100644 sound/soc/codecs/tfa98xx.c create mode 100644 sound/soc/codecs/tfa98xx.h create mode 100644 sound/soc/codecs/tfa98xx_genregs_N1C.h create mode 100644 sound/soc/codecs/tfa98xx_parameters.h create mode 100644 sound/soc/codecs/tfa98xx_tfafieldnames.h create mode 100644 sound/soc/codecs/tfa9912_tfafieldnames.h create mode 100644 sound/soc/codecs/tfa_container.c create mode 100644 sound/soc/codecs/tfa_container.h create mode 100644 sound/soc/codecs/tfa_device.h create mode 100644 sound/soc/codecs/tfa_dsp.c create mode 100644 sound/soc/codecs/tfa_dsp_fw.h create mode 100644 sound/soc/codecs/tfa_ext.h create mode 100644 sound/soc/codecs/tfa_init.c create mode 100644 sound/soc/codecs/tfa_internal.h create mode 100644 sound/soc/codecs/tfa_service.h diff --git a/Documentation/devicetree/bindings/sound/tfa9897.txt b/Documentation/devicetree/bindings/sound/tfa9897.txt new file mode 100644 index 000000000000..6e5fedbb2108 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tfa9897.txt @@ -0,0 +1,24 @@ +TFA9897 SmartpA + +Required properties: + + - compatible : "nxp,tfa98xx" + + - reg : I2C address of the device + + - dvdd-supply : Power supply for PA's dvdd + + - dvdd-voltage : Minimum and maximum voltage in uV to set for power supply + + - dvdd-current : dvdd's max current in uA + +Examples: + + i2c_smartpa@34 { + compatible = "nxp,tfa98xx"; + reg = <0x34>; + reset-gpio = <&tlmm 68 0>; + dvdd-supply = <&pm660_l9>; + dvdd-voltage = <1800000 1800000>; + dvdd-current = <15000>; + }; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c367d11079bc..a16215781573 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -217,6 +217,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_WM9705 if SND_SOC_AC97_BUS select SND_SOC_WM9712 if SND_SOC_AC97_BUS select SND_SOC_WM9713 if SND_SOC_AC97_BUS + select SND_SOC_TFA98XX if I2C help Normally ASoC codec drivers are only built if a machine driver which uses them is also built since they are only usable with a machine @@ -1177,4 +1178,10 @@ config SND_SOC_TPA6130A2 tristate "Texas Instruments TPA6130A2 headphone amplifier" depends on I2C +config SND_SOC_TFA98XX + tristate "NXP Semiconductors TFA98XX amplifier" + depends on I2C + help + Enables support for NXP98xx Smart PA. + endmenu diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 05018b7ca72b..787655b8e2cd 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -237,6 +237,11 @@ snd-soc-max98504-objs := max98504.o snd-soc-tpa6130a2-objs := tpa6130a2.o snd-soc-tas2552-objs := tas2552.o +snd-soc-tfa98xx-objs := tfa98xx.o +snd-soc-tfa98xx-objs += tfa_container.o +snd-soc-tfa98xx-objs += tfa_dsp.o +snd-soc-tfa98xx-objs += tfa_init.o + obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o @@ -474,3 +479,4 @@ obj-$(CONFIG_SND_SOC_DIO2125) += snd-soc-dio2125.o obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o +obj-$(CONFIG_SND_SOC_TFA98XX) += snd-soc-tfa98xx.o diff --git a/sound/soc/codecs/config.h b/sound/soc/codecs/config.h new file mode 100644 index 000000000000..85b0aebe17d1 --- /dev/null +++ b/sound/soc/codecs/config.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +/* + * Linux kernel specific definitions used by code shared with + * Linux/Windows user space. + */ + +#ifndef __CONFIG_LINUX_KERNEL_INC__ +#define __CONFIG_LINUX_KERNEL_INC__ + +#include +#include +#include +#include +#include + +#define _ASSERT(e) +#ifndef PRINT_ASSERT +#define PRINT_ASSERT(e) {\ + (if ((e))\ + printk(KERN_ERR "PrintAssert:%s (%s:%d) error code:%d\n",\ + __FUNCTION__, __FILE__, __LINE__, e)) \ + } +#endif +#if defined(CONFIG_TRACING) && defined(DEBUG) + #define tfa98xx_trace_printk(...) trace_printk(__VA_ARGS__) +#else + #define tfa98xx_trace_printk(...) +#endif + +#endif /* __CONFIG_LINUX_KERNEL_INC__ */ + diff --git a/sound/soc/codecs/dbgprint.h b/sound/soc/codecs/dbgprint.h new file mode 100644 index 000000000000..bcd3bda64523 --- /dev/null +++ b/sound/soc/codecs/dbgprint.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _DBGPRINT_H +# define _DBGPRINT_H + +/* Debugging macro's. */ +# ifndef DEBUG +# define DEBUG +# endif + +# ifndef ASSERT +//#define ASSERT +# endif + //TODO wwwim +# ifndef _ASSERT + #define _ASSERT(e) +# endif + +# ifndef PREFIX +# define PREFIX "tfa98xx: " +# define DRIVER_NAME "tfa98xx" +# endif + +#ifdef __KERNEL__ + +# ifdef DEBUG +# define _DEBUG(level, fmt, va...) do {\ + if (unlikely(debug >= (level))) \ + printk(KERN_INFO PREFIX "%s:%d: "fmt,\ + __func__, __LINE__, ##va); \ + } while (0); + +# else +# define _DEBUG(level, fmt, va...) do {} while (0) +# endif + +# define MSG(fmt, va...) printk(KERN_INFO PREFIX "%s:%d: "fmt,\ + __func__, __LINE__, ##va) +# define _ERRORMSG(fmt, va...) printk(KERN_ERR PREFIX "ERROR %s:%d: "fmt,\ + __func__, __LINE__, ##va) + + +# define DEBUG0(x...) MSG(x) +# define DEBUG1(x...) _DEBUG(1, x) +# define DEBUG2(x...) _DEBUG(2, x) +# define DEBUG3(x...) _DEBUG(3, x) +# define ERRORMSG(x...) _ERRORMSG(x) +# define PRINT(x...) printk(x) +# define PRINT_ERROR(x...) printk(KERN_INFO PREFIX " **ERROR** " x) +# define PRINT_ASSERT(e) if (e) printk(KERN_ERR\ + "PrintAssert:%s (%s:%d) error code:%d\n",\ + __FUNCTION__, __FILE__, __LINE__, e) + +# define PRINT_ENTRY DEBUG2("+[%s]\n", __func__) +# define PRINT_EXIT DEBUG2("-[%s]\n", __func__) + +# ifdef ASSERT +# define assert(cond, action) do {\ + if (unlikely(!(cond))) { + DEBUG0("Assert:\ + %s\n", #cond); action; } } \ + while (0) +# else +# define assert(cond, action) do { } while (0) +# endif + +#else /* __KERNEL__ */ +#if defined(WIN32) || defined(_X64) +#include +/* user mode */ +# ifdef DEBUG +# define _DEBUGMSG(level, fmt, ...) printf(PREFIX "%s:%d: "fmt,\ + __FUNCTION__, __LINE__, __VA_ARGS__) +# else +# define _DEBUGMSG(level, fmt, ...) do {} while (0) +# endif + +# define _ERRORMSG(fmt, ...) printf(PREFIX "%s:%s:%d: "fmt, __FILE__,\ + __FUNCTION__, __LINE__, __VA_ARGS__) + +# define DEBUG0(...) MSG(__VA_ARGS__) +# define DEBUG1(...) _DEBUGMSG(1, __VA_ARGS__) +# define DEBUG2(...) _DEBUGMSG(2, __VA_ARGS__) +# define DEBUG3(...) _DEBUGMSG(3, __VA_ARGS__) +# define ERRORMSG(fmt, ...) _ERRORMSG(fmt, __VA_ARGS__) +# define PRINT(...) printf(__VA_ARGS__) +/* +# define PRINT(...) { FILE *stream; \ + if((stream = freopen("nxp_tfa.txt", "ab+", stdout)) == NULL) exit(-1);\ + printf(__VA_ARGS__); \ + freopen( "CON", "ab+", stdout ); \ + } +*/ +# define PRINT_ERROR(...) fprintf(stderr, __VA_ARGS__) +# define PRINT_FILE(file, ...) fprintf(file, __VA_ARGS__) +# define PRINT_ASSERT(e) {\ + if ((e))\ + fprintf(stderr, "PrintAssert:%s (%s:%d)\ + error code:%d\n", __FUNCTION__,\ + __FILE__, __LINE__, e)\ + } +//# define PRINT_ASSERT(e) if ((e)) fprintf(stderr, "PrintAssert:%s (%s:%d) %s\n",__FUNCTION__,__FILE__,__LINE__, Tfa98xx_GetErrorString(e)) + +#elif defined(__CODE_RED) +#include "app_global.h" +# ifdef DEBUG +# define _DEBUG(level, fmt, va...) TB_TRACE_INF(TbTracePfx2("tfa",\ + TB_FUNC, va)) +//printf(PREFIX "%s:%d: "fmt,__func__,__LINE__,##va); +# else +# define _DEBUG(level, fmt, va...) do {} while (0) +# endif + +# define MSG(fmt, ...) TB_TRACE_INF(TbTracePfx2("tfa", TB_FUNC, __VA_ARGS__)) +//printf(PREFIX "%s:%s:%d: "fmt,__FILE__,__func__,__LINE__,##va) +//TB_TRACE_INF(TbTracePfx2(APP_PFX,TB_FUNC,"path=%s, chan=%u, muted=%s, vol=%d\n", +// path->isRecording ? "recording" : "playback", +// i, +// channelVol.currentMuteValue ? "YES" : "NO", +// channelVol.currentVolumeValue +// )); +//# define _ERRORMSG(fmt,va...) TB_TRACE_INF(TbTracePfx2("tfa",TB_FUNC,va)) +# define ERRORMSG(...) TB_TRACE_INF(TbTracePfx2("tfa", TB_FUNC, __VA_ARGS__)) +//fprintf(stderr, PREFIX "ERROR %s:%s:%d: "fmt,__FILE__,__func__,__LINE__, ##va) + +#define DEBUG0(x...) MSG(x) +#define DEBUG1(x...) _DEBUG(1, x) +#define DEBUG2(x...) _DEBUG(2, x) +#define DEBUG3(x...) _DEBUG(3, x) +//# define ERRORMSG(x...) _ERRORMSG(x) +#define PRINT(x...) TB_TRACE_INF(TbTracePfx2("tfa", TB_FUNC, x)) +//printf(x) +#define PRINT_ERROR(x...) TB_TRACE_INF(TbTracePfx2("tfa", TB_FUNC, x)) +//fprintf(stderr,__VA_ARGS__) +#define PRINT_FILE(file, x...) TB_TRACE_INF(TbTracePfx2("tfa", TB_FUNC, x)) +//fprintf(file,__VA_ARGS__) +#define PRINT_ASSERT(e) +//TB_TRACE_INF(TbTracePfx2("tfa",TB_FUNC,Tfa98xx_GetErrorString(e))) +//if ((e)) fprintf(stderr, "PrintAssert:%s (%s:%d) %s\n",__FUNCTION__,__FILE__,__LINE__, Tfa98xx_GetErrorString(e)) +#else +#include +/* user mode */ +# ifdef DEBUG +# define _DEBUG(level, fmt, va...) printf(PREFIX "%s:%d: "fmt, __func__,\ + __LINE__, ##va); +# else +# define _DEBUG(level, fmt, va...) do {} while (0) +# endif + +# define MSG(fmt, va...) printf(PREFIX "%s:%s:%d: "fmt, __FILE__, __func__,\ + __LINE__, ##va) +# define _ERRORMSG(fmt, va...) fprintf(stderr, PREFIX "ERROR %s:%s:%d: "fmt,\ + __FILE__, __func__, __LINE__, ##va) + +#define DEBUG0(x...) MSG(x) +#define DEBUG1(x...) _DEBUG(1, x) +#define DEBUG2(x...) _DEBUG(2, x) +#define DEBUG3(x...) _DEBUG(3, x) +#define ERRORMSG(x...) _ERRORMSG(x) +#define PRINT(x...) printf(x) +#define PRINT_ERROR(...) fprintf(stderr, __VA_ARGS__) +#define PRINT_FILE(file, ...) fprintf(file, __VA_ARGS__) +#define PRINT_ASSERT(e)if ((e)) fprintf(stderr, "PrintAssert:%s (%s:%d)\ + error code:%d\n", __FUNCTION__, __FILE__, __LINE__, e) +//# define PRINT_ASSERT(e) if ((e)) fprintf(stderr, "PrintAssert:%s (%s:%d) %s\n", __FUNCTION__, __FILE__, __LINE__, Tfa98xx_GetErrorString(e)) + + +#endif /* WIN32 */ + +#endif /* user */ + +#endif /* _DBGPRINT_H --------------- */ diff --git a/sound/soc/codecs/tfa.h b/sound/soc/codecs/tfa.h new file mode 100644 index 000000000000..92410b7e7671 --- /dev/null +++ b/sound/soc/codecs/tfa.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA_H_ +#define TFA_H_ + +/* set the limit for the container file length */ +#define TFA_MAX_CNT_LENGTH (256*1024) + +extern struct tfa_device **devs; + +/** + * tfa error return codes + */ +enum tfa_error { + tfa_error_ok, /**< no error */ + tfa_error_device, /**< no response from device */ + tfa_error_bad_param,/**< parameter no accepted */ + tfa_error_noclock, /**< required clock not present */ + tfa_error_timeout, /**< a timeout occurred */ + tfa_error_dsp, /**< a DSP error was returned */ + tfa_error_container,/**< no or wrong container file */ + tfa_error_max /**< impossible value, max enum */ +}; + +enum Tfa98xx_Error tfa_write_filters(struct tfa_device *tfa, int prof_idx); + +struct tfa_device **tfa_devs_create(int count); +void tfa_devs_destroy(int count); + +struct tfa_device **tfa_get_device_struct(void); + +int tfa_plop_noise_interrupt(struct tfa_device *tfa, int profile, int vstep); +void tfa_lp_mode_interrupt(struct tfa_device *tfa); + +#endif /* TFA_H_ */ diff --git a/sound/soc/codecs/tfa1_tfafieldnames.h b/sound/soc/codecs/tfa1_tfafieldnames.h new file mode 100644 index 000000000000..81fed6a34e4d --- /dev/null +++ b/sound/soc/codecs/tfa1_tfafieldnames.h @@ -0,0 +1,921 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ +#define TFA9897_I2CVERSION 34 +typedef enum nxpTfa1BfEnumList { +TFA1_BF_VDDS = 0x0000, /*!< Power-on-reset flag */ +TFA1_BF_PLLS = 0x0010, /*!< PLL lock */ +TFA1_BF_OTDS = 0x0020, /*!< Over Temperature Protection alarm */ +TFA1_BF_OVDS = 0x0030, /*!< Over Voltage Protection alarm */ +TFA1_BF_UVDS = 0x0040, /*!< Under Voltage Protection alarm */ +TFA1_BF_OCDS = 0x0050, /*!< Over Current Protection alarm */ +TFA1_BF_CLKS = 0x0060, /*!< Clocks stable flag */ +TFA1_BF_CLIPS = 0x0070, /*!< Amplifier clipping */ +TFA1_BF_MTPB = 0x0080, /*!< MTP busy */ +TFA1_BF_NOCLK = 0x0090, /*!< Flag lost clock from clock generationunit*/ +TFA1_BF_SPKS = 0x00a0, /*!< Speaker error flag */ +TFA1_BF_ACS = 0x00b0, /*!< Cold Start flag */ +TFA1_BF_SWS = 0x00c0, /*!< Flag Engage */ +TFA1_BF_WDS = 0x00d0, /*!< Flag watchdog reset */ +TFA1_BF_AMPS = 0x00e0, /*!< Amplifier is enabled by manager */ +TFA1_BF_AREFS = 0x00f0, /*!< References are enabled by manager */ +TFA1_BF_BATS = 0x0109, /*!< Battery voltage readout; 0 .. 5.5 [V] */ +TFA1_BF_TEMPS = 0x0208, /*!< Temperature readout from the temperature + * sensor */ +TFA1_BF_REV = 0x030b, /*!< Device type number is B97 */ +TFA1_BF_RCV = 0x0420, /*!< Enable Receiver Mode */ +TFA1_BF_CHS12 = 0x0431, /*!< Channel Selection TDM input for Coolflux */ +TFA1_BF_INPLVL = 0x0450, /*!< Input level selection control */ +TFA1_BF_CHSA = 0x0461, /*!< Input selection for amplifier */ +TFA1_BF_I2SDOE = 0x04b0, /*!< Enable data output */ +TFA1_BF_AUDFS = 0x04c3, /*!< Audio sample rate setting */ +TFA1_BF_BSSCR = 0x0501, /*!< Protection Attack Time */ +TFA1_BF_BSST = 0x0523, /*!< ProtectionThreshold */ +TFA1_BF_BSSRL = 0x0561, /*!< Protection Maximum Reduction */ +TFA1_BF_BSSRR = 0x0582, /*!< Battery Protection Release Time */ +TFA1_BF_BSSHY = 0x05b1, /*!< Battery Protection Hysteresis */ +TFA1_BF_BSSR = 0x05e0, /*!< battery voltage for I2C read out only */ +TFA1_BF_BSSBY = 0x05f0, /*!< bypass clipper battery protection */ +TFA1_BF_DPSA = 0x0600, /*!< Enable dynamic powerstage activation */ +TFA1_BF_CFSM = 0x0650, /*!< Soft mute in CoolFlux */ +TFA1_BF_BSSS = 0x0670, /*!< BatSenseSteepness */ +TFA1_BF_VOL = 0x0687, /*!< volume control (in CoolFlux) */ +TFA1_BF_DCVO = 0x0702, /*!< Boost Voltage */ +TFA1_BF_DCMCC = 0x0733, /*!< Max boost coil current - step of 175 mA */ +TFA1_BF_DCIE = 0x07a0, /*!< Adaptive boost mode */ +TFA1_BF_DCSR = 0x07b0, /*!< Soft RampUp/Down mode for DCDC controller*/ +TFA1_BF_DCPAVG = 0x07c0, /*!< ctrl_peak2avg for analog part of DCDC */ +TFA1_BF_TROS = 0x0800, /*!< Select external temperature also the ext_temp + * will be put on the temp read out */ +TFA1_BF_EXTTS = 0x0818, /*!< external temperature setting to be given + * by host*/ +TFA1_BF_PWDN = 0x0900, /*!< Device Mode */ +TFA1_BF_I2CR = 0x0910, /*!< I2C Reset */ +TFA1_BF_CFE = 0x0920, /*!< Enable CoolFlux */ +TFA1_BF_AMPE = 0x0930, /*!< Enable Amplifier */ +TFA1_BF_DCA = 0x0940, /*!< EnableBoost */ +TFA1_BF_SBSL = 0x0950, /*!< Coolflux configured */ +TFA1_BF_AMPC = 0x0960, /*!< Selection on how Amplifier is enabled */ +TFA1_BF_DCDIS = 0x0970, /*!< DCDC not connected */ +TFA1_BF_PSDR = 0x0980, /*!< IDDQ test amplifier */ +TFA1_BF_DCCV = 0x0991, /*!< Coil Value */ +TFA1_BF_CCFD = 0x09b0, /*!< Selection CoolFlux Clock */ +TFA1_BF_INTPAD = 0x09c1, /*!< INT pad configuration control */ +TFA1_BF_IPLL = 0x09e0, /*!< PLL input reference clock selection */ +TFA1_BF_MTPK = 0x0b07, /*!< 5Ah, 90d To access KEY1_Protected registers + * (Default for engineering) */ +TFA1_BF_CVFDLY = 0x0c25, /*!< Fractional delay adjustment between current + and voltage sense */ +TFA1_BF_TDMPRF = 0x1011, /*!< TDM_usecase */ +TFA1_BF_TDMEN = 0x1030, /*!< TDM interface control */ +TFA1_BF_TDMCKINV = 0x1040, /*!< TDM clock inversion */ +TFA1_BF_TDMFSLN = 0x1053, /*!< TDM FS length */ +TFA1_BF_TDMFSPOL = 0x1090, /*!< TDM FS polarity */ +TFA1_BF_TDMSAMSZ = 0x10a4, /*!< TDM Sample Size for all tdm + sinks/sources */ +TFA1_BF_TDMSLOTS = 0x1103, /*!< Number of slots */ +TFA1_BF_TDMSLLN = 0x1144, /*!< Slot length */ +TFA1_BF_TDMBRMG = 0x1194, /*!< Bits remaining */ +TFA1_BF_TDMDDEL = 0x11e0, /*!< Data delay */ +TFA1_BF_TDMDADJ = 0x11f0, /*!< Data adjustment */ +TFA1_BF_TDMTXFRM = 0x1201, /*!< TXDATA format */ +TFA1_BF_TDMUUS0 = 0x1221, /*!< TXDATA format unused slot sd0 */ +TFA1_BF_TDMUUS1 = 0x1241, /*!< TXDATA format unused slot sd1 */ +TFA1_BF_TDMSI0EN = 0x1270, /*!< TDM sink0 enable */ +TFA1_BF_TDMSI1EN = 0x1280, /*!< TDM sink1 enable */ +TFA1_BF_TDMSI2EN = 0x1290, /*!< TDM sink2 enable */ +TFA1_BF_TDMSO0EN = 0x12a0, /*!< TDM source0 enable */ +TFA1_BF_TDMSO1EN = 0x12b0, /*!< TDM source1 enable */ +TFA1_BF_TDMSO2EN = 0x12c0, /*!< TDM source2 enable */ +TFA1_BF_TDMSI0IO = 0x12d0, /*!< tdm_sink0_io */ +TFA1_BF_TDMSI1IO = 0x12e0, /*!< tdm_sink1_io */ +TFA1_BF_TDMSI2IO = 0x12f0, /*!< tdm_sink2_io */ +TFA1_BF_TDMSO0IO = 0x1300, /*!< tdm_source0_io */ +TFA1_BF_TDMSO1IO = 0x1310, /*!< tdm_source1_io */ +TFA1_BF_TDMSO2IO = 0x1320, /*!< tdm_source2_io */ +TFA1_BF_TDMSI0SL = 0x1333, /*!< sink0_slot [GAIN IN] */ +TFA1_BF_TDMSI1SL = 0x1373, /*!< sink1_slot [CH1 IN] */ +TFA1_BF_TDMSI2SL = 0x13b3, /*!< sink2_slot [CH2 IN] */ +TFA1_BF_TDMSO0SL = 0x1403, /*!< source0_slot [GAIN OUT] */ +TFA1_BF_TDMSO1SL = 0x1443, /*!< source1_slot [Voltage Sense] */ +TFA1_BF_TDMSO2SL = 0x1483, /*!< source2_slot [Current Sense] */ +TFA1_BF_NBCK = 0x14c3, /*!< NBCK */ +TFA1_BF_INTOVDDS = 0x2000, /*!< flag_por_int_out */ +TFA1_BF_INTOPLLS = 0x2010, /*!< flag_pll_lock_int_out */ +TFA1_BF_INTOOTDS = 0x2020, /*!< flag_otpok_int_out */ +TFA1_BF_INTOOVDS = 0x2030, /*!< flag_ovpok_int_out */ +TFA1_BF_INTOUVDS = 0x2040, /*!< flag_uvpok_int_out */ +TFA1_BF_INTOOCDS = 0x2050, /*!< flag_ocp_alarm_int_out */ +TFA1_BF_INTOCLKS = 0x2060, /*!< flag_clocks_stable_int_out */ +TFA1_BF_INTOCLIPS = 0x2070, /*!< flag_clip_int_out */ +TFA1_BF_INTOMTPB = 0x2080, /*!< mtp_busy_int_out */ +TFA1_BF_INTONOCLK = 0x2090, /*!< flag_lost_clk_int_out */ +TFA1_BF_INTOSPKS = 0x20a0, /*!< flag_cf_speakererror_int_out */ +TFA1_BF_INTOACS = 0x20b0, /*!< flag_cold_started_int_out */ +TFA1_BF_INTOSWS = 0x20c0, /*!< flag_engage_int_out */ +TFA1_BF_INTOWDS = 0x20d0, /*!< flag_watchdog_reset_int_out */ +TFA1_BF_INTOAMPS = 0x20e0, /*!< flag_enbl_amp_int_out */ +TFA1_BF_INTOAREFS = 0x20f0, /*!< flag_enbl_ref_int_out */ +TFA1_BF_INTOACK = 0x2201, /*!< Interrupt status register output - + * Corresponding flag */ +TFA1_BF_INTIVDDS = 0x2300, /*!< flag_por_int_in */ +TFA1_BF_INTIPLLS = 0x2310, /*!< flag_pll_lock_int_in */ +TFA1_BF_INTIOTDS = 0x2320, /*!< flag_otpok_int_in */ +TFA1_BF_INTIOVDS = 0x2330, /*!< flag_ovpok_int_in */ +TFA1_BF_INTIUVDS = 0x2340, /*!< flag_uvpok_int_in */ +TFA1_BF_INTIOCDS = 0x2350, /*!< flag_ocp_alarm_int_in */ +TFA1_BF_INTICLKS = 0x2360, /*!< flag_clocks_stable_int_in */ +TFA1_BF_INTICLIPS = 0x2370, /*!< flag_clip_int_in */ +TFA1_BF_INTIMTPB = 0x2380, /*!< mtp_busy_int_in */ +TFA1_BF_INTINOCLK = 0x2390, /*!< flag_lost_clk_int_in */ +TFA1_BF_INTISPKS = 0x23a0, /*!< flag_cf_speakererror_int_in */ +TFA1_BF_INTIACS = 0x23b0, /*!< flag_cold_started_int_in */ +TFA1_BF_INTISWS = 0x23c0, /*!< flag_engage_int_in */ +TFA1_BF_INTIWDS = 0x23d0, /*!< flag_watchdog_reset_int_in */ +TFA1_BF_INTIAMPS = 0x23e0, /*!< flag_enbl_amp_int_in */ +TFA1_BF_INTIAREFS = 0x23f0, /*!< flag_enbl_ref_int_in */ +TFA1_BF_INTIACK = 0x2501, /*!< Interrupt register input */ +TFA1_BF_INTENVDDS = 0x2600, /*!< flag_por_int_enable */ +TFA1_BF_INTENPLLS = 0x2610, /*!< flag_pll_lock_int_enable */ +TFA1_BF_INTENOTDS = 0x2620, /*!< flag_otpok_int_enable */ +TFA1_BF_INTENOVDS = 0x2630, /*!< flag_ovpok_int_enable */ +TFA1_BF_INTENUVDS = 0x2640, /*!< flag_uvpok_int_enable */ +TFA1_BF_INTENOCDS = 0x2650, /*!< flag_ocp_alarm_int_enable */ +TFA1_BF_INTENCLKS = 0x2660, /*!< flag_clocks_stable_int_enable */ +TFA1_BF_INTENCLIPS = 0x2670, /*!< flag_clip_int_enable */ +TFA1_BF_INTENMTPB = 0x2680, /*!< mtp_busy_int_enable */ +TFA1_BF_INTENNOCLK = 0x2690, /*!< flag_lost_clk_int_enable */ +TFA1_BF_INTENSPKS = 0x26a0, /*!< flag_cf_speakererror_int_enable */ +TFA1_BF_INTENACS = 0x26b0, /*!< flag_cold_started_int_enable */ +TFA1_BF_INTENSWS = 0x26c0, /*!< flag_engage_int_enable */ +TFA1_BF_INTENWDS = 0x26d0, /*!< flag_watchdog_reset_int_enable */ +TFA1_BF_INTENAMPS = 0x26e0, /*!< flag_enbl_amp_int_enable */ +TFA1_BF_INTENAREFS = 0x26f0, /*!< flag_enbl_ref_int_enable */ +TFA1_BF_INTENACK = 0x2801, /*!< Interrupt enable register */ +TFA1_BF_INTPOLVDDS = 0x2900, /*!< flag_por_int_pol */ +TFA1_BF_INTPOLPLLS = 0x2910, /*!< flag_pll_lock_int_pol */ +TFA1_BF_INTPOLOTDS = 0x2920, /*!< flag_otpok_int_pol */ +TFA1_BF_INTPOLOVDS = 0x2930, /*!< flag_ovpok_int_pol */ +TFA1_BF_INTPOLUVDS = 0x2940, /*!< flag_uvpok_int_pol */ +TFA1_BF_INTPOLOCDS = 0x2950, /*!< flag_ocp_alarm_int_pol */ +TFA1_BF_INTPOLCLKS = 0x2960, /*!< flag_clocks_stable_int_pol */ +TFA1_BF_INTPOLCLIPS = 0x2970, /*!< flag_clip_int_pol */ +TFA1_BF_INTPOLMTPB = 0x2980, /*!< mtp_busy_int_pol */ +TFA1_BF_INTPOLNOCLK = 0x2990, /*!< flag_lost_clk_int_pol */ +TFA1_BF_INTPOLSPKS = 0x29a0, /*!< flag_cf_speakererror_int_pol */ +TFA1_BF_INTPOLACS = 0x29b0, /*!< flag_cold_started_int_pol */ +TFA1_BF_INTPOLSWS = 0x29c0, /*!< flag_engage_int_pol */ +TFA1_BF_INTPOLWDS = 0x29d0, /*!< flag_watchdog_reset_int_pol */ +TFA1_BF_INTPOLAMPS = 0x29e0, /*!< flag_enbl_amp_int_pol */ +TFA1_BF_INTPOLAREFS = 0x29f0, /*!< flag_enbl_ref_int_pol */ +TFA1_BF_INTPOLACK = 0x2b01, /*!< Interrupt status flags + * polarity register */ +TFA1_BF_CLIP = 0x4900, /*!< Bypass clip control */ +TFA1_BF_CIMTP = 0x62b0, /*!< start copying all the data from i2cregs_mtp + to mtp [Key 2 protected] */ +TFA1_BF_RST = 0x7000, /*!< Reset CoolFlux DSP */ +TFA1_BF_DMEM = 0x7011, /*!< Target memory for access */ +TFA1_BF_AIF = 0x7030, /*!< Autoincrement-flag for memory-address */ +TFA1_BF_CFINT = 0x7040, /*!< Interrupt CoolFlux DSP */ +TFA1_BF_REQ = 0x7087, /*!< request for access (8 channels) */ +TFA1_BF_REQCMD = 0x7080, /*!< Firmware event request rpc command */ +TFA1_BF_REQRST = 0x7090, /*!< Firmware event request reset restart */ +TFA1_BF_REQMIPS = 0x70a0, /*!< Firmware event request short on mips */ +TFA1_BF_REQMUTED = 0x70b0, /*!< Firmware event request mute sequence ready*/ +TFA1_BF_REQVOL = 0x70c0, /*!< Firmware event request volume ready */ +TFA1_BF_REQDMG = 0x70d0, /*!< Firmware event request speaker damage detected*/ +TFA1_BF_REQCAL = 0x70e0, /*!< Firmware event request calibration completed */ +TFA1_BF_REQRSV = 0x70f0, /*!< Firmware event request reserved */ +TFA1_BF_MADD = 0x710f, /*!< memory-address to be accessed */ +TFA1_BF_MEMA = 0x720f, /*!< activate memory access (24- or 32-bits data is + * written/read to/from memory */ +TFA1_BF_ERR = 0x7307, /*!< Coolflux error flags */ +TFA1_BF_ACK = 0x7387, /*!< acknowledge of requests (8 channels) */ +TFA1_BF_MTPOTC = 0x8000, /*!< Calibration schedule (key2 protected) */ +TFA1_BF_MTPEX = 0x8010, /*!< (key2 protected) */ +} nxpTfa1BfEnumList_t; +#define TFA1_NAMETABLE static tfaBfName_t Tfa1DatasheetNames[] = {\ +{ 0x0, "VDDS"}, /* Power-on-reset flag , */\ +{ 0x10, "PLLS"}, /* PLL lock , */\ +{ 0x20, "OTDS"}, /* Over Temperature Protection alarm , */\ +{ 0x30, "OVDS"}, /* Over Voltage Protection alarm , */\ +{ 0x40, "UVDS"}, /* Under Voltage Protection alarm , */\ +{ 0x50, "OCDS"}, /* Over Current Protection alarm , */\ +{ 0x60, "CLKS"}, /* Clocks stable flag , */\ +{ 0x70, "CLIPS"}, /* Amplifier clipping , */\ +{ 0x80, "MTPB"}, /* MTP busy , */\ +{ 0x90, "NOCLK"}, /* Flag lost clock from clock generation unit , */\ +{ 0xa0, "SPKS"}, /* Speaker error flag , */\ +{ 0xb0, "ACS"}, /* Cold Start flag , */\ +{ 0xc0, "SWS"}, /* Flag Engage , */\ +{ 0xd0, "WDS"}, /* Flag watchdog reset , */\ +{ 0xe0, "AMPS"}, /* Amplifier is enabled by manager , */\ +{ 0xf0, "AREFS"}, /* References are enabled by manager , */\ +{ 0x109, "BATS"}, /* Battery voltage readout; 0 .. 5.5 [V] , */\ +{ 0x208, "TEMPS"}, /* Temperature readout from the temperature sensor , */\ +{ 0x30b, "REV"}, /* Device type number is B97 , */\ +{ 0x420, "RCV"}, /* Enable Receiver Mode , */\ +{ 0x431, "CHS12"}, /* Channel Selection TDM input for Coolflux , */\ +{ 0x450, "INPLVL"}, /* Input level selection control , */\ +{ 0x461, "CHSA"}, /* Input selection for amplifier , */\ +{ 0x4b0, "I2SDOE"}, /* Enable data output , */\ +{ 0x4c3, "AUDFS"}, /* Audio sample rate setting , */\ +{ 0x501, "SSCR"}, /* Protection Attack Time , */\ +{ 0x523, "SST"}, /* ProtectionThreshold , */\ +{ 0x561, "SSRL"}, /* Protection Maximum Reduction , */\ +{ 0x582, "SSRR"}, /* Battery Protection Release Time , */\ +{ 0x5b1, "SSHY"}, /* Battery Protection Hysteresis , */\ +{ 0x5e0, "SSR"}, /* battery voltage for I2C read out only , */\ +{ 0x5f0, "SSBY"}, /* bypass clipper battery protection , */\ +{ 0x600, "DPSA"}, /* Enable dynamic powerstage activation , */\ +{ 0x650, "CFSM"}, /* Soft mute in CoolFlux , */\ +{ 0x670, "SSS"}, /* BatSenseSteepness , */\ +{ 0x687, "VOL"}, /* volume control (in CoolFlux) , */\ +{ 0x702, "DCVO"}, /* Boost Voltage , */\ +{ 0x733, "DCMCC"}, /* Max boost coil current - step of 175 mA , */\ +{ 0x7a0, "DCIE"}, /* Adaptive boost mode , */\ +{ 0x7b0, "DCSR"}, /* Soft RampUp/Down mode for DCDC controller , */\ +{ 0x7c0, "DCPAVG"}, /* ctrl_peak2avg for analog part of DCDC , */\ +{ 0x800, "TROS"}, /* Select external temperature also the ext_temp will be + * put on the temp read out , */\ +{ 0x818, "EXTTS"}, /* external temperature setting to be given by host , */\ +{ 0x900, "PWDN"}, /* Device Mode , */\ +{ 0x910, "I2CR"}, /* I2C Reset , */\ +{ 0x920, "CFE"}, /* Enable CoolFlux , */\ +{ 0x930, "AMPE"}, /* Enable Amplifier , */\ +{ 0x940, "DCA"}, /* EnableBoost , */\ +{ 0x950, "SBSL"}, /* Coolflux configured , */\ +{ 0x960, "AMPC"}, /* Selection on how Amplifier is enabled , */\ +{ 0x970, "DCDIS"}, /* DCDC not connected , */\ +{ 0x980, "PSDR"}, /* IDDQ test amplifier , */\ +{ 0x991, "DCCV"}, /* Coil Value , */\ +{ 0x9b0, "CCFD"}, /* Selection CoolFlux Clock , */\ +{ 0x9c1, "INTPAD"}, /* INT pad configuration control , */\ +{ 0x9e0, "IPLL"}, /* PLL input reference clock selection , */\ +{ 0xb07, "MTPK"}, /* 5Ah, 90d To access KEY1_Protected registers + * (Default for engineering), */\ +{ 0xc25, "CVFDLY"}, /* Fractional delay adjustment between current and + * voltage sense, */\ +{ 0x1011, "TDMPRF"}, /* TDM_usecase , */\ +{ 0x1030, "TDMEN"}, /* TDM interface control , */\ +{ 0x1040, "TDMCKINV"}, /* TDM clock inversion , */\ +{ 0x1053, "TDMFSLN"}, /* TDM FS length , */\ +{ 0x1090, "TDMFSPOL"}, /* TDM FS polarity , */\ +{ 0x10a4, "TDMSAMSZ"}, /* TDM Sample Size for all tdm sinks/sources , */\ +{ 0x1103, "TDMSLOTS"}, /* Number of slots , */\ +{ 0x1144, "TDMSLLN"}, /* Slot length , */\ +{ 0x1194, "TDMBRMG"}, /* Bits remaining , */\ +{ 0x11e0, "TDMDDEL"}, /* Data delay , */\ +{ 0x11f0, "TDMDADJ"}, /* Data adjustment , */\ +{ 0x1201, "TDMTXFRM"}, /* TXDATA format , */\ +{ 0x1221, "TDMUUS0"}, /* TXDATA format unused slot sd0 , */\ +{ 0x1241, "TDMUUS1"}, /* TXDATA format unused slot sd1 , */\ +{ 0x1270, "TDMSI0EN"}, /* TDM sink0 enable , */\ +{ 0x1280, "TDMSI1EN"}, /* TDM sink1 enable , */\ +{ 0x1290, "TDMSI2EN"}, /* TDM sink2 enable , */\ +{ 0x12a0, "TDMSO0EN"}, /* TDM source0 enable , */\ +{ 0x12b0, "TDMSO1EN"}, /* TDM source1 enable , */\ +{ 0x12c0, "TDMSO2EN"}, /* TDM source2 enable , */\ +{ 0x12d0, "TDMSI0IO"}, /* tdm_sink0_io , */\ +{ 0x12e0, "TDMSI1IO"}, /* tdm_sink1_io , */\ +{ 0x12f0, "TDMSI2IO"}, /* tdm_sink2_io , */\ +{ 0x1300, "TDMSO0IO"}, /* tdm_source0_io , */\ +{ 0x1310, "TDMSO1IO"}, /* tdm_source1_io , */\ +{ 0x1320, "TDMSO2IO"}, /* tdm_source2_io , */\ +{ 0x1333, "TDMSI0SL"}, /* sink0_slot [GAIN IN] , */\ +{ 0x1373, "TDMSI1SL"}, /* sink1_slot [CH1 IN] , */\ +{ 0x13b3, "TDMSI2SL"}, /* sink2_slot [CH2 IN] , */\ +{ 0x1403, "TDMSO0SL"}, /* source0_slot [GAIN OUT] , */\ +{ 0x1443, "TDMSO1SL"}, /* source1_slot [Voltage Sense] , */\ +{ 0x1483, "TDMSO2SL"}, /* source2_slot [Current Sense] , */\ +{ 0x14c3, "NBCK"}, /* NBCK , */\ +{ 0x2000, "INTOVDDS"}, /* flag_por_int_out , */\ +{ 0x2010, "INTOPLLS"}, /* flag_pll_lock_int_out , */\ +{ 0x2020, "INTOOTDS"}, /* flag_otpok_int_out , */\ +{ 0x2030, "INTOOVDS"}, /* flag_ovpok_int_out , */\ +{ 0x2040, "INTOUVDS"}, /* flag_uvpok_int_out , */\ +{ 0x2050, "INTOOCDS"}, /* flag_ocp_alarm_int_out , */\ +{ 0x2060, "INTOCLKS"}, /* flag_clocks_stable_int_out , */\ +{ 0x2070, "INTOCLIPS"}, /* flag_clip_int_out , */\ +{ 0x2080, "INTOMTPB"}, /* mtp_busy_int_out , */\ +{ 0x2090, "INTONOCLK"}, /* flag_lost_clk_int_out , */\ +{ 0x20a0, "INTOSPKS"}, /* flag_cf_speakererror_int_out , */\ +{ 0x20b0, "INTOACS"}, /* flag_cold_started_int_out , */\ +{ 0x20c0, "INTOSWS"}, /* flag_engage_int_out , */\ +{ 0x20d0, "INTOWDS"}, /* flag_watchdog_reset_int_out , */\ +{ 0x20e0, "INTOAMPS"}, /* flag_enbl_amp_int_out , */\ +{ 0x20f0, "INTOAREFS"}, /* flag_enbl_ref_int_out , */\ +{ 0x2201, "INTOACK"}, /* Interrupt status register output + * - Corresponding flag, */\ +{ 0x2300, "INTIVDDS"}, /* flag_por_int_in , */\ +{ 0x2310, "INTIPLLS"}, /* flag_pll_lock_int_in , */\ +{ 0x2320, "INTIOTDS"}, /* flag_otpok_int_in , */\ +{ 0x2330, "INTIOVDS"}, /* flag_ovpok_int_in , */\ +{ 0x2340, "INTIUVDS"}, /* flag_uvpok_int_in , */\ +{ 0x2350, "INTIOCDS"}, /* flag_ocp_alarm_int_in , */\ +{ 0x2360, "INTICLKS"}, /* flag_clocks_stable_int_in , */\ +{ 0x2370, "INTICLIPS"}, /* flag_clip_int_in , */\ +{ 0x2380, "INTIMTPB"}, /* mtp_busy_int_in , */\ +{ 0x2390, "INTINOCLK"}, /* flag_lost_clk_int_in , */\ +{ 0x23a0, "INTISPKS"}, /* flag_cf_speakererror_int_in , */\ +{ 0x23b0, "INTIACS"}, /* flag_cold_started_int_in , */\ +{ 0x23c0, "INTISWS"}, /* flag_engage_int_in , */\ +{ 0x23d0, "INTIWDS"}, /* flag_watchdog_reset_int_in , */\ +{ 0x23e0, "INTIAMPS"}, /* flag_enbl_amp_int_in , */\ +{ 0x23f0, "INTIAREFS"}, /* flag_enbl_ref_int_in , */\ +{ 0x2501, "INTIACK"}, /* Interrupt register input , */\ +{ 0x2600, "INTENVDDS"}, /* flag_por_int_enable , */\ +{ 0x2610, "INTENPLLS"}, /* flag_pll_lock_int_enable , */\ +{ 0x2620, "INTENOTDS"}, /* flag_otpok_int_enable , */\ +{ 0x2630, "INTENOVDS"}, /* flag_ovpok_int_enable , */\ +{ 0x2640, "INTENUVDS"}, /* flag_uvpok_int_enable , */\ +{ 0x2650, "INTENOCDS"}, /* flag_ocp_alarm_int_enable , */\ +{ 0x2660, "INTENCLKS"}, /* flag_clocks_stable_int_enable , */\ +{ 0x2670, "INTENCLIPS"}, /* flag_clip_int_enable , */\ +{ 0x2680, "INTENMTPB"}, /* mtp_busy_int_enable , */\ +{ 0x2690, "INTENNOCLK"}, /* flag_lost_clk_int_enable , */\ +{ 0x26a0, "INTENSPKS"}, /* flag_cf_speakererror_int_enable , */\ +{ 0x26b0, "INTENACS"}, /* flag_cold_started_int_enable , */\ +{ 0x26c0, "INTENSWS"}, /* flag_engage_int_enable , */\ +{ 0x26d0, "INTENWDS"}, /* flag_watchdog_reset_int_enable , */\ +{ 0x26e0, "INTENAMPS"}, /* flag_enbl_amp_int_enable , */\ +{ 0x26f0, "INTENAREFS"}, /* flag_enbl_ref_int_enable , */\ +{ 0x2801, "INTENACK"}, /* Interrupt enable register , */\ +{ 0x2900, "INTPOLVDDS"}, /* flag_por_int_pol , */\ +{ 0x2910, "INTPOLPLLS"}, /* flag_pll_lock_int_pol , */\ +{ 0x2920, "INTPOLOTDS"}, /* flag_otpok_int_pol , */\ +{ 0x2930, "INTPOLOVDS"}, /* flag_ovpok_int_pol , */\ +{ 0x2940, "INTPOLUVDS"}, /* flag_uvpok_int_pol , */\ +{ 0x2950, "INTPOLOCDS"}, /* flag_ocp_alarm_int_pol , */\ +{ 0x2960, "INTPOLCLKS"}, /* flag_clocks_stable_int_pol , */\ +{ 0x2970, "INTPOLCLIPS"}, /* flag_clip_int_pol , */\ +{ 0x2980, "INTPOLMTPB"}, /* mtp_busy_int_pol , */\ +{ 0x2990, "INTPOLNOCLK"}, /* flag_lost_clk_int_pol , */\ +{ 0x29a0, "INTPOLSPKS"}, /* flag_cf_speakererror_int_pol , */\ +{ 0x29b0, "INTPOLACS"}, /* flag_cold_started_int_pol , */\ +{ 0x29c0, "INTPOLSWS"}, /* flag_engage_int_pol , */\ +{ 0x29d0, "INTPOLWDS"}, /* flag_watchdog_reset_int_pol , */\ +{ 0x29e0, "INTPOLAMPS"}, /* flag_enbl_amp_int_pol , */\ +{ 0x29f0, "INTPOLAREFS"}, /* flag_enbl_ref_int_pol , */\ +{ 0x2b01, "INTPOLACK"}, /* Interrupt status flags polarity register , */\ +{ 0x4900, "CLIP"}, /* Bypass clip control , */\ +{ 0x62b0, "CIMTP"}, /* start copying all the data from i2cregs_mtp + * to mtp [Key 2 protected], */\ +{ 0x7000, "RST"}, /* Reset CoolFlux DSP , */\ +{ 0x7011, "DMEM"}, /* Target memory for access , */\ +{ 0x7030, "AIF"}, /* Autoincrement-flag for memory-address , */\ +{ 0x7040, "CFINT"}, /* Interrupt CoolFlux DSP , */\ +{ 0x7087, "REQ"}, /* request for access (8 channels) , */\ +{ 0x7080, "REQCMD"}, /* Firmware event request rpc command , */\ +{ 0x7090, "REQRST"}, /* Firmware event request reset restart , */\ +{ 0x70a0, "REQMIPS"}, /* Firmware event request short on mips , */\ +{ 0x70b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ +{ 0x70c0, "REQVOL"}, /* Firmware event request volume ready , */\ +{ 0x70d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ +{ 0x70e0, "REQCAL"}, /* Firmware event request calibration completed , */\ +{ 0x70f0, "REQRSV"}, /* Firmware event request reserved , */\ +{ 0x710f, "MADD"}, /* memory-address to be accessed , */\ +{ 0x720f, "MEMA"}, /* activate memory access (24- or 32-bits data is + * written/read to/from memory, */\ +{ 0x7307, "ERR"}, /* Coolflux error flags , */\ +{ 0x7387, "ACK"}, /* acknowledge of requests (8 channels) , */\ +{ 0x7380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ +{ 0x7390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ +{ 0x73a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ +{ 0x73b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready,*/\ +{ 0x73c0, "ACKVOL"}, /* Firmware event acknowledge volume ready ,*/\ +{ 0x73d0, "ACKDMG"}, /* Firmware event acknowledge speaker + * damage detected,*/\ +{ 0x73e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed,*/\ +{ 0x73f0, "ACKRSV"}, /* Firmware event acknowledge reserved ,*/\ +{ 0x8000, "MTPOTC"}, /* Calibration schedule (key2 protected) ,*/\ +{ 0x8010, "MTPEX"}, /* (key2 protected) ,*/\ +{ 0x8045, "SWPROFIL" },\ +{ 0x80a5, "SWVSTEP" },\ +{ 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA1_BITNAMETABLE static tfaBfName_t Tfa1BitNames[] = {\ +{ 0x0, "flag_por"}, /* Power-on-reset flag , */\ +{ 0x10, "flag_pll_lock"}, /* PLL lock , */\ +{ 0x20, "flag_otpok"}, /* Over Temperature Protection alarm , */\ +{ 0x30, "flag_ovpok"}, /* Over Voltage Protection alarm , */\ +{ 0x40, "flag_uvpok"}, /* Under Voltage Protection alarm , */\ +{ 0x50, "flag_ocp_alarm"}, /* Over Current Protection alarm , */\ +{ 0x60, "flag_clocks_stable"}, /* Clocks stable flag , */\ +{ 0x70, "flag_clip"}, /* Amplifier clipping , */\ +{ 0x80, "mtp_busy"}, /* MTP busy , */\ +{ 0x90, "flag_lost_clk"}, /* Flag lost clock from clock generation unit , */\ +{ 0xa0, "flag_cf_speakererror"}, /* Speaker error flag , */\ +{ 0xb0, "flag_cold_started"}, /* Cold Start flag , */\ +{ 0xc0, "flag_engage"}, /* Flag Engage , */\ +{ 0xd0, "flag_watchdog_reset"}, /* Flag watchdog reset , */\ +{ 0xe0, "flag_enbl_amp"}, /* Amplifier is enabled by manager , */\ +{ 0xf0, "flag_enbl_ref"}, /* References are enabled by manager , */\ +{ 0x109, "bat_adc"}, /* Battery voltage readout; 0 .. 5.5 [V] , */\ +{ 0x208, "temp_adc"}, /* Temperature readout from the temperature sensor , */\ +{ 0x30b, "rev_reg"}, /* Device type number is B97 , */\ +{ 0x420, "ctrl_rcv"}, /* Enable Receiver Mode , */\ +{ 0x431, "chan_sel"}, /* Channel Selection TDM input for Coolflux , */\ +{ 0x450, "input_level"}, /* Input level selection control , */\ +{ 0x461, "vamp_sel"}, /* Input selection for amplifier , */\ +{ 0x4c3, "audio_fs"}, /* Audio sample rate setting , */\ +{ 0x501, "vbat_prot_attacktime"}, /* Protection Attack Time , */\ +{ 0x523, "vbat_prot_thlevel"}, /* ProtectionThreshold , */\ +{ 0x561, "vbat_prot_max_reduct"}, /* Protection Maximum Reduction , */\ +{ 0x582, "vbat_prot_release_t"}, /* Battery Protection Release Time , */\ +{ 0x5b1, "vbat_prot_hysterese"}, /* Battery Protection Hysteresis , */\ +{ 0x5d0, "reset_min_vbat"}, /* reset clipper , */\ +{ 0x5e0, "sel_vbat"}, /* battery voltage for I2C read out only , */\ +{ 0x5f0, "bypass_clipper"}, /* bypass clipper battery protection , */\ +{ 0x600, "dpsa"}, /* Enable dynamic powerstage activation , */\ +{ 0x650, "cf_mute"}, /* Soft mute in CoolFlux , */\ +{ 0x670, "batsense_steepness"}, /* BatSenseSteepness , */\ +{ 0x687, "vol"}, /* volume control (in CoolFlux) , */\ +{ 0x702, "boost_volt"}, /* Boost Voltage , */\ +{ 0x733, "boost_cur"}, /* Max boost coil current - step of 175 mA , */\ +{ 0x7a0, "boost_intel"}, /* Adaptive boost mode , */\ +{ 0x7b0, "boost_speed"}, /* Soft RampUp/Down mode for DCDC controller , */\ +{ 0x7c0, "boost_peak2avg"}, /* ctrl_peak2avg for analog part of DCDC , */\ +{ 0x800, "ext_temp_sel"}, /* Select external temperature also the ext_temp will be put on the temp read out , */\ +{ 0x818, "ext_temp"}, /* external temperature setting to be given by host , */\ +{ 0x8b2, "dcdc_synchronisation"}, /* DCDC synchronisation off + 7 positions , */\ +{ 0x900, "powerdown"}, /* Device Mode , */\ +{ 0x910, "reset"}, /* I2C Reset , */\ +{ 0x920, "enbl_coolflux"}, /* Enable CoolFlux , */\ +{ 0x930, "enbl_amplifier"}, /* Enable Amplifier , */\ +{ 0x940, "enbl_boost"}, /* EnableBoost , */\ +{ 0x950, "coolflux_configured"}, /* Coolflux configured , */\ +{ 0x960, "sel_enbl_amplifier"}, /* Selection on how Amplifier is enabled , */\ +{ 0x970, "dcdcoff_mode"}, /* DCDC not connected , */\ +{ 0x980, "iddqtest"}, /* IDDQ test amplifier , */\ +{ 0x991, "coil_value"}, /* Coil Value , */\ +{ 0x9b0, "sel_cf_clock"}, /* Selection CoolFlux Clock , */\ +{ 0x9c1, "int_pad_io"}, /* INT pad configuration control , */\ +{ 0x9e0, "sel_fs_bck"}, /* PLL input reference clock selection , */\ +{ 0x9f0, "sel_scl_cf_clock"}, /* Coolflux sub-system clock , */\ +{ 0xb07, "mtpkey2"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ +{ 0xc00, "enbl_volt_sense"}, /* Voltage sense enabling control bit , */\ +{ 0xc10, "vsense_pwm_sel"}, /* Voltage sense PWM source selection control , */\ +{ 0xc25, "vi_frac_delay"}, /* Fractional delay adjustment between current and voltage sense, */\ +{ 0xc80, "sel_voltsense_out"}, /* TDM output data selection control , */\ +{ 0xc90, "vsense_bypass_avg"}, /* Voltage Sense Average Block Bypass , */\ +{ 0xd05, "cf_frac_delay"}, /* Fractional delay adjustment between current and voltage sense by firmware, */\ +{ 0xe00, "bypass_dcdc_curr_prot"}, /* Control to switch off dcdc current reduction with bat protection, */\ +{ 0xe80, "disable_clock_sh_prot"}, /* disable clock_sh protection , */\ +{ 0xe96, "reserve_reg_1_15_9"}, /* , */\ +{ 0x1011, "tdm_usecase"}, /* TDM_usecase , */\ +{ 0x1030, "tdm_enable"}, /* TDM interface control , */\ +{ 0x1040, "tdm_clk_inversion"}, /* TDM clock inversion , */\ +{ 0x1053, "tdm_fs_ws_length"}, /* TDM FS length , */\ +{ 0x1090, "tdm_fs_ws_polarity"}, /* TDM FS polarity , */\ +{ 0x10a4, "tdm_sample_size"}, /* TDM Sample Size for all tdm sinks/sources , */\ +{ 0x1103, "tdm_nb_of_slots"}, /* Number of slots , */\ +{ 0x1144, "tdm_slot_length"}, /* Slot length , */\ +{ 0x1194, "tdm_bits_remaining"}, /* Bits remaining , */\ +{ 0x11e0, "tdm_data_delay"}, /* Data delay , */\ +{ 0x11f0, "tdm_data_adjustment"}, /* Data adjustment , */\ +{ 0x1201, "tdm_txdata_format"}, /* TXDATA format , */\ +{ 0x1221, "tdm_txdata_format_unused_slot_sd0"}, /* TXDATA format unused slot sd0 , */\ +{ 0x1241, "tdm_txdata_format_unused_slot_sd1"}, /* TXDATA format unused slot sd1 , */\ +{ 0x1270, "tdm_sink0_enable"}, /* TDM sink0 enable , */\ +{ 0x1280, "tdm_sink1_enable"}, /* TDM sink1 enable , */\ +{ 0x1290, "tdm_sink2_enable"}, /* TDM sink2 enable , */\ +{ 0x12a0, "tdm_source0_enable"}, /* TDM source0 enable , */\ +{ 0x12b0, "tdm_source1_enable"}, /* TDM source1 enable , */\ +{ 0x12c0, "tdm_source2_enable"}, /* TDM source2 enable , */\ +{ 0x12d0, "tdm_sink0_io"}, /* tdm_sink0_io , */\ +{ 0x12e0, "tdm_sink1_io"}, /* tdm_sink1_io , */\ +{ 0x12f0, "tdm_sink2_io"}, /* tdm_sink2_io , */\ +{ 0x1300, "tdm_source0_io"}, /* tdm_source0_io , */\ +{ 0x1310, "tdm_source1_io"}, /* tdm_source1_io , */\ +{ 0x1320, "tdm_source2_io"}, /* tdm_source2_io , */\ +{ 0x1333, "tdm_sink0_slot"}, /* sink0_slot [GAIN IN] , */\ +{ 0x1373, "tdm_sink1_slot"}, /* sink1_slot [CH1 IN] , */\ +{ 0x13b3, "tdm_sink2_slot"}, /* sink2_slot [CH2 IN] , */\ +{ 0x1403, "tdm_source0_slot"}, /* source0_slot [GAIN OUT] , */\ +{ 0x1443, "tdm_source1_slot"}, /* source1_slot [Voltage Sense] , */\ +{ 0x1483, "tdm_source2_slot"}, /* source2_slot [Current Sense] , */\ +{ 0x14c3, "tdm_nbck"}, /* NBCK , */\ +{ 0x1500, "flag_tdm_lut_error"}, /* TDM LUT error flag , */\ +{ 0x1512, "flag_tdm_status"}, /* TDM interface status bits , */\ +{ 0x1540, "flag_tdm_error"}, /* TDM interface error indicator , */\ +{ 0x2000, "flag_por_int_out"}, /* flag_por_int_out , */\ +{ 0x2010, "flag_pll_lock_int_out"}, /* flag_pll_lock_int_out , */\ +{ 0x2020, "flag_otpok_int_out"}, /* flag_otpok_int_out , */\ +{ 0x2030, "flag_ovpok_int_out"}, /* flag_ovpok_int_out , */\ +{ 0x2040, "flag_uvpok_int_out"}, /* flag_uvpok_int_out , */\ +{ 0x2050, "flag_ocp_alarm_int_out"}, /* flag_ocp_alarm_int_out , */\ +{ 0x2060, "flag_clocks_stable_int_out"}, /* flag_clocks_stable_int_out , */\ +{ 0x2070, "flag_clip_int_out"}, /* flag_clip_int_out , */\ +{ 0x2080, "mtp_busy_int_out"}, /* mtp_busy_int_out , */\ +{ 0x2090, "flag_lost_clk_int_out"}, /* flag_lost_clk_int_out , */\ +{ 0x20a0, "flag_cf_speakererror_int_out"}, /* flag_cf_speakererror_int_out , */\ +{ 0x20b0, "flag_cold_started_int_out"}, /* flag_cold_started_int_out , */\ +{ 0x20c0, "flag_engage_int_out"}, /* flag_engage_int_out , */\ +{ 0x20d0, "flag_watchdog_reset_int_out"}, /* flag_watchdog_reset_int_out , */\ +{ 0x20e0, "flag_enbl_amp_int_out"}, /* flag_enbl_amp_int_out , */\ +{ 0x20f0, "flag_enbl_ref_int_out"}, /* flag_enbl_ref_int_out , */\ +{ 0x2100, "flag_voutcomp_int_out"}, /* flag_voutcomp_int_out , */\ +{ 0x2110, "flag_voutcomp93_int_out"}, /* flag_voutcomp93_int_out , */\ +{ 0x2120, "flag_voutcomp86_int_out"}, /* flag_voutcomp86_int_out , */\ +{ 0x2130, "flag_hiz_int_out"}, /* flag_hiz_int_out , */\ +{ 0x2140, "flag_ocpokbst_int_out"}, /* flag_ocpokbst_int_out , */\ +{ 0x2150, "flag_peakcur_int_out"}, /* flag_peakcur_int_out , */\ +{ 0x2160, "flag_ocpokap_int_out"}, /* flag_ocpokap_int_out , */\ +{ 0x2170, "flag_ocpokan_int_out"}, /* flag_ocpokan_int_out , */\ +{ 0x2180, "flag_ocpokbp_int_out"}, /* flag_ocpokbp_int_out , */\ +{ 0x2190, "flag_ocpokbn_int_out"}, /* flag_ocpokbn_int_out , */\ +{ 0x21a0, "flag_adc10_ready_int_out"}, /* flag_adc10_ready_int_out , */\ +{ 0x21b0, "flag_clipa_high_int_out"}, /* flag_clipa_high_int_out , */\ +{ 0x21c0, "flag_clipa_low_int_out"}, /* flag_clipa_low_int_out , */\ +{ 0x21d0, "flag_clipb_high_int_out"}, /* flag_clipb_high_int_out , */\ +{ 0x21e0, "flag_clipb_low_int_out"}, /* flag_clipb_low_int_out , */\ +{ 0x21f0, "flag_tdm_error_int_out"}, /* flag_tdm_error_int_out , */\ +{ 0x2201, "interrupt_out3"}, /* Interrupt status register output - Corresponding flag, */\ +{ 0x2300, "flag_por_int_in"}, /* flag_por_int_in , */\ +{ 0x2310, "flag_pll_lock_int_in"}, /* flag_pll_lock_int_in , */\ +{ 0x2320, "flag_otpok_int_in"}, /* flag_otpok_int_in , */\ +{ 0x2330, "flag_ovpok_int_in"}, /* flag_ovpok_int_in , */\ +{ 0x2340, "flag_uvpok_int_in"}, /* flag_uvpok_int_in , */\ +{ 0x2350, "flag_ocp_alarm_int_in"}, /* flag_ocp_alarm_int_in , */\ +{ 0x2360, "flag_clocks_stable_int_in"}, /* flag_clocks_stable_int_in , */\ +{ 0x2370, "flag_clip_int_in"}, /* flag_clip_int_in , */\ +{ 0x2380, "mtp_busy_int_in"}, /* mtp_busy_int_in , */\ +{ 0x2390, "flag_lost_clk_int_in"}, /* flag_lost_clk_int_in , */\ +{ 0x23a0, "flag_cf_speakererror_int_in"}, /* flag_cf_speakererror_int_in , */\ +{ 0x23b0, "flag_cold_started_int_in"}, /* flag_cold_started_int_in , */\ +{ 0x23c0, "flag_engage_int_in"}, /* flag_engage_int_in , */\ +{ 0x23d0, "flag_watchdog_reset_int_in"}, /* flag_watchdog_reset_int_in , */\ +{ 0x23e0, "flag_enbl_amp_int_in"}, /* flag_enbl_amp_int_in , */\ +{ 0x23f0, "flag_enbl_ref_int_in"}, /* flag_enbl_ref_int_in , */\ +{ 0x2400, "flag_voutcomp_int_in"}, /* flag_voutcomp_int_in , */\ +{ 0x2410, "flag_voutcomp93_int_in"}, /* flag_voutcomp93_int_in , */\ +{ 0x2420, "flag_voutcomp86_int_in"}, /* flag_voutcomp86_int_in , */\ +{ 0x2430, "flag_hiz_int_in"}, /* flag_hiz_int_in , */\ +{ 0x2440, "flag_ocpokbst_int_in"}, /* flag_ocpokbst_int_in , */\ +{ 0x2450, "flag_peakcur_int_in"}, /* flag_peakcur_int_in , */\ +{ 0x2460, "flag_ocpokap_int_in"}, /* flag_ocpokap_int_in , */\ +{ 0x2470, "flag_ocpokan_int_in"}, /* flag_ocpokan_int_in , */\ +{ 0x2480, "flag_ocpokbp_int_in"}, /* flag_ocpokbp_int_in , */\ +{ 0x2490, "flag_ocpokbn_int_in"}, /* flag_ocpokbn_int_in , */\ +{ 0x24a0, "flag_adc10_ready_int_in"}, /* flag_adc10_ready_int_in , */\ +{ 0x24b0, "flag_clipa_high_int_in"}, /* flag_clipa_high_int_in , */\ +{ 0x24c0, "flag_clipa_low_int_in"}, /* flag_clipa_low_int_in , */\ +{ 0x24d0, "flag_clipb_high_int_in"}, /* flag_clipb_high_int_in , */\ +{ 0x24e0, "flag_clipb_low_int_in"}, /* flag_clipb_low_int_in , */\ +{ 0x24f0, "flag_tdm_error_int_in"}, /* flag_tdm_error_int_in , */\ +{ 0x2501, "interrupt_in3"}, /* Interrupt register input , */\ +{ 0x2600, "flag_por_int_enable"}, /* flag_por_int_enable , */\ +{ 0x2610, "flag_pll_lock_int_enable"}, /* flag_pll_lock_int_enable , */\ +{ 0x2620, "flag_otpok_int_enable"}, /* flag_otpok_int_enable , */\ +{ 0x2630, "flag_ovpok_int_enable"}, /* flag_ovpok_int_enable , */\ +{ 0x2640, "flag_uvpok_int_enable"}, /* flag_uvpok_int_enable , */\ +{ 0x2650, "flag_ocp_alarm_int_enable"}, /* flag_ocp_alarm_int_enable , */\ +{ 0x2660, "flag_clocks_stable_int_enable"}, /* flag_clocks_stable_int_enable , */\ +{ 0x2670, "flag_clip_int_enable"}, /* flag_clip_int_enable , */\ +{ 0x2680, "mtp_busy_int_enable"}, /* mtp_busy_int_enable , */\ +{ 0x2690, "flag_lost_clk_int_enable"}, /* flag_lost_clk_int_enable , */\ +{ 0x26a0, "flag_cf_speakererror_int_enable"}, /* flag_cf_speakererror_int_enable , */\ +{ 0x26b0, "flag_cold_started_int_enable"}, /* flag_cold_started_int_enable , */\ +{ 0x26c0, "flag_engage_int_enable"}, /* flag_engage_int_enable , */\ +{ 0x26d0, "flag_watchdog_reset_int_enable"}, /* flag_watchdog_reset_int_enable , */\ +{ 0x26e0, "flag_enbl_amp_int_enable"}, /* flag_enbl_amp_int_enable , */\ +{ 0x26f0, "flag_enbl_ref_int_enable"}, /* flag_enbl_ref_int_enable , */\ +{ 0x2700, "flag_voutcomp_int_enable"}, /* flag_voutcomp_int_enable , */\ +{ 0x2710, "flag_voutcomp93_int_enable"}, /* flag_voutcomp93_int_enable , */\ +{ 0x2720, "flag_voutcomp86_int_enable"}, /* flag_voutcomp86_int_enable , */\ +{ 0x2730, "flag_hiz_int_enable"}, /* flag_hiz_int_enable , */\ +{ 0x2740, "flag_ocpokbst_int_enable"}, /* flag_ocpokbst_int_enable , */\ +{ 0x2750, "flag_peakcur_int_enable"}, /* flag_peakcur_int_enable , */\ +{ 0x2760, "flag_ocpokap_int_enable"}, /* flag_ocpokap_int_enable , */\ +{ 0x2770, "flag_ocpokan_int_enable"}, /* flag_ocpokan_int_enable , */\ +{ 0x2780, "flag_ocpokbp_int_enable"}, /* flag_ocpokbp_int_enable , */\ +{ 0x2790, "flag_ocpokbn_int_enable"}, /* flag_ocpokbn_int_enable , */\ +{ 0x27a0, "flag_adc10_ready_int_enable"}, /* flag_adc10_ready_int_enable , */\ +{ 0x27b0, "flag_clipa_high_int_enable"}, /* flag_clipa_high_int_enable , */\ +{ 0x27c0, "flag_clipa_low_int_enable"}, /* flag_clipa_low_int_enable , */\ +{ 0x27d0, "flag_clipb_high_int_enable"}, /* flag_clipb_high_int_enable , */\ +{ 0x27e0, "flag_clipb_low_int_enable"}, /* flag_clipb_low_int_enable , */\ +{ 0x27f0, "flag_tdm_error_int_enable"}, /* flag_tdm_error_int_enable , */\ +{ 0x2801, "interrupt_enable3"}, /* Interrupt enable register , */\ +{ 0x2900, "flag_por_int_pol"}, /* flag_por_int_pol , */\ +{ 0x2910, "flag_pll_lock_int_pol"}, /* flag_pll_lock_int_pol , */\ +{ 0x2920, "flag_otpok_int_pol"}, /* flag_otpok_int_pol , */\ +{ 0x2930, "flag_ovpok_int_pol"}, /* flag_ovpok_int_pol , */\ +{ 0x2940, "flag_uvpok_int_pol"}, /* flag_uvpok_int_pol , */\ +{ 0x2950, "flag_ocp_alarm_int_pol"}, /* flag_ocp_alarm_int_pol , */\ +{ 0x2960, "flag_clocks_stable_int_pol"}, /* flag_clocks_stable_int_pol , */\ +{ 0x2970, "flag_clip_int_pol"}, /* flag_clip_int_pol , */\ +{ 0x2980, "mtp_busy_int_pol"}, /* mtp_busy_int_pol , */\ +{ 0x2990, "flag_lost_clk_int_pol"}, /* flag_lost_clk_int_pol , */\ +{ 0x29a0, "flag_cf_speakererror_int_pol"}, /* flag_cf_speakererror_int_pol , */\ +{ 0x29b0, "flag_cold_started_int_pol"}, /* flag_cold_started_int_pol , */\ +{ 0x29c0, "flag_engage_int_pol"}, /* flag_engage_int_pol , */\ +{ 0x29d0, "flag_watchdog_reset_int_pol"}, /* flag_watchdog_reset_int_pol , */\ +{ 0x29e0, "flag_enbl_amp_int_pol"}, /* flag_enbl_amp_int_pol , */\ +{ 0x29f0, "flag_enbl_ref_int_pol"}, /* flag_enbl_ref_int_pol , */\ +{ 0x2a00, "flag_voutcomp_int_pol"}, /* flag_voutcomp_int_pol , */\ +{ 0x2a10, "flag_voutcomp93_int_pol"}, /* flag_voutcomp93_int_pol , */\ +{ 0x2a20, "flag_voutcomp86_int_pol"}, /* flag_voutcomp86_int_pol , */\ +{ 0x2a30, "flag_hiz_int_pol"}, /* flag_hiz_int_pol , */\ +{ 0x2a40, "flag_ocpokbst_int_pol"}, /* flag_ocpokbst_int_pol , */\ +{ 0x2a50, "flag_peakcur_int_pol"}, /* flag_peakcur_int_pol , */\ +{ 0x2a60, "flag_ocpokap_int_pol"}, /* flag_ocpokap_int_pol , */\ +{ 0x2a70, "flag_ocpokan_int_pol"}, /* flag_ocpokan_int_pol , */\ +{ 0x2a80, "flag_ocpokbp_int_pol"}, /* flag_ocpokbp_int_pol , */\ +{ 0x2a90, "flag_ocpokbn_int_pol"}, /* flag_ocpokbn_int_pol , */\ +{ 0x2aa0, "flag_adc10_ready_int_pol"}, /* flag_adc10_ready_int_pol , */\ +{ 0x2ab0, "flag_clipa_high_int_pol"}, /* flag_clipa_high_int_pol , */\ +{ 0x2ac0, "flag_clipa_low_int_pol"}, /* flag_clipa_low_int_pol , */\ +{ 0x2ad0, "flag_clipb_high_int_pol"}, /* flag_clipb_high_int_pol , */\ +{ 0x2ae0, "flag_clipb_low_int_pol"}, /* flag_clipb_low_int_pol , */\ +{ 0x2af0, "flag_tdm_error_int_pol"}, /* flag_tdm_error_int_pol , */\ +{ 0x2b01, "status_polarity3"}, /* Interrupt status flags polarity register , */\ +{ 0x3000, "flag_voutcomp"}, /* flag_voutcomp, indication Vset is larger than Vbat, */\ +{ 0x3010, "flag_voutcomp93"}, /* flag_voutcomp93, indication Vset is larger than 1.07* Vbat, */\ +{ 0x3020, "flag_voutcomp86"}, /* flag_voutcomp86, indication Vset is larger than 1.14* Vbat, */\ +{ 0x3030, "flag_hiz"}, /* flag_hiz, indication Vbst is larger than Vbat , */\ +{ 0x3040, "flag_ocpokbst"}, /* flag_ocpokbst, indication no over current in boost converter pmos switch, */\ +{ 0x3050, "flag_peakcur"}, /* flag_peakcur, indication current is max in dcdc converter, */\ +{ 0x3060, "flag_ocpokap"}, /* flag_ocpokap, indication no over current in amplifier "a" pmos output stage, */\ +{ 0x3070, "flag_ocpokan"}, /* flag_ocpokan, indication no over current in amplifier "a" nmos output stage, */\ +{ 0x3080, "flag_ocpokbp"}, /* flag_ocpokbp, indication no over current in amplifier "b" pmos output stage, */\ +{ 0x3090, "flag_ocpokbn"}, /* flag_ocpokbn, indication no over current in amplifier"b" nmos output stage, */\ +{ 0x30a0, "flag_adc10_ready"}, /* flag_adc10_ready, indication adc10 is ready , */\ +{ 0x30b0, "flag_clipa_high"}, /* flag_clipa_high, indication pmos amplifier "a" is clipping, */\ +{ 0x30c0, "flag_clipa_low"}, /* flag_clipa_low, indication nmos amplifier "a" is clipping, */\ +{ 0x30d0, "flag_clipb_high"}, /* flag_clipb_high, indication pmos amplifier "b" is clipping, */\ +{ 0x30e0, "flag_clipb_low"}, /* flag_clipb_low, indication nmos amplifier "b" is clipping, */\ +{ 0x310f, "mtp_man_data_out"}, /* single word read from MTP (manual copy) , */\ +{ 0x3200, "key01_locked"}, /* key01_locked, indication key 1 is locked , */\ +{ 0x3210, "key02_locked"}, /* key02_locked, indication key 2 is locked , */\ +{ 0x3225, "mtp_ecc_tcout"}, /* mtp_ecc_tcout , */\ +{ 0x3280, "mtpctrl_valid_test_rd"}, /* mtp test readout for read , */\ +{ 0x3290, "mtpctrl_valid_test_wr"}, /* mtp test readout for write , */\ +{ 0x32a0, "flag_in_alarm_state"}, /* Alarm state , */\ +{ 0x32b0, "mtp_ecc_err2"}, /* two or more bit errors detected in MTP, can not reconstruct value, */\ +{ 0x32c0, "mtp_ecc_err1"}, /* one bit error detected in MTP, reconstructed value, */\ +{ 0x32d0, "mtp_mtp_hvf"}, /* high voltage ready flag for MTP , */\ +{ 0x32f0, "mtp_zero_check_fail"}, /* zero check failed (tbd) for MTP , */\ +{ 0x3309, "data_adc10_tempbat"}, /* data_adc10_tempbat[9;0], adc 10 data output for testing, */\ +{ 0x400f, "hid_code"}, /* 5A6Bh, 23147d to access registers (Default for engineering), */\ +{ 0x4100, "bypass_hp"}, /* Bypass_High Pass Filter , */\ +{ 0x4110, "hard_mute"}, /* Hard Mute , */\ +{ 0x4120, "soft_mute"}, /* Soft Mute , */\ +{ 0x4134, "pwm_delay"}, /* PWM DelayBits to set the delay , */\ +{ 0x4180, "pwm_shape"}, /* PWM Shape , */\ +{ 0x4190, "pwm_bitlength"}, /* PWM Bitlength in noise shaper , */\ +{ 0x4203, "drive"}, /* Drive bits to select amount of power stage amplifier, */\ +{ 0x4240, "reclock_pwm"}, /* , */\ +{ 0x4250, "reclock_voltsense"}, /* , */\ +{ 0x4281, "dpsalevel"}, /* DPSA Threshold level , */\ +{ 0x42a1, "dpsa_release"}, /* DPSA Release time , */\ +{ 0x42c0, "coincidence"}, /* Prevent simultaneously switching of output stage , */\ +{ 0x42d0, "kickback"}, /* Prevent double pulses of output stage , */\ +{ 0x4306, "drivebst"}, /* Drive bits to select the powertransistor sections boost converter, */\ +{ 0x43a0, "ocptestbst"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0);For new ocp (ctrl_reversebst is 1);, */\ +{ 0x43d0, "test_abistfft_enbl"}, /* FFT coolflux , */\ +{ 0x43f0, "test_bcontrol"}, /* test _bcontrol , */\ +{ 0x4400, "reversebst"}, /* OverCurrent Protection selection of power stage boost converter, */\ +{ 0x4410, "sensetest"}, /* Test option for the sense NMOS in booster for current mode control., */\ +{ 0x4420, "enbl_engagebst"}, /* Enable power stage dcdc controller , */\ +{ 0x4470, "enbl_slopecur"}, /* Enable bit of max-current dac , */\ +{ 0x4480, "enbl_voutcomp"}, /* Enable vout comparators , */\ +{ 0x4490, "enbl_voutcomp93"}, /* Enable vout-93 comparators , */\ +{ 0x44a0, "enbl_voutcomp86"}, /* Enable vout-86 comparators , */\ +{ 0x44b0, "enbl_hizcom"}, /* Enable hiz comparator , */\ +{ 0x44c0, "enbl_peakcur"}, /* Enable peak current , */\ +{ 0x44d0, "bypass_ovpglitch"}, /* Bypass OVP Glitch Filter , */\ +{ 0x44e0, "enbl_windac"}, /* Enable window dac , */\ +{ 0x44f0, "enbl_powerbst"}, /* Enable line of the powerstage , */\ +{ 0x4507, "ocp_thr"}, /* ocp_thr threshold level for OCP , */\ +{ 0x4580, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ +{ 0x4590, "bypass_ovp"}, /* Bypass OVP , */\ +{ 0x45a0, "bypass_uvp"}, /* Bypass UVP , */\ +{ 0x45b0, "bypass_otp"}, /* Bypass OTP , */\ +{ 0x45c0, "bypass_ocp"}, /* Bypass OCP , */\ +{ 0x45d0, "bypass_ocpcounter"}, /* BypassOCPCounter , */\ +{ 0x45e0, "bypass_lost_clk"}, /* Bypasslost_clk detector , */\ +{ 0x45f0, "vpalarm"}, /* vpalarm (uvp ovp handling) , */\ +{ 0x4600, "bypass_gc"}, /* bypass_gc, bypasses the CS gain correction , */\ +{ 0x4610, "cs_gain_control"}, /* gain control by means of MTP or i2c; 0 is MTP , */\ +{ 0x4627, "cs_gain"}, /* + / - 128 steps in steps of 1/4 percent 2's compliment, */\ +{ 0x46a0, "bypass_lp"}, /* bypass Low-Pass filter in temperature sensor , */\ +{ 0x46b0, "bypass_pwmcounter"}, /* bypass_pwmcounter , */\ +{ 0x46c0, "cs_negfixed"}, /* does not switch to neg , */\ +{ 0x46d2, "cs_neghyst"}, /* switches to neg depending on level , */\ +{ 0x4700, "switch_fb"}, /* switch_fb , */\ +{ 0x4713, "se_hyst"}, /* se_hyst , */\ +{ 0x4754, "se_level"}, /* se_level , */\ +{ 0x47a5, "ktemp"}, /* temperature compensation trimming , */\ +{ 0x4800, "cs_negin"}, /* negin , */\ +{ 0x4810, "cs_sein"}, /* cs_sein , */\ +{ 0x4820, "cs_coincidence"}, /* Coincidence current sense , */\ +{ 0x4830, "iddqtestbst"}, /* for iddq testing in powerstage of boost convertor , */\ +{ 0x4840, "coincidencebst"}, /* Switch protection on to prevent simultaneously switching power stages bst and amp, */\ +{ 0x4876, "delay_se_neg"}, /* delay of se and neg , */\ +{ 0x48e1, "cs_ttrack"}, /* sample & hold track time , */\ +{ 0x4900, "bypass_clip"}, /* Bypass clip control , */\ +{ 0x4920, "cf_cgate_off"}, /* to disable clock gating in the coolflux , */\ +{ 0x4940, "clipfast"}, /* clock switch for battery protection clipper, it switches back to old frequency, */\ +{ 0x4950, "cs_8ohm"}, /* 8 ohm mode for current sense (gain mode) , */\ +{ 0x4974, "delay_clock_sh"}, /* delay_sh, tunes S7H delay , */\ +{ 0x49c0, "inv_clksh"}, /* Invert the sample/hold clock for current sense ADC, */\ +{ 0x49d0, "inv_neg"}, /* Invert neg signal , */\ +{ 0x49e0, "inv_se"}, /* Invert se signal , */\ +{ 0x49f0, "setse"}, /* switches between Single Ende and differential mode; 1 is single ended, */\ +{ 0x4a12, "adc10_sel"}, /* select the input to convert the 10b ADC , */\ +{ 0x4a60, "adc10_reset"}, /* Global asynchronous reset (active HIGH) 10 bit ADC, */\ +{ 0x4a81, "adc10_test"}, /* Test mode selection signal 10 bit ADC , */\ +{ 0x4aa0, "bypass_lp_vbat"}, /* lp filter in batt sensor , */\ +{ 0x4ae0, "dc_offset"}, /* switch offset control on/off, is decimator offset control, */\ +{ 0x4af0, "tsense_hibias"}, /* bit to set the biasing in temp sensor to high , */\ +{ 0x4b00, "adc13_iset"}, /* Micadc Setting of current consumption. Debug use only, */\ +{ 0x4b14, "adc13_gain"}, /* Micadc gain setting (2-compl) , */\ +{ 0x4b61, "adc13_slowdel"}, /* Micadc Delay setting for internal clock. Debug use only, */\ +{ 0x4b83, "adc13_offset"}, /* Micadc ADC offset setting , */\ +{ 0x4bc0, "adc13_bsoinv"}, /* Micadc bit stream output invert mode for test , */\ +{ 0x4bd0, "adc13_resonator_enable"}, /* Micadc Give extra SNR with less stability. Debug use only, */\ +{ 0x4be0, "testmicadc"}, /* Mux at input of MICADC for test purpose , */\ +{ 0x4c0f, "abist_offset"}, /* offset control for ABIST testing , */\ +{ 0x4d05, "windac"}, /* for testing direct control windac , */\ +{ 0x4dc3, "pwm_dcc_cnt"}, /* control pwm duty cycle when enbl_pwm_dcc is 1 , */\ +{ 0x4e04, "slopecur"}, /* for testing direct control slopecur , */\ +{ 0x4e50, "ctrl_dem"}, /* dyn element matching control, rest of codes are optional, */\ +{ 0x4ed0, "enbl_pwm_dcc"}, /* to enable direct control of pwm duty cycle , */\ +{ 0x5007, "gain"}, /* Gain setting of the gain multiplier , */\ +{ 0x5081, "sourceb"}, /* Set OUTB to , */\ +{ 0x50a1, "sourcea"}, /* Set OUTA to , */\ +{ 0x50c1, "sourcebst"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ +{ 0x50e0, "tdm_enable_loopback"}, /* TDM loopback test , */\ +{ 0x5104, "pulselengthbst"}, /* pulse length setting test input for boost converter, */\ +{ 0x5150, "bypasslatchbst"}, /* bypass_latch in boost converter , */\ +{ 0x5160, "invertbst"}, /* invert pwmbst test signal , */\ +{ 0x5174, "pulselength"}, /* pulse length setting test input for amplifier , */\ +{ 0x51c0, "bypasslatch"}, /* bypass_latch in PWM source selection module , */\ +{ 0x51d0, "invertb"}, /* invert pwmb test signal , */\ +{ 0x51e0, "inverta"}, /* invert pwma test signal , */\ +{ 0x51f0, "bypass_ctrlloop"}, /* bypass_ctrlloop bypasses the control loop of the amplifier, */\ +{ 0x5210, "test_rdsona"}, /* tbd for rdson testing , */\ +{ 0x5220, "test_rdsonb"}, /* tbd for rdson testing , */\ +{ 0x5230, "test_rdsonbst"}, /* tbd for rdson testing , */\ +{ 0x5240, "test_cvia"}, /* tbd for rdson testing , */\ +{ 0x5250, "test_cvib"}, /* tbd for rdson testing , */\ +{ 0x5260, "test_cvibst"}, /* tbd for rdson testing , */\ +{ 0x5306, "digimuxa_sel"}, /* DigimuxA input selection control (see Digimux list for details), */\ +{ 0x5376, "digimuxb_sel"}, /* DigimuxB input selection control (see Digimux list for details), */\ +{ 0x5400, "hs_mode"}, /* hs_mode, high speed mode I2C bus , */\ +{ 0x5412, "test_parametric_io"}, /* test_parametric_io for testing pads , */\ +{ 0x5440, "enbl_ringo"}, /* enbl_ringo, for test purpose to check with ringo , */\ +{ 0x5456, "digimuxc_sel"}, /* DigimuxC input selection control (see Digimux list for details), */\ +{ 0x54c0, "dio_ehs"}, /* Slew control for DIO in output mode , */\ +{ 0x54d0, "gainio_ehs"}, /* Slew control for GAINIO in output mode , */\ +{ 0x550d, "enbl_amp"}, /* enbl_amp for testing to enable all analoge blocks in amplifier, */\ +{ 0x5600, "use_direct_ctrls"}, /* use_direct_ctrls, to overrule several functions direct for testing, */\ +{ 0x5610, "rst_datapath"}, /* rst_datapath, datapath reset , */\ +{ 0x5620, "rst_cgu"}, /* rst_cgu, cgu reset , */\ +{ 0x5637, "enbl_ref"}, /* for testing to enable all analoge blocks in references, */\ +{ 0x56b0, "enbl_engage"}, /* Enable output stage amplifier , */\ +{ 0x56c0, "use_direct_clk_ctrl"}, /* use_direct_clk_ctrl, to overrule several functions direct for testing, */\ +{ 0x56d0, "use_direct_pll_ctrl"}, /* use_direct_pll_ctrl, to overrule several functions direct for testing, */\ +{ 0x56e0, "use_direct_ctrls_2"}, /* use_direct_sourseamp_ctrls, to overrule several functions direct for testing, */\ +{ 0x5707, "anamux"}, /* Anamux control , */\ +{ 0x57c0, "ocptest"}, /* ctrl_ocptest, deactivates the over current protection in the power stages of the amplifier. The ocp flag signals stay active., */\ +{ 0x57e0, "otptest"}, /* otptest, test mode otp amplifier , */\ +{ 0x57f0, "reverse"}, /* 1: Normal mode, slope is controlled , */\ +{ 0x5813, "pll_selr"}, /* pll_selr , */\ +{ 0x5854, "pll_selp"}, /* pll_selp , */\ +{ 0x58a5, "pll_seli"}, /* pll_seli , */\ +{ 0x5950, "pll_mdec_msb"}, /* most significant bits of pll_mdec[16] , */\ +{ 0x5960, "pll_ndec_msb"}, /* most significant bits of pll_ndec[9] , */\ +{ 0x5970, "pll_frm"}, /* pll_frm , */\ +{ 0x5980, "pll_directi"}, /* pll_directi , */\ +{ 0x5990, "pll_directo"}, /* pll_directo , */\ +{ 0x59a0, "enbl_pll"}, /* enbl_pll , */\ +{ 0x59f0, "pll_bypass"}, /* pll_bypass , */\ +{ 0x5a0f, "tsig_freq"}, /* tsig_freq, internal sinus test generator, frequency control, */\ +{ 0x5b02, "tsig_freq_msb"}, /* select internal sinus test generator, frequency control msb bits, */\ +{ 0x5b30, "inject_tsig"}, /* inject_tsig, control bit to switch to internal sinus test generator, */\ +{ 0x5b44, "adc10_prog_sample"}, /* control ADC10 , */\ +{ 0x5c0f, "pll_mdec"}, /* bits 15..0 of pll_mdec[16;0] , */\ +{ 0x5d06, "pll_pdec"}, /* pll_pdec , */\ +{ 0x5d78, "pll_ndec"}, /* bits 8..0 of pll_ndec[9;0] , */\ +{ 0x6007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ +{ 0x6185, "mtp_ecc_tcin"}, /* Mtp_ecc_tcin , */\ +{ 0x6203, "mtp_man_address_in"}, /* address from I2C regs for writing one word single mtp, */\ +{ 0x6260, "mtp_ecc_eeb"}, /* enable code bit generation (active low!) , */\ +{ 0x6270, "mtp_ecc_ecb"}, /* enable correction signal (active low!) , */\ +{ 0x6280, "man_copy_mtp_to_iic"}, /* start copying single word from mtp to i2cregs_mtp , */\ +{ 0x6290, "man_copy_iic_to_mtp"}, /* start copying single word from i2cregs_mtp to mtp [Key 1 protected], */\ +{ 0x62a0, "auto_copy_mtp_to_iic"}, /* start copying all the data from mtp to i2cregs_mtp, */\ +{ 0x62b0, "auto_copy_iic_to_mtp"}, /* start copying all the data from i2cregs_mtp to mtp [Key 2 protected], */\ +{ 0x62d2, "mtp_speed_mode"}, /* Speed mode , */\ +{ 0x6340, "mtp_direct_enable"}, /* mtp_direct_enable (key1 protected) , */\ +{ 0x6350, "mtp_direct_wr"}, /* mtp_direct_wr (key1 protected) , */\ +{ 0x6360, "mtp_direct_rd"}, /* mtp_direct_rd (key1 protected) , */\ +{ 0x6370, "mtp_direct_rst"}, /* mtp_direct_rst (key1 protected) , */\ +{ 0x6380, "mtp_direct_ers"}, /* mtp_direct_ers (key1 protected) , */\ +{ 0x6390, "mtp_direct_prg"}, /* mtp_direct_prg (key1 protected) , */\ +{ 0x63a0, "mtp_direct_epp"}, /* mtp_direct_epp (key1 protected) , */\ +{ 0x63b4, "mtp_direct_test"}, /* mtp_direct_test (key1 protected) , */\ +{ 0x640f, "mtp_man_data_in"}, /* single word to be written to MTP (manual copy) , */\ +{ 0x7000, "cf_rst_dsp"}, /* Reset CoolFlux DSP , */\ +{ 0x7011, "cf_dmem"}, /* Target memory for access , */\ +{ 0x7030, "cf_aif"}, /* Autoincrement-flag for memory-address , */\ +{ 0x7040, "cf_int"}, /* Interrupt CoolFlux DSP , */\ +{ 0x7087, "cf_req"}, /* request for access (8 channels) , */\ +{ 0x710f, "cf_madd"}, /* memory-address to be accessed , */\ +{ 0x720f, "cf_mema"}, /* activate memory access (24- or 32-bits data is written/read to/from memory, */\ +{ 0x7307, "cf_err"}, /* Coolflux error flags , */\ +{ 0x7387, "cf_ack"}, /* acknowledge of requests (8 channels) , */\ +{ 0x8000, "calibration_onetime"}, /* Calibration schedule (key2 protected) , */\ +{ 0x8010, "calibr_ron_done"}, /* (key2 protected) , */\ +{ 0x8105, "calibr_vout_offset"}, /* calibr_vout_offset (DCDCoffset) 2's compliment (key1 protected), */\ +{ 0x8163, "calibr_delta_gain"}, /* delta gain for vamp (alpha) 2's compliment (key1 protected), */\ +{ 0x81a5, "calibr_offs_amp"}, /* offset for vamp (Ampoffset) 2's compliment (key1 protected), */\ +{ 0x8207, "calibr_gain_cs"}, /* gain current sense (Imeasalpha) 2's compliment (key1 protected), */\ +{ 0x8284, "calibr_temp_offset"}, /* temperature offset 2's compliment (key1 protected), */\ +{ 0x82d2, "calibr_temp_gain"}, /* temperature gain 2's compliment (key1 protected) , */\ +{ 0x830f, "calibr_ron"}, /* Ron resistance of coil (key1 protected) , */\ +{ 0x8505, "type_bits_HW"}, /* Key1_Protected_MTP5 , */\ +{ 0x8601, "type_bits_1_0_SW"}, /* MTP-control SW , */\ +{ 0x8681, "type_bits_8_9_SW"}, /* MTP-control SW , */\ +{ 0x870f, "type_bits2_SW"}, /* MTP-control SW2 , */\ +{ 0x8806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ +{ 0x8870, "htol_iic_addr_en"}, /* HTOL_I2C_Address_Enable , */\ +{ 0x8881, "ctrl_ovp_response"}, /* OVP response control , */\ +{ 0x88a0, "disable_ovp_alarm_state"}, /* OVP alarm state control , */\ +{ 0x88b0, "enbl_stretch_ovp"}, /* OVP alram strech control , */\ +{ 0x88c0, "cf_debug_mode"}, /* Coolflux debug mode , */\ +{ 0x8a0f, "production_data1"}, /* (key1 protected) , */\ +{ 0x8b0f, "production_data2"}, /* (key1 protected) , */\ +{ 0x8c0f, "production_data3"}, /* (key1 protected) , */\ +{ 0x8d0f, "production_data4"}, /* (key1 protected) , */\ +{ 0x8e0f, "production_data5"}, /* (key1 protected) , */\ +{ 0x8f0f, "production_data6"}, /* (key1 protected) , */\ +{ 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa1_irq { +tfa1_irq_vdds = 0, +tfa1_irq_plls = 1, +tfa1_irq_ds = 2, +tfa1_irq_vds = 3, +tfa1_irq_uvds = 4, +tfa1_irq_cds = 5, +tfa1_irq_clks = 6, +tfa1_irq_clips = 7, +tfa1_irq_mtpb = 8, +tfa1_irq_clk = 9, +tfa1_irq_spks = 10, +tfa1_irq_acs = 11, +tfa1_irq_sws = 12, +tfa1_irq_wds = 13, +tfa1_irq_amps = 14, +tfa1_irq_arefs = 15, +tfa1_irq_ack = 32, +tfa1_irq_max = 33, +tfa1_irq_all = -1 /* all irqs */}; + +#define TFA1_IRQ_NAMETABLE static tfaIrqName_t Tfa1IrqNames[] = {\ +{ 0, "VDDS"},\ +{ 1, "PLLS"},\ +{ 2, "DS"},\ +{ 3, "VDS"},\ +{ 4, "UVDS"},\ +{ 5, "CDS"},\ +{ 6, "CLKS"},\ +{ 7, "CLIPS"},\ +{ 8, "MTPB"},\ +{ 9, "CLK"},\ +{ 10, "SPKS"},\ +{ 11, "ACS"},\ +{ 12, "SWS"},\ +{ 13, "WDS"},\ +{ 14, "AMPS"},\ +{ 15, "AREFS"},\ +{ 16, "16"},\ +{ 17, "17"},\ +{ 18, "18"},\ +{ 19, "19"},\ +{ 20, "20"},\ +{ 21, "21"},\ +{ 22, "22"},\ +{ 23, "23"},\ +{ 24, "24"},\ +{ 25, "25"},\ +{ 26, "26"},\ +{ 27, "27"},\ +{ 28, "28"},\ +{ 29, "29"},\ +{ 30, "30"},\ +{ 31, "31"},\ +{ 32, "ACK"},\ +{ 33, "33"},\ +}; diff --git a/sound/soc/codecs/tfa2_tfafieldnames_N1C.h b/sound/soc/codecs/tfa2_tfafieldnames_N1C.h new file mode 100644 index 000000000000..2bd61cc66de8 --- /dev/null +++ b/sound/soc/codecs/tfa2_tfafieldnames_N1C.h @@ -0,0 +1,1526 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ +#define TFA9888_I2CVERSION 18 +typedef enum nxpTfa2BfEnumList { + TFA2_BF_PWDN = 0x0000, /*!< Powerdown selection */ + TFA2_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA2_BF_CFE = 0x0020, /*!< Enable CoolFlux */ + TFA2_BF_AMPE = 0x0030, /*!< Activate Amplifier */ + TFA2_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ + TFA2_BF_SBSL = 0x0050, /*!< Coolflux configured */ + TFA2_BF_AMPC = 0x0060, /*!< CoolFlux controls amplifier */ + TFA2_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA2_BF_FSSSEL = 0x0091, /*!< Audio sample reference */ + TFA2_BF_BYPOCP = 0x00b0, /*!< Bypass OCP */ + TFA2_BF_TSTOCP = 0x00c0, /*!< OCP testing control */ + TFA2_BF_AMPINSEL = 0x0101, /*!< Amplifier input selection */ + TFA2_BF_MANSCONF = 0x0120, /*!< I2C configured */ + TFA2_BF_MANCOLD = 0x0130, /*!< Execute cold start */ + TFA2_BF_MANAOOSC = 0x0140, /*!< Internal osc off at PWDN */ + TFA2_BF_MANROBOD = 0x0150, /*!< Reaction on BOD */ + TFA2_BF_BODE = 0x0160, /*!< BOD Enable */ + TFA2_BF_BODHYS = 0x0170, /*!< BOD Hysteresis */ + TFA2_BF_BODFILT = 0x0181, /*!< BOD filter */ + TFA2_BF_BODTHLVL = 0x01a1, /*!< BOD threshold */ + TFA2_BF_MUTETO = 0x01d0, /*!< Time out SB mute sequence */ + TFA2_BF_RCVNS = 0x01e0, /*!< Noise shaper selection */ + TFA2_BF_MANWDE = 0x01f0, /*!< Watchdog manager reaction */ + TFA2_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ + TFA2_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ + TFA2_BF_FRACTDEL = 0x0255, /*!< V/I Fractional delay */ + TFA2_BF_BYPHVBF = 0x02b0, /*!< Bypass HVBAT filter */ + TFA2_BF_LDOBYP = 0x02c0, /*!< Receiver LDO bypass */ + TFA2_BF_REV = 0x030f, /*!< Revision info */ + TFA2_BF_REFCKEXT = 0x0401, /*!< PLL external ref clock */ + TFA2_BF_REFCKSEL = 0x0420, /*!< PLL internal ref clock */ + TFA2_BF_SSLEFTE = 0x0500, /*!< Enable left channel */ + TFA2_BF_SSRIGHTE = 0x0510, /*!< Enable right channel */ + TFA2_BF_VSLEFTE = 0x0520, /*!< Voltage sense left */ + TFA2_BF_VSRIGHTE = 0x0530, /*!< Voltage sense right */ + TFA2_BF_CSLEFTE = 0x0540, /*!< Current sense left */ + TFA2_BF_CSRIGHTE = 0x0550, /*!< Current sense right */ + TFA2_BF_SSPDME = 0x0560, /*!< Sub-system PDM */ + TFA2_BF_STGAIN = 0x0d18, /*!< Side tone gain */ + TFA2_BF_PDMSMUTE = 0x0da0, /*!< Side tone soft mute */ + TFA2_BF_SWVSTEP = 0x0e06, /*!< Register for the host SW to record the current active vstep */ + TFA2_BF_VDDS = 0x1000, /*!< POR */ + TFA2_BF_PLLS = 0x1010, /*!< PLL lock */ + TFA2_BF_OTDS = 0x1020, /*!< OTP alarm */ + TFA2_BF_OVDS = 0x1030, /*!< OVP alarm */ + TFA2_BF_UVDS = 0x1040, /*!< UVP alarm */ + TFA2_BF_CLKS = 0x1050, /*!< Clocks stable */ + TFA2_BF_MTPB = 0x1060, /*!< MTP busy */ + TFA2_BF_NOCLK = 0x1070, /*!< Lost clock */ + TFA2_BF_SPKS = 0x1080, /*!< Speaker error */ + TFA2_BF_ACS = 0x1090, /*!< Cold Start */ + TFA2_BF_SWS = 0x10a0, /*!< Amplifier engage */ + TFA2_BF_WDS = 0x10b0, /*!< Watchdog */ + TFA2_BF_AMPS = 0x10c0, /*!< Amplifier enable */ + TFA2_BF_AREFS = 0x10d0, /*!< References enable */ + TFA2_BF_ADCCR = 0x10e0, /*!< Control ADC */ + TFA2_BF_BODNOK = 0x10f0, /*!< BOD */ + TFA2_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA2_BF_DCDCA = 0x1110, /*!< DCDC active */ + TFA2_BF_DCOCPOK = 0x1120, /*!< DCDC OCP nmos */ + TFA2_BF_DCHVBAT = 0x1140, /*!< DCDC level 1x */ + TFA2_BF_DCH114 = 0x1150, /*!< DCDC level 1.14x */ + TFA2_BF_DCH107 = 0x1160, /*!< DCDC level 1.07x */ + TFA2_BF_STMUTEB = 0x1170, /*!< side tone (un)mute busy */ + TFA2_BF_STMUTE = 0x1180, /*!< side tone mute state */ + TFA2_BF_TDMLUTER = 0x1190, /*!< TDM LUT error */ + TFA2_BF_TDMSTAT = 0x11a2, /*!< TDM status bits */ + TFA2_BF_TDMERR = 0x11d0, /*!< TDM error */ + TFA2_BF_HAPTIC = 0x11e0, /*!< Status haptic driver */ + TFA2_BF_OCPOAPL = 0x1200, /*!< OCPOK pmos A left */ + TFA2_BF_OCPOANL = 0x1210, /*!< OCPOK nmos A left */ + TFA2_BF_OCPOBPL = 0x1220, /*!< OCPOK pmos B left */ + TFA2_BF_OCPOBNL = 0x1230, /*!< OCPOK nmos B left */ + TFA2_BF_CLIPAHL = 0x1240, /*!< Clipping A left to Vddp */ + TFA2_BF_CLIPALL = 0x1250, /*!< Clipping A left to gnd */ + TFA2_BF_CLIPBHL = 0x1260, /*!< Clipping B left to Vddp */ + TFA2_BF_CLIPBLL = 0x1270, /*!< Clipping B left to gnd */ + TFA2_BF_OCPOAPRC = 0x1280, /*!< OCPOK pmos A RCV */ + TFA2_BF_OCPOANRC = 0x1290, /*!< OCPOK nmos A RCV */ + TFA2_BF_OCPOBPRC = 0x12a0, /*!< OCPOK pmos B RCV */ + TFA2_BF_OCPOBNRC = 0x12b0, /*!< OCPOK nmos B RCV */ + TFA2_BF_RCVLDOR = 0x12c0, /*!< RCV LDO regulates */ + TFA2_BF_RCVLDOBR = 0x12d0, /*!< Receiver LDO ready */ + TFA2_BF_OCDSL = 0x12e0, /*!< OCP left amplifier */ + TFA2_BF_CLIPSL = 0x12f0, /*!< Amplifier left clipping */ + TFA2_BF_OCPOAPR = 0x1300, /*!< OCPOK pmos A right */ + TFA2_BF_OCPOANR = 0x1310, /*!< OCPOK nmos A right */ + TFA2_BF_OCPOBPR = 0x1320, /*!< OCPOK pmos B right */ + TFA2_BF_OCPOBNR = 0x1330, /*!< OCPOK nmos B right */ + TFA2_BF_CLIPAHR = 0x1340, /*!< Clipping A right to Vddp */ + TFA2_BF_CLIPALR = 0x1350, /*!< Clipping A right to gnd */ + TFA2_BF_CLIPBHR = 0x1360, /*!< Clipping B left to Vddp */ + TFA2_BF_CLIPBLR = 0x1370, /*!< Clipping B right to gnd */ + TFA2_BF_OCDSR = 0x1380, /*!< OCP right amplifier */ + TFA2_BF_CLIPSR = 0x1390, /*!< Amplifier right clipping */ + TFA2_BF_OCPOKMC = 0x13a0, /*!< OCPOK MICVDD */ + TFA2_BF_MANALARM = 0x13b0, /*!< Alarm state */ + TFA2_BF_MANWAIT1 = 0x13c0, /*!< Wait HW I2C settings */ + TFA2_BF_MANWAIT2 = 0x13d0, /*!< Wait CF config */ + TFA2_BF_MANMUTE = 0x13e0, /*!< Audio mute sequence */ + TFA2_BF_MANOPER = 0x13f0, /*!< Operating state */ + TFA2_BF_SPKSL = 0x1400, /*!< Left speaker status */ + TFA2_BF_SPKSR = 0x1410, /*!< Right speaker status */ + TFA2_BF_CLKOOR = 0x1420, /*!< External clock status */ + TFA2_BF_MANSTATE = 0x1433, /*!< Device manager status */ + TFA2_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA2_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA2_BF_TDMUC = 0x2003, /*!< Usecase setting */ + TFA2_BF_TDME = 0x2040, /*!< Enable interface */ + TFA2_BF_TDMMODE = 0x2050, /*!< Slave/master */ + TFA2_BF_TDMCLINV = 0x2060, /*!< Reception data to BCK clock */ + TFA2_BF_TDMFSLN = 0x2073, /*!< FS length (master mode only) */ + TFA2_BF_TDMFSPOL = 0x20b0, /*!< FS polarity */ + TFA2_BF_TDMNBCK = 0x20c3, /*!< N-BCK's in FS */ + TFA2_BF_TDMSLOTS = 0x2103, /*!< N-slots in Frame */ + TFA2_BF_TDMSLLN = 0x2144, /*!< N-bits in slot */ + TFA2_BF_TDMBRMG = 0x2194, /*!< N-bits remaining */ + TFA2_BF_TDMDEL = 0x21e0, /*!< data delay to FS */ + TFA2_BF_TDMADJ = 0x21f0, /*!< data adjustment */ + TFA2_BF_TDMOOMP = 0x2201, /*!< Received audio compression */ + TFA2_BF_TDMSSIZE = 0x2224, /*!< Sample size per slot */ + TFA2_BF_TDMTXDFO = 0x2271, /*!< Format unused bits */ + TFA2_BF_TDMTXUS0 = 0x2291, /*!< Format unused slots GAINIO */ + TFA2_BF_TDMTXUS1 = 0x22b1, /*!< Format unused slots DIO1 */ + TFA2_BF_TDMTXUS2 = 0x22d1, /*!< Format unused slots DIO2 */ + TFA2_BF_TDMLE = 0x2310, /*!< Control audio left */ + TFA2_BF_TDMRE = 0x2320, /*!< Control audio right */ + TFA2_BF_TDMVSRE = 0x2340, /*!< Control voltage sense right */ + TFA2_BF_TDMCSRE = 0x2350, /*!< Control current sense right */ + TFA2_BF_TDMVSLE = 0x2360, /*!< Voltage sense left control */ + TFA2_BF_TDMCSLE = 0x2370, /*!< Current sense left control */ + TFA2_BF_TDMCFRE = 0x2380, /*!< DSP out right control */ + TFA2_BF_TDMCFLE = 0x2390, /*!< DSP out left control */ + TFA2_BF_TDMCF3E = 0x23a0, /*!< AEC ref left control */ + TFA2_BF_TDMCF4E = 0x23b0, /*!< AEC ref right control */ + TFA2_BF_TDMPD1E = 0x23c0, /*!< PDM 1 control */ + TFA2_BF_TDMPD2E = 0x23d0, /*!< PDM 2 control */ + TFA2_BF_TDMLIO = 0x2421, /*!< IO audio left */ + TFA2_BF_TDMRIO = 0x2441, /*!< IO audio right */ + TFA2_BF_TDMVSRIO = 0x2481, /*!< IO voltage sense right */ + TFA2_BF_TDMCSRIO = 0x24a1, /*!< IO current sense right */ + TFA2_BF_TDMVSLIO = 0x24c1, /*!< IO voltage sense left */ + TFA2_BF_TDMCSLIO = 0x24e1, /*!< IO current sense left */ + TFA2_BF_TDMCFRIO = 0x2501, /*!< IO dspout right */ + TFA2_BF_TDMCFLIO = 0x2521, /*!< IO dspout left */ + TFA2_BF_TDMCF3IO = 0x2541, /*!< IO AEC ref left control */ + TFA2_BF_TDMCF4IO = 0x2561, /*!< IO AEC ref right control */ + TFA2_BF_TDMPD1IO = 0x2581, /*!< IO pdm1 */ + TFA2_BF_TDMPD2IO = 0x25a1, /*!< IO pdm2 */ + TFA2_BF_TDMLS = 0x2643, /*!< Position audio left */ + TFA2_BF_TDMRS = 0x2683, /*!< Position audio right */ + TFA2_BF_TDMVSRS = 0x2703, /*!< Position voltage sense right */ + TFA2_BF_TDMCSRS = 0x2743, /*!< Position current sense right */ + TFA2_BF_TDMVSLS = 0x2783, /*!< Position voltage sense left */ + TFA2_BF_TDMCSLS = 0x27c3, /*!< Position current sense left */ + TFA2_BF_TDMCFRS = 0x2803, /*!< Position dspout right */ + TFA2_BF_TDMCFLS = 0x2843, /*!< Position dspout left */ + TFA2_BF_TDMCF3S = 0x2883, /*!< Position AEC ref left control */ + TFA2_BF_TDMCF4S = 0x28c3, /*!< Position AEC ref right control */ + TFA2_BF_TDMPD1S = 0x2903, /*!< Position pdm1 */ + TFA2_BF_TDMPD2S = 0x2943, /*!< Position pdm2 */ + TFA2_BF_PDMSM = 0x3100, /*!< PDM control */ + TFA2_BF_PDMSTSEL = 0x3111, /*!< Side tone input */ + TFA2_BF_PDMLSEL = 0x3130, /*!< PDM data selection for left channel during PDM direct mode */ + TFA2_BF_PDMRSEL = 0x3140, /*!< PDM data selection for right channel during PDM direct mode */ + TFA2_BF_MICVDDE = 0x3150, /*!< Enable MICVDD */ + TFA2_BF_PDMCLRAT = 0x3201, /*!< PDM BCK/Fs ratio */ + TFA2_BF_PDMGAIN = 0x3223, /*!< PDM gain */ + TFA2_BF_PDMOSEL = 0x3263, /*!< PDM output selection - RE/FE data combination */ + TFA2_BF_SELCFHAPD = 0x32a0, /*!< Select the source for haptic data output (not for customer) */ + TFA2_BF_HAPTIME = 0x3307, /*!< Duration (ms) */ + TFA2_BF_HAPLEVEL = 0x3387, /*!< DC value (FFS) */ + TFA2_BF_GPIODIN = 0x3403, /*!< Receiving value */ + TFA2_BF_GPIOCTRL = 0x3500, /*!< GPIO master control over GPIO1/2 ports (not for customer) */ + TFA2_BF_GPIOCONF = 0x3513, /*!< Configuration */ + TFA2_BF_GPIODOUT = 0x3553, /*!< Transmitting value */ + TFA2_BF_ISTVDDS = 0x4000, /*!< Status POR */ + TFA2_BF_ISTPLLS = 0x4010, /*!< Status PLL lock */ + TFA2_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ + TFA2_BF_ISTOVDS = 0x4030, /*!< Status OVP alarm */ + TFA2_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ + TFA2_BF_ISTCLKS = 0x4050, /*!< Status clocks stable */ + TFA2_BF_ISTMTPB = 0x4060, /*!< Status MTP busy */ + TFA2_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ + TFA2_BF_ISTSPKS = 0x4080, /*!< Status speaker error */ + TFA2_BF_ISTACS = 0x4090, /*!< Status cold start */ + TFA2_BF_ISTSWS = 0x40a0, /*!< Status amplifier engage */ + TFA2_BF_ISTWDS = 0x40b0, /*!< Status watchdog */ + TFA2_BF_ISTAMPS = 0x40c0, /*!< Status amplifier enable */ + TFA2_BF_ISTAREFS = 0x40d0, /*!< Status Ref enable */ + TFA2_BF_ISTADCCR = 0x40e0, /*!< Status Control ADC */ + TFA2_BF_ISTBODNOK = 0x40f0, /*!< Status BOD */ + TFA2_BF_ISTBSTCU = 0x4100, /*!< Status DCDC current limiting */ + TFA2_BF_ISTBSTHI = 0x4110, /*!< Status DCDC active */ + TFA2_BF_ISTBSTOC = 0x4120, /*!< Status DCDC OCP */ + TFA2_BF_ISTBSTPKCUR = 0x4130, /*!< Status bst peakcur */ + TFA2_BF_ISTBSTVC = 0x4140, /*!< Status DCDC level 1x */ + TFA2_BF_ISTBST86 = 0x4150, /*!< Status DCDC level 1.14x */ + TFA2_BF_ISTBST93 = 0x4160, /*!< Status DCDC level 1.07x */ + TFA2_BF_ISTRCVLD = 0x4170, /*!< Status rcvldop ready */ + TFA2_BF_ISTOCPL = 0x4180, /*!< Status ocp alarm left */ + TFA2_BF_ISTOCPR = 0x4190, /*!< Status ocp alarm right */ + TFA2_BF_ISTMWSRC = 0x41a0, /*!< Status Waits HW I2C settings */ + TFA2_BF_ISTMWCFC = 0x41b0, /*!< Status waits CF config */ + TFA2_BF_ISTMWSMU = 0x41c0, /*!< Status Audio mute sequence */ + TFA2_BF_ISTCFMER = 0x41d0, /*!< Status cfma error */ + TFA2_BF_ISTCFMAC = 0x41e0, /*!< Status cfma ack */ + TFA2_BF_ISTCLKOOR = 0x41f0, /*!< Status flag_clk_out_of_range */ + TFA2_BF_ISTTDMER = 0x4200, /*!< Status tdm error */ + TFA2_BF_ISTCLPL = 0x4210, /*!< Status clip left */ + TFA2_BF_ISTCLPR = 0x4220, /*!< Status clip right */ + TFA2_BF_ISTOCPM = 0x4230, /*!< Status mic ocpok */ + TFA2_BF_ICLVDDS = 0x4400, /*!< Clear POR */ + TFA2_BF_ICLPLLS = 0x4410, /*!< Clear PLL lock */ + TFA2_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ + TFA2_BF_ICLOVDS = 0x4430, /*!< Clear OVP alarm */ + TFA2_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ + TFA2_BF_ICLCLKS = 0x4450, /*!< Clear clocks stable */ + TFA2_BF_ICLMTPB = 0x4460, /*!< Clear mtp busy */ + TFA2_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ + TFA2_BF_ICLSPKS = 0x4480, /*!< Clear speaker error */ + TFA2_BF_ICLACS = 0x4490, /*!< Clear cold started */ + TFA2_BF_ICLSWS = 0x44a0, /*!< Clear amplifier engage */ + TFA2_BF_ICLWDS = 0x44b0, /*!< Clear watchdog */ + TFA2_BF_ICLAMPS = 0x44c0, /*!< Clear enbl amp */ + TFA2_BF_ICLAREFS = 0x44d0, /*!< Clear ref enable */ + TFA2_BF_ICLADCCR = 0x44e0, /*!< Clear control ADC */ + TFA2_BF_ICLBODNOK = 0x44f0, /*!< Clear BOD */ + TFA2_BF_ICLBSTCU = 0x4500, /*!< Clear DCDC current limiting */ + TFA2_BF_ICLBSTHI = 0x4510, /*!< Clear DCDC active */ + TFA2_BF_ICLBSTOC = 0x4520, /*!< Clear DCDC OCP */ + TFA2_BF_ICLBSTPC = 0x4530, /*!< Clear bst peakcur */ + TFA2_BF_ICLBSTVC = 0x4540, /*!< Clear DCDC level 1x */ + TFA2_BF_ICLBST86 = 0x4550, /*!< Clear DCDC level 1.14x */ + TFA2_BF_ICLBST93 = 0x4560, /*!< Clear DCDC level 1.07x */ + TFA2_BF_ICLRCVLD = 0x4570, /*!< Clear rcvldop ready */ + TFA2_BF_ICLOCPL = 0x4580, /*!< Clear ocp alarm left */ + TFA2_BF_ICLOCPR = 0x4590, /*!< Clear ocp alarm right */ + TFA2_BF_ICLMWSRC = 0x45a0, /*!< Clear wait HW I2C settings */ + TFA2_BF_ICLMWCFC = 0x45b0, /*!< Clear wait cf config */ + TFA2_BF_ICLMWSMU = 0x45c0, /*!< Clear audio mute sequence */ + TFA2_BF_ICLCFMER = 0x45d0, /*!< Clear cfma err */ + TFA2_BF_ICLCFMAC = 0x45e0, /*!< Clear cfma ack */ + TFA2_BF_ICLCLKOOR = 0x45f0, /*!< Clear flag_clk_out_of_range */ + TFA2_BF_ICLTDMER = 0x4600, /*!< Clear tdm error */ + TFA2_BF_ICLCLPL = 0x4610, /*!< Clear clip left */ + TFA2_BF_ICLCLPR = 0x4620, /*!< Clear clip right */ + TFA2_BF_ICLOCPM = 0x4630, /*!< Clear mic ocpok */ + TFA2_BF_IEVDDS = 0x4800, /*!< Enable por */ + TFA2_BF_IEPLLS = 0x4810, /*!< Enable pll lock */ + TFA2_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ + TFA2_BF_IEOVDS = 0x4830, /*!< Enable OVP alarm */ + TFA2_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ + TFA2_BF_IECLKS = 0x4850, /*!< Enable clocks stable */ + TFA2_BF_IEMTPB = 0x4860, /*!< Enable mtp busy */ + TFA2_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ + TFA2_BF_IESPKS = 0x4880, /*!< Enable speaker error */ + TFA2_BF_IEACS = 0x4890, /*!< Enable cold started */ + TFA2_BF_IESWS = 0x48a0, /*!< Enable amplifier engage */ + TFA2_BF_IEWDS = 0x48b0, /*!< Enable watchdog */ + TFA2_BF_IEAMPS = 0x48c0, /*!< Enable enbl amp */ + TFA2_BF_IEAREFS = 0x48d0, /*!< Enable ref enable */ + TFA2_BF_IEADCCR = 0x48e0, /*!< Enable Control ADC */ + TFA2_BF_IEBODNOK = 0x48f0, /*!< Enable BOD */ + TFA2_BF_IEBSTCU = 0x4900, /*!< Enable DCDC current limiting */ + TFA2_BF_IEBSTHI = 0x4910, /*!< Enable DCDC active */ + TFA2_BF_IEBSTOC = 0x4920, /*!< Enable DCDC OCP */ + TFA2_BF_IEBSTPC = 0x4930, /*!< Enable bst peakcur */ + TFA2_BF_IEBSTVC = 0x4940, /*!< Enable DCDC level 1x */ + TFA2_BF_IEBST86 = 0x4950, /*!< Enable DCDC level 1.14x */ + TFA2_BF_IEBST93 = 0x4960, /*!< Enable DCDC level 1.07x */ + TFA2_BF_IERCVLD = 0x4970, /*!< Enable rcvldop ready */ + TFA2_BF_IEOCPL = 0x4980, /*!< Enable ocp alarm left */ + TFA2_BF_IEOCPR = 0x4990, /*!< Enable ocp alarm right */ + TFA2_BF_IEMWSRC = 0x49a0, /*!< Enable waits HW I2C settings */ + TFA2_BF_IEMWCFC = 0x49b0, /*!< Enable man wait cf config */ + TFA2_BF_IEMWSMU = 0x49c0, /*!< Enable man Audio mute sequence */ + TFA2_BF_IECFMER = 0x49d0, /*!< Enable cfma err */ + TFA2_BF_IECFMAC = 0x49e0, /*!< Enable cfma ack */ + TFA2_BF_IECLKOOR = 0x49f0, /*!< Enable flag_clk_out_of_range */ + TFA2_BF_IETDMER = 0x4a00, /*!< Enable tdm error */ + TFA2_BF_IECLPL = 0x4a10, /*!< Enable clip left */ + TFA2_BF_IECLPR = 0x4a20, /*!< Enable clip right */ + TFA2_BF_IEOCPM1 = 0x4a30, /*!< Enable mic ocpok */ + TFA2_BF_IPOVDDS = 0x4c00, /*!< Polarity por */ + TFA2_BF_IPOPLLS = 0x4c10, /*!< Polarity pll lock */ + TFA2_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ + TFA2_BF_IPOOVDS = 0x4c30, /*!< Polarity OVP alarm */ + TFA2_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ + TFA2_BF_IPOCLKS = 0x4c50, /*!< Polarity clocks stable */ + TFA2_BF_IPOMTPB = 0x4c60, /*!< Polarity mtp busy */ + TFA2_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ + TFA2_BF_IPOSPKS = 0x4c80, /*!< Polarity speaker error */ + TFA2_BF_IPOACS = 0x4c90, /*!< Polarity cold started */ + TFA2_BF_IPOSWS = 0x4ca0, /*!< Polarity amplifier engage */ + TFA2_BF_IPOWDS = 0x4cb0, /*!< Polarity watchdog */ + TFA2_BF_IPOAMPS = 0x4cc0, /*!< Polarity enbl amp */ + TFA2_BF_IPOAREFS = 0x4cd0, /*!< Polarity ref enable */ + TFA2_BF_IPOADCCR = 0x4ce0, /*!< Polarity Control ADC */ + TFA2_BF_IPOBODNOK = 0x4cf0, /*!< Polarity BOD */ + TFA2_BF_IPOBSTCU = 0x4d00, /*!< Polarity DCDC current limiting */ + TFA2_BF_IPOBSTHI = 0x4d10, /*!< Polarity DCDC active */ + TFA2_BF_IPOBSTOC = 0x4d20, /*!< Polarity DCDC OCP */ + TFA2_BF_IPOBSTPC = 0x4d30, /*!< Polarity bst peakcur */ + TFA2_BF_IPOBSTVC = 0x4d40, /*!< Polarity DCDC level 1x */ + TFA2_BF_IPOBST86 = 0x4d50, /*!< Polarity DCDC level 1.14x */ + TFA2_BF_IPOBST93 = 0x4d60, /*!< Polarity DCDC level 1.07x */ + TFA2_BF_IPORCVLD = 0x4d70, /*!< Polarity rcvldop ready */ + TFA2_BF_IPOOCPL = 0x4d80, /*!< Polarity ocp alarm left */ + TFA2_BF_IPOOCPR = 0x4d90, /*!< Polarity ocp alarm right */ + TFA2_BF_IPOMWSRC = 0x4da0, /*!< Polarity waits HW I2C settings */ + TFA2_BF_IPOMWCFC = 0x4db0, /*!< Polarity man wait cf config */ + TFA2_BF_IPOMWSMU = 0x4dc0, /*!< Polarity man audio mute sequence */ + TFA2_BF_IPOCFMER = 0x4dd0, /*!< Polarity cfma err */ + TFA2_BF_IPOCFMAC = 0x4de0, /*!< Polarity cfma ack */ + TFA2_BF_IPCLKOOR = 0x4df0, /*!< Polarity flag_clk_out_of_range */ + TFA2_BF_IPOTDMER = 0x4e00, /*!< Polarity tdm error */ + TFA2_BF_IPOCLPL = 0x4e10, /*!< Polarity clip left */ + TFA2_BF_IPOCLPR = 0x4e20, /*!< Polarity clip right */ + TFA2_BF_IPOOCPM = 0x4e30, /*!< Polarity mic ocpok */ + TFA2_BF_BSSCR = 0x5001, /*!< Battery protection attack Time */ + TFA2_BF_BSST = 0x5023, /*!< Battery protection threshold voltage level */ + TFA2_BF_BSSRL = 0x5061, /*!< Battery protection maximum reduction */ + TFA2_BF_BSSRR = 0x5082, /*!< Battery protection release time */ + TFA2_BF_BSSHY = 0x50b1, /*!< Battery protection hysteresis */ + TFA2_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA2_BF_BSSBY = 0x50f0, /*!< Bypass HW clipper */ + TFA2_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ + TFA2_BF_INTSMUTE = 0x5110, /*!< Soft mute HW */ + TFA2_BF_CFSML = 0x5120, /*!< Soft mute FW left */ + TFA2_BF_CFSMR = 0x5130, /*!< Soft mute FW right */ + TFA2_BF_HPFBYPL = 0x5140, /*!< Bypass HPF left */ + TFA2_BF_HPFBYPR = 0x5150, /*!< Bypass HPF right */ + TFA2_BF_DPSAL = 0x5160, /*!< Enable DPSA left */ + TFA2_BF_DPSAR = 0x5170, /*!< Enable DPSA right */ + TFA2_BF_VOL = 0x5187, /*!< FW volume control for primary audio channel */ + TFA2_BF_HNDSFRCV = 0x5200, /*!< Selection receiver */ + TFA2_BF_CLIPCTRL = 0x5222, /*!< Clip control setting */ + TFA2_BF_AMPGAIN = 0x5257, /*!< Amplifier gain */ + TFA2_BF_SLOPEE = 0x52d0, /*!< Enables slope control */ + TFA2_BF_SLOPESET = 0x52e1, /*!< Set slope */ + TFA2_BF_VOLSEC = 0x5a07, /*!< FW volume control for secondary audio channel */ + TFA2_BF_SWPROFIL = 0x5a87, /*!< Software profile data */ + TFA2_BF_DCVO = 0x7002, /*!< Boost voltage */ + TFA2_BF_DCMCC = 0x7033, /*!< Max coil current */ + TFA2_BF_DCCV = 0x7071, /*!< Coil Value */ + TFA2_BF_DCIE = 0x7090, /*!< Adaptive boost mode */ + TFA2_BF_DCSR = 0x70a0, /*!< Soft ramp up/down */ + TFA2_BF_DCSYNCP = 0x70b2, /*!< DCDC synchronization off + 7 positions */ + TFA2_BF_DCDIS = 0x70e0, /*!< DCDC on/off */ + TFA2_BF_RST = 0x9000, /*!< Reset */ + TFA2_BF_DMEM = 0x9011, /*!< Target memory */ + TFA2_BF_AIF = 0x9030, /*!< Auto increment */ + TFA2_BF_CFINT = 0x9040, /*!< Interrupt - auto clear */ + TFA2_BF_CFCGATE = 0x9050, /*!< Coolflux clock gating disabling control */ + TFA2_BF_REQ = 0x9087, /*!< request for access (8 channels) */ + TFA2_BF_REQCMD = 0x9080, /*!< Firmware event request rpc command */ + TFA2_BF_REQRST = 0x9090, /*!< Firmware event request reset restart */ + TFA2_BF_REQMIPS = 0x90a0, /*!< Firmware event request short on mips */ + TFA2_BF_REQMUTED = 0x90b0, /*!< Firmware event request mute sequence ready */ + TFA2_BF_REQVOL = 0x90c0, /*!< Firmware event request volume ready */ + TFA2_BF_REQDMG = 0x90d0, /*!< Firmware event request speaker damage detected */ + TFA2_BF_REQCAL = 0x90e0, /*!< Firmware event request calibration completed */ + TFA2_BF_REQRSV = 0x90f0, /*!< Firmware event request reserved */ + TFA2_BF_MADD = 0x910f, /*!< Memory address */ + TFA2_BF_MEMA = 0x920f, /*!< Activate memory access */ + TFA2_BF_ERR = 0x9307, /*!< Error flags */ + TFA2_BF_ACK = 0x9387, /*!< Acknowledge of requests */ + TFA2_BF_ACKCMD = 0x9380, /*!< Firmware event acknowledge rpc command */ + TFA2_BF_ACKRST = 0x9390, /*!< Firmware event acknowledge reset restart */ + TFA2_BF_ACKMIPS = 0x93a0, /*!< Firmware event acknowledge short on mips */ + TFA2_BF_ACKMUTED = 0x93b0, /*!< Firmware event acknowledge mute sequence ready */ + TFA2_BF_ACKVOL = 0x93c0, /*!< Firmware event acknowledge volume ready */ + TFA2_BF_ACKDMG = 0x93d0, /*!< Firmware event acknowledge speaker damage detected */ + TFA2_BF_ACKCAL = 0x93e0, /*!< Firmware event acknowledge calibration completed */ + TFA2_BF_ACKRSV = 0x93f0, /*!< Firmware event acknowledge reserved */ + TFA2_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ + TFA2_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ + TFA2_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ + TFA2_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp */ + TFA2_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ + TFA2_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ + TFA2_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA2_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA2_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ + TFA2_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA2_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ + TFA2_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA2_BF_USERDEF = 0xf042, /*!< Calibration delta current limit DCDC */ + TFA2_BF_R25CL = 0xf40f, /*!< Ron resistance of left channel speaker coil */ + TFA2_BF_R25CR = 0xf50f, /*!< Ron resistance of right channel speaker coil */ +} nxpTfa2BfEnumList_t; +#define TFA2_NAMETABLE static tfaBfName_t Tfa2DatasheetNames[] = {\ + { 0x0, "PWDN"}, /* Powerdown selection , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x20, "CFE"}, /* Enable CoolFlux , */\ + { 0x30, "AMPE"}, /* Activate Amplifier , */\ + { 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ + { 0x50, "SBSL"}, /* Coolflux configured , */\ + { 0x60, "AMPC"}, /* CoolFlux controls amplifier , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0x91, "FSSSEL"}, /* Audio sample reference , */\ + { 0xb0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xc0, "TSTOCP"}, /* OCP testing control , */\ + { 0x101, "AMPINSEL"}, /* Amplifier input selection , */\ + { 0x120, "MANSCONF"}, /* I2C configured , */\ + { 0x130, "MANCOLD"}, /* Execute cold start , */\ + { 0x140, "MANAOOSC"}, /* Internal osc off at PWDN , */\ + { 0x150, "MANROBOD"}, /* Reaction on BOD , */\ + { 0x160, "BODE"}, /* BOD Enable , */\ + { 0x170, "BODHYS"}, /* BOD Hysteresis , */\ + { 0x181, "BODFILT"}, /* BOD filter , */\ + { 0x1a1, "BODTHLVL"}, /* BOD threshold , */\ + { 0x1d0, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x1e0, "RCVNS"}, /* Noise shaper selection , */\ + { 0x1f0, "MANWDE"}, /* Watchdog manager reaction , */\ + { 0x203, "AUDFS"}, /* Sample rate (fs) , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ + { 0x2b0, "BYPHVBF"}, /* Bypass HVBAT filter , */\ + { 0x2c0, "LDOBYP"}, /* Receiver LDO bypass , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ + { 0x500, "SSLEFTE"}, /* Enable left channel , */\ + { 0x510, "SSRIGHTE"}, /* Enable right channel , */\ + { 0x520, "VSLEFTE"}, /* Voltage sense left , */\ + { 0x530, "VSRIGHTE"}, /* Voltage sense right , */\ + { 0x540, "CSLEFTE"}, /* Current sense left , */\ + { 0x550, "CSRIGHTE"}, /* Current sense right , */\ + { 0x560, "SSPDME"}, /* Sub-system PDM , */\ + { 0xd18, "STGAIN"}, /* Side tone gain , */\ + { 0xda0, "PDMSMUTE"}, /* Side tone soft mute , */\ + { 0xe06, "SWVSTEP"}, /* Register for the host SW to record the current active vstep, */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "PLLS"}, /* PLL lock , */\ + { 0x1020, "OTDS"}, /* OTP alarm , */\ + { 0x1030, "OVDS"}, /* OVP alarm , */\ + { 0x1040, "UVDS"}, /* UVP alarm , */\ + { 0x1050, "CLKS"}, /* Clocks stable , */\ + { 0x1060, "MTPB"}, /* MTP busy , */\ + { 0x1070, "NOCLK"}, /* Lost clock , */\ + { 0x1080, "SPKS"}, /* Speaker error , */\ + { 0x1090, "ACS"}, /* Cold Start , */\ + { 0x10a0, "SWS"}, /* Amplifier engage , */\ + { 0x10b0, "WDS"}, /* Watchdog , */\ + { 0x10c0, "AMPS"}, /* Amplifier enable , */\ + { 0x10d0, "AREFS"}, /* References enable , */\ + { 0x10e0, "ADCCR"}, /* Control ADC , */\ + { 0x10f0, "BODNOK"}, /* BOD , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active , */\ + { 0x1120, "DCOCPOK"}, /* DCDC OCP nmos , */\ + { 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1170, "STMUTEB"}, /* side tone (un)mute busy , */\ + { 0x1180, "STMUTE"}, /* side tone mute state , */\ + { 0x1190, "TDMLUTER"}, /* TDM LUT error , */\ + { 0x11a2, "TDMSTAT"}, /* TDM status bits , */\ + { 0x11d0, "TDMERR"}, /* TDM error , */\ + { 0x11e0, "HAPTIC"}, /* Status haptic driver , */\ + { 0x1200, "OCPOAPL"}, /* OCPOK pmos A left , */\ + { 0x1210, "OCPOANL"}, /* OCPOK nmos A left , */\ + { 0x1220, "OCPOBPL"}, /* OCPOK pmos B left , */\ + { 0x1230, "OCPOBNL"}, /* OCPOK nmos B left , */\ + { 0x1240, "CLIPAHL"}, /* Clipping A left to Vddp , */\ + { 0x1250, "CLIPALL"}, /* Clipping A left to gnd , */\ + { 0x1260, "CLIPBHL"}, /* Clipping B left to Vddp , */\ + { 0x1270, "CLIPBLL"}, /* Clipping B left to gnd , */\ + { 0x1280, "OCPOAPRC"}, /* OCPOK pmos A RCV , */\ + { 0x1290, "OCPOANRC"}, /* OCPOK nmos A RCV , */\ + { 0x12a0, "OCPOBPRC"}, /* OCPOK pmos B RCV , */\ + { 0x12b0, "OCPOBNRC"}, /* OCPOK nmos B RCV , */\ + { 0x12c0, "RCVLDOR"}, /* RCV LDO regulates , */\ + { 0x12d0, "RCVLDOBR"}, /* Receiver LDO ready , */\ + { 0x12e0, "OCDSL"}, /* OCP left amplifier , */\ + { 0x12f0, "CLIPSL"}, /* Amplifier left clipping , */\ + { 0x1300, "OCPOAPR"}, /* OCPOK pmos A right , */\ + { 0x1310, "OCPOANR"}, /* OCPOK nmos A right , */\ + { 0x1320, "OCPOBPR"}, /* OCPOK pmos B right , */\ + { 0x1330, "OCPOBNR"}, /* OCPOK nmos B right , */\ + { 0x1340, "CLIPAHR"}, /* Clipping A right to Vddp , */\ + { 0x1350, "CLIPALR"}, /* Clipping A right to gnd , */\ + { 0x1360, "CLIPBHR"}, /* Clipping B left to Vddp , */\ + { 0x1370, "CLIPBLR"}, /* Clipping B right to gnd , */\ + { 0x1380, "OCDSR"}, /* OCP right amplifier , */\ + { 0x1390, "CLIPSR"}, /* Amplifier right clipping , */\ + { 0x13a0, "OCPOKMC"}, /* OCPOK MICVDD , */\ + { 0x13b0, "MANALARM"}, /* Alarm state , */\ + { 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ + { 0x13d0, "MANWAIT2"}, /* Wait CF config , */\ + { 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x13f0, "MANOPER"}, /* Operating state , */\ + { 0x1400, "SPKSL"}, /* Left speaker status , */\ + { 0x1410, "SPKSR"}, /* Right speaker status , */\ + { 0x1420, "CLKOOR"}, /* External clock status , */\ + { 0x1433, "MANSTATE"}, /* Device manager status , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x2003, "TDMUC"}, /* Usecase setting , */\ + { 0x2040, "TDME"}, /* Enable interface , */\ + { 0x2050, "TDMMODE"}, /* Slave/master , */\ + { 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2073, "TDMFSLN"}, /* FS length (master mode only) , */\ + { 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ + { 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ + { 0x2103, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x21e0, "TDMDEL"}, /* data delay to FS , */\ + { 0x21f0, "TDMADJ"}, /* data adjustment , */\ + { 0x2201, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2271, "TDMTXDFO"}, /* Format unused bits , */\ + { 0x2291, "TDMTXUS0"}, /* Format unused slots GAINIO , */\ + { 0x22b1, "TDMTXUS1"}, /* Format unused slots DIO1 , */\ + { 0x22d1, "TDMTXUS2"}, /* Format unused slots DIO2 , */\ + { 0x2310, "TDMLE"}, /* Control audio left , */\ + { 0x2320, "TDMRE"}, /* Control audio right , */\ + { 0x2340, "TDMVSRE"}, /* Control voltage sense right , */\ + { 0x2350, "TDMCSRE"}, /* Control current sense right , */\ + { 0x2360, "TDMVSLE"}, /* Voltage sense left control , */\ + { 0x2370, "TDMCSLE"}, /* Current sense left control , */\ + { 0x2380, "TDMCFRE"}, /* DSP out right control , */\ + { 0x2390, "TDMCFLE"}, /* DSP out left control , */\ + { 0x23a0, "TDMCF3E"}, /* AEC ref left control , */\ + { 0x23b0, "TDMCF4E"}, /* AEC ref right control , */\ + { 0x23c0, "TDMPD1E"}, /* PDM 1 control , */\ + { 0x23d0, "TDMPD2E"}, /* PDM 2 control , */\ + { 0x2421, "TDMLIO"}, /* IO audio left , */\ + { 0x2441, "TDMRIO"}, /* IO audio right , */\ + { 0x2481, "TDMVSRIO"}, /* IO voltage sense right , */\ + { 0x24a1, "TDMCSRIO"}, /* IO current sense right , */\ + { 0x24c1, "TDMVSLIO"}, /* IO voltage sense left , */\ + { 0x24e1, "TDMCSLIO"}, /* IO current sense left , */\ + { 0x2501, "TDMCFRIO"}, /* IO dspout right , */\ + { 0x2521, "TDMCFLIO"}, /* IO dspout left , */\ + { 0x2541, "TDMCF3IO"}, /* IO AEC ref left control , */\ + { 0x2561, "TDMCF4IO"}, /* IO AEC ref right control , */\ + { 0x2581, "TDMPD1IO"}, /* IO pdm1 , */\ + { 0x25a1, "TDMPD2IO"}, /* IO pdm2 , */\ + { 0x2643, "TDMLS"}, /* Position audio left , */\ + { 0x2683, "TDMRS"}, /* Position audio right , */\ + { 0x2703, "TDMVSRS"}, /* Position voltage sense right , */\ + { 0x2743, "TDMCSRS"}, /* Position current sense right , */\ + { 0x2783, "TDMVSLS"}, /* Position voltage sense left , */\ + { 0x27c3, "TDMCSLS"}, /* Position current sense left , */\ + { 0x2803, "TDMCFRS"}, /* Position dspout right , */\ + { 0x2843, "TDMCFLS"}, /* Position dspout left , */\ + { 0x2883, "TDMCF3S"}, /* Position AEC ref left control , */\ + { 0x28c3, "TDMCF4S"}, /* Position AEC ref right control , */\ + { 0x2903, "TDMPD1S"}, /* Position pdm1 , */\ + { 0x2943, "TDMPD2S"}, /* Position pdm2 , */\ + { 0x3100, "PDMSM"}, /* PDM control , */\ + { 0x3111, "PDMSTSEL"}, /* Side tone input , */\ + { 0x3130, "PDMLSEL"}, /* PDM data selection for left channel during PDM direct mode, */\ + { 0x3140, "PDMRSEL"}, /* PDM data selection for right channel during PDM direct mode, */\ + { 0x3150, "MICVDDE"}, /* Enable MICVDD , */\ + { 0x3201, "PDMCLRAT"}, /* PDM BCK/Fs ratio , */\ + { 0x3223, "PDMGAIN"}, /* PDM gain , */\ + { 0x3263, "PDMOSEL"}, /* PDM output selection - RE/FE data combination , */\ + { 0x32a0, "SELCFHAPD"}, /* Select the source for haptic data output (not for customer), */\ + { 0x3307, "HAPTIME"}, /* Duration (ms) , */\ + { 0x3387, "HAPLEVEL"}, /* DC value (FFS) , */\ + { 0x3403, "GPIODIN"}, /* Receiving value , */\ + { 0x3500, "GPIOCTRL"}, /* GPIO master control over GPIO1/2 ports (not for customer), */\ + { 0x3513, "GPIOCONF"}, /* Configuration , */\ + { 0x3553, "GPIODOUT"}, /* Transmitting value , */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTPLLS"}, /* Status PLL lock , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOVDS"}, /* Status OVP alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTCLKS"}, /* Status clocks stable , */\ + { 0x4060, "ISTMTPB"}, /* Status MTP busy , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4080, "ISTSPKS"}, /* Status speaker error , */\ + { 0x4090, "ISTACS"}, /* Status cold start , */\ + { 0x40a0, "ISTSWS"}, /* Status amplifier engage , */\ + { 0x40b0, "ISTWDS"}, /* Status watchdog , */\ + { 0x40c0, "ISTAMPS"}, /* Status amplifier enable , */\ + { 0x40d0, "ISTAREFS"}, /* Status Ref enable , */\ + { 0x40e0, "ISTADCCR"}, /* Status Control ADC , */\ + { 0x40f0, "ISTBODNOK"}, /* Status BOD , */\ + { 0x4100, "ISTBSTCU"}, /* Status DCDC current limiting , */\ + { 0x4110, "ISTBSTHI"}, /* Status DCDC active , */\ + { 0x4120, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4130, "ISTBSTPKCUR"}, /* Status bst peakcur , */\ + { 0x4140, "ISTBSTVC"}, /* Status DCDC level 1x , */\ + { 0x4150, "ISTBST86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "ISTBST93"}, /* Status DCDC level 1.07x , */\ + { 0x4170, "ISTRCVLD"}, /* Status rcvldop ready , */\ + { 0x4180, "ISTOCPL"}, /* Status ocp alarm left , */\ + { 0x4190, "ISTOCPR"}, /* Status ocp alarm right , */\ + { 0x41a0, "ISTMWSRC"}, /* Status Waits HW I2C settings , */\ + { 0x41b0, "ISTMWCFC"}, /* Status waits CF config , */\ + { 0x41c0, "ISTMWSMU"}, /* Status Audio mute sequence , */\ + { 0x41d0, "ISTCFMER"}, /* Status cfma error , */\ + { 0x41e0, "ISTCFMAC"}, /* Status cfma ack , */\ + { 0x41f0, "ISTCLKOOR"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "ISTTDMER"}, /* Status tdm error , */\ + { 0x4210, "ISTCLPL"}, /* Status clip left , */\ + { 0x4220, "ISTCLPR"}, /* Status clip right , */\ + { 0x4230, "ISTOCPM"}, /* Status mic ocpok , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLPLLS"}, /* Clear PLL lock , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOVDS"}, /* Clear OVP alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLCLKS"}, /* Clear clocks stable , */\ + { 0x4460, "ICLMTPB"}, /* Clear mtp busy , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4480, "ICLSPKS"}, /* Clear speaker error , */\ + { 0x4490, "ICLACS"}, /* Clear cold started , */\ + { 0x44a0, "ICLSWS"}, /* Clear amplifier engage , */\ + { 0x44b0, "ICLWDS"}, /* Clear watchdog , */\ + { 0x44c0, "ICLAMPS"}, /* Clear enbl amp , */\ + { 0x44d0, "ICLAREFS"}, /* Clear ref enable , */\ + { 0x44e0, "ICLADCCR"}, /* Clear control ADC , */\ + { 0x44f0, "ICLBODNOK"}, /* Clear BOD , */\ + { 0x4500, "ICLBSTCU"}, /* Clear DCDC current limiting , */\ + { 0x4510, "ICLBSTHI"}, /* Clear DCDC active , */\ + { 0x4520, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4530, "ICLBSTPC"}, /* Clear bst peakcur , */\ + { 0x4540, "ICLBSTVC"}, /* Clear DCDC level 1x , */\ + { 0x4550, "ICLBST86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "ICLBST93"}, /* Clear DCDC level 1.07x , */\ + { 0x4570, "ICLRCVLD"}, /* Clear rcvldop ready , */\ + { 0x4580, "ICLOCPL"}, /* Clear ocp alarm left , */\ + { 0x4590, "ICLOCPR"}, /* Clear ocp alarm right , */\ + { 0x45a0, "ICLMWSRC"}, /* Clear wait HW I2C settings , */\ + { 0x45b0, "ICLMWCFC"}, /* Clear wait cf config , */\ + { 0x45c0, "ICLMWSMU"}, /* Clear audio mute sequence , */\ + { 0x45d0, "ICLCFMER"}, /* Clear cfma err , */\ + { 0x45e0, "ICLCFMAC"}, /* Clear cfma ack , */\ + { 0x45f0, "ICLCLKOOR"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "ICLTDMER"}, /* Clear tdm error , */\ + { 0x4610, "ICLCLPL"}, /* Clear clip left , */\ + { 0x4620, "ICLCLPR"}, /* Clear clip right , */\ + { 0x4630, "ICLOCPM"}, /* Clear mic ocpok , */\ + { 0x4800, "IEVDDS"}, /* Enable por , */\ + { 0x4810, "IEPLLS"}, /* Enable pll lock , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOVDS"}, /* Enable OVP alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IECLKS"}, /* Enable clocks stable , */\ + { 0x4860, "IEMTPB"}, /* Enable mtp busy , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4880, "IESPKS"}, /* Enable speaker error , */\ + { 0x4890, "IEACS"}, /* Enable cold started , */\ + { 0x48a0, "IESWS"}, /* Enable amplifier engage , */\ + { 0x48b0, "IEWDS"}, /* Enable watchdog , */\ + { 0x48c0, "IEAMPS"}, /* Enable enbl amp , */\ + { 0x48d0, "IEAREFS"}, /* Enable ref enable , */\ + { 0x48e0, "IEADCCR"}, /* Enable Control ADC , */\ + { 0x48f0, "IEBODNOK"}, /* Enable BOD , */\ + { 0x4900, "IEBSTCU"}, /* Enable DCDC current limiting , */\ + { 0x4910, "IEBSTHI"}, /* Enable DCDC active , */\ + { 0x4920, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4930, "IEBSTPC"}, /* Enable bst peakcur , */\ + { 0x4940, "IEBSTVC"}, /* Enable DCDC level 1x , */\ + { 0x4950, "IEBST86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "IEBST93"}, /* Enable DCDC level 1.07x , */\ + { 0x4970, "IERCVLD"}, /* Enable rcvldop ready , */\ + { 0x4980, "IEOCPL"}, /* Enable ocp alarm left , */\ + { 0x4990, "IEOCPR"}, /* Enable ocp alarm right , */\ + { 0x49a0, "IEMWSRC"}, /* Enable waits HW I2C settings , */\ + { 0x49b0, "IEMWCFC"}, /* Enable man wait cf config , */\ + { 0x49c0, "IEMWSMU"}, /* Enable man Audio mute sequence , */\ + { 0x49d0, "IECFMER"}, /* Enable cfma err , */\ + { 0x49e0, "IECFMAC"}, /* Enable cfma ack , */\ + { 0x49f0, "IECLKOOR"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "IETDMER"}, /* Enable tdm error , */\ + { 0x4a10, "IECLPL"}, /* Enable clip left , */\ + { 0x4a20, "IECLPR"}, /* Enable clip right , */\ + { 0x4a30, "IEOCPM1"}, /* Enable mic ocpok , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity por , */\ + { 0x4c10, "IPOPLLS"}, /* Polarity pll lock , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOVDS"}, /* Polarity OVP alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOCLKS"}, /* Polarity clocks stable , */\ + { 0x4c60, "IPOMTPB"}, /* Polarity mtp busy , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4c80, "IPOSPKS"}, /* Polarity speaker error , */\ + { 0x4c90, "IPOACS"}, /* Polarity cold started , */\ + { 0x4ca0, "IPOSWS"}, /* Polarity amplifier engage , */\ + { 0x4cb0, "IPOWDS"}, /* Polarity watchdog , */\ + { 0x4cc0, "IPOAMPS"}, /* Polarity enbl amp , */\ + { 0x4cd0, "IPOAREFS"}, /* Polarity ref enable , */\ + { 0x4ce0, "IPOADCCR"}, /* Polarity Control ADC , */\ + { 0x4cf0, "IPOBODNOK"}, /* Polarity BOD , */\ + { 0x4d00, "IPOBSTCU"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "IPOBSTHI"}, /* Polarity DCDC active , */\ + { 0x4d20, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "IPOBSTPC"}, /* Polarity bst peakcur , */\ + { 0x4d40, "IPOBSTVC"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "IPOBST86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "IPOBST93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d70, "IPORCVLD"}, /* Polarity rcvldop ready , */\ + { 0x4d80, "IPOOCPL"}, /* Polarity ocp alarm left , */\ + { 0x4d90, "IPOOCPR"}, /* Polarity ocp alarm right , */\ + { 0x4da0, "IPOMWSRC"}, /* Polarity waits HW I2C settings , */\ + { 0x4db0, "IPOMWCFC"}, /* Polarity man wait cf config , */\ + { 0x4dc0, "IPOMWSMU"}, /* Polarity man audio mute sequence , */\ + { 0x4dd0, "IPOCFMER"}, /* Polarity cfma err , */\ + { 0x4de0, "IPOCFMAC"}, /* Polarity cfma ack , */\ + { 0x4df0, "IPCLKOOR"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "IPOTDMER"}, /* Polarity tdm error , */\ + { 0x4e10, "IPOCLPL"}, /* Polarity clip left , */\ + { 0x4e20, "IPOCLPR"}, /* Polarity clip right , */\ + { 0x4e30, "IPOOCPM"}, /* Polarity mic ocpok , */\ + { 0x5001, "BSSCR"}, /* Battery protection attack Time , */\ + { 0x5023, "BSST"}, /* Battery protection threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery protection maximum reduction , */\ + { 0x5082, "BSSRR"}, /* Battery protection release time , */\ + { 0x50b1, "BSSHY"}, /* Battery protection hysteresis , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass HW clipper , */\ + { 0x5100, "BSSS"}, /* Vbat prot steepness , */\ + { 0x5110, "INTSMUTE"}, /* Soft mute HW , */\ + { 0x5120, "CFSML"}, /* Soft mute FW left , */\ + { 0x5130, "CFSMR"}, /* Soft mute FW right , */\ + { 0x5140, "HPFBYPL"}, /* Bypass HPF left , */\ + { 0x5150, "HPFBYPR"}, /* Bypass HPF right , */\ + { 0x5160, "DPSAL"}, /* Enable DPSA left , */\ + { 0x5170, "DPSAR"}, /* Enable DPSA right , */\ + { 0x5187, "VOL"}, /* FW volume control for primary audio channel , */\ + { 0x5200, "HNDSFRCV"}, /* Selection receiver , */\ + { 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x52d0, "SLOPEE"}, /* Enables slope control , */\ + { 0x52e1, "SLOPESET"}, /* Set slope , */\ + { 0x5a07, "VOLSEC"}, /* FW volume control for secondary audio channel , */\ + { 0x5a87, "SWPROFIL"}, /* Software profile data , */\ + { 0x7002, "DCVO"}, /* Boost voltage , */\ + { 0x7033, "DCMCC"}, /* Max coil current , */\ + { 0x7071, "DCCV"}, /* Coil Value , */\ + { 0x7090, "DCIE"}, /* Adaptive boost mode , */\ + { 0x70a0, "DCSR"}, /* Soft ramp up/down , */\ + { 0x70b2, "DCSYNCP"}, /* DCDC synchronization off + 7 positions , */\ + { 0x70e0, "DCDIS"}, /* DCDC on/off , */\ + { 0x9000, "RST"}, /* Reset , */\ + { 0x9011, "DMEM"}, /* Target memory , */\ + { 0x9030, "AIF"}, /* Auto increment , */\ + { 0x9040, "CFINT"}, /* Interrupt - auto clear , */\ + { 0x9050, "CFCGATE"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "REQCMD"}, /* Firmware event request rpc command , */\ + { 0x9090, "REQRST"}, /* Firmware event request reset restart , */\ + { 0x90a0, "REQMIPS"}, /* Firmware event request short on mips , */\ + { 0x90b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "REQVOL"}, /* Firmware event request volume ready , */\ + { 0x90d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "REQCAL"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "REQRSV"}, /* Firmware event request reserved , */\ + { 0x910f, "MADD"}, /* Memory address , */\ + { 0x920f, "MEMA"}, /* Activate memory access , */\ + { 0x9307, "ERR"}, /* Error flags , */\ + { 0x9387, "ACK"}, /* Acknowledge of requests , */\ + { 0x9380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "ACKVOL"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "ACKDMG"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "ACKRSV"}, /* Firmware event acknowledge reserved , */\ + { 0xa107, "MTPK"}, /* MTP KEY2 register , */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ + { 0xf40f, "R25CL"}, /* Ron resistance of left channel speaker coil , */\ + { 0xf50f, "R25CR"}, /* Ron resistance of right channel speaker coil , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA2_BITNAMETABLE static tfaBfName_t Tfa2BitNames[] = {\ + { 0x0, "powerdown"}, /* Powerdown selection , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x20, "enbl_coolflux"}, /* Enable CoolFlux , */\ + { 0x30, "enbl_amplifier"}, /* Activate Amplifier , */\ + { 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ + { 0x50, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x60, "sel_enbl_amplifier"}, /* CoolFlux controls amplifier , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0x91, "fs_pulse_sel"}, /* Audio sample reference , */\ + { 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xc0, "test_ocp"}, /* OCP testing control , */\ + { 0x101, "vamp_sel"}, /* Amplifier input selection , */\ + { 0x120, "src_set_configured"}, /* I2C configured , */\ + { 0x130, "execute_cold_start"}, /* Execute cold start , */\ + { 0x140, "enbl_osc1m_auto_off"}, /* Internal osc off at PWDN , */\ + { 0x150, "man_enbl_brown_out"}, /* Reaction on BOD , */\ + { 0x160, "enbl_bod"}, /* BOD Enable , */\ + { 0x170, "enbl_bod_hyst"}, /* BOD Hysteresis , */\ + { 0x181, "bod_delay"}, /* BOD filter , */\ + { 0x1a1, "bod_lvlsel"}, /* BOD threshold , */\ + { 0x1d0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x1e0, "pwm_sel_rcv_ns"}, /* Noise shaper selection , */\ + { 0x1f0, "man_enbl_watchdog"}, /* Watchdog manager reaction , */\ + { 0x203, "audio_fs"}, /* Sample rate (fs) , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ + { 0x2b0, "bypass_hvbat_filter"}, /* Bypass HVBAT filter , */\ + { 0x2c0, "ctrl_rcvldop_bypass"}, /* Receiver LDO bypass , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ + { 0x500, "enbl_spkr_ss_left"}, /* Enable left channel , */\ + { 0x510, "enbl_spkr_ss_right"}, /* Enable right channel , */\ + { 0x520, "enbl_volsense_left"}, /* Voltage sense left , */\ + { 0x530, "enbl_volsense_right"}, /* Voltage sense right , */\ + { 0x540, "enbl_cursense_left"}, /* Current sense left , */\ + { 0x550, "enbl_cursense_right"}, /* Current sense right , */\ + { 0x560, "enbl_pdm_ss"}, /* Sub-system PDM , */\ + { 0xd00, "side_tone_gain_sel"}, /* PDM side tone gain selector , */\ + { 0xd18, "side_tone_gain"}, /* Side tone gain , */\ + { 0xda0, "mute_side_tone"}, /* Side tone soft mute , */\ + { 0xe06, "ctrl_digtoana"}, /* Register for the host SW to record the current active vstep, */\ + { 0xe70, "enbl_cmfb_left"}, /* Current sense common mode feedback control for left channel, */\ + { 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_pll_lock"}, /* PLL lock , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm , */\ + { 0x1030, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm , */\ + { 0x1050, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1060, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1070, "flag_lost_clk"}, /* Lost clock , */\ + { 0x1080, "flag_cf_speakererror"}, /* Speaker error , */\ + { 0x1090, "flag_cold_started"}, /* Cold Start , */\ + { 0x10a0, "flag_engage"}, /* Amplifier engage , */\ + { 0x10b0, "flag_watchdog_reset"}, /* Watchdog , */\ + { 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x10d0, "flag_enbl_ref"}, /* References enable , */\ + { 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x10f0, "flag_bod_vddd_nok"}, /* BOD , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active , */\ + { 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos , */\ + { 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1170, "flag_soft_mute_busy"}, /* side tone (un)mute busy , */\ + { 0x1180, "flag_soft_mute_state"}, /* side tone mute state , */\ + { 0x1190, "flag_tdm_lut_error"}, /* TDM LUT error , */\ + { 0x11a2, "flag_tdm_status"}, /* TDM status bits , */\ + { 0x11d0, "flag_tdm_error"}, /* TDM error , */\ + { 0x11e0, "flag_haptic_busy"}, /* Status haptic driver , */\ + { 0x1200, "flag_ocpokap_left"}, /* OCPOK pmos A left , */\ + { 0x1210, "flag_ocpokan_left"}, /* OCPOK nmos A left , */\ + { 0x1220, "flag_ocpokbp_left"}, /* OCPOK pmos B left , */\ + { 0x1230, "flag_ocpokbn_left"}, /* OCPOK nmos B left , */\ + { 0x1240, "flag_clipa_high_left"}, /* Clipping A left to Vddp , */\ + { 0x1250, "flag_clipa_low_left"}, /* Clipping A left to gnd , */\ + { 0x1260, "flag_clipb_high_left"}, /* Clipping B left to Vddp , */\ + { 0x1270, "flag_clipb_low_left"}, /* Clipping B left to gnd , */\ + { 0x1280, "flag_ocpokap_rcv"}, /* OCPOK pmos A RCV , */\ + { 0x1290, "flag_ocpokan_rcv"}, /* OCPOK nmos A RCV , */\ + { 0x12a0, "flag_ocpokbp_rcv"}, /* OCPOK pmos B RCV , */\ + { 0x12b0, "flag_ocpokbn_rcv"}, /* OCPOK nmos B RCV , */\ + { 0x12c0, "flag_rcvldop_ready"}, /* RCV LDO regulates , */\ + { 0x12d0, "flag_rcvldop_bypassready"}, /* Receiver LDO ready , */\ + { 0x12e0, "flag_ocp_alarm_left"}, /* OCP left amplifier , */\ + { 0x12f0, "flag_clip_left"}, /* Amplifier left clipping , */\ + { 0x1300, "flag_ocpokap_right"}, /* OCPOK pmos A right , */\ + { 0x1310, "flag_ocpokan_right"}, /* OCPOK nmos A right , */\ + { 0x1320, "flag_ocpokbp_right"}, /* OCPOK pmos B right , */\ + { 0x1330, "flag_ocpokbn_right"}, /* OCPOK nmos B right , */\ + { 0x1340, "flag_clipa_high_right"}, /* Clipping A right to Vddp , */\ + { 0x1350, "flag_clipa_low_right"}, /* Clipping A right to gnd , */\ + { 0x1360, "flag_clipb_high_right"}, /* Clipping B left to Vddp , */\ + { 0x1370, "flag_clipb_low_right"}, /* Clipping B right to gnd , */\ + { 0x1380, "flag_ocp_alarm_right"}, /* OCP right amplifier , */\ + { 0x1390, "flag_clip_right"}, /* Amplifier right clipping , */\ + { 0x13a0, "flag_mic_ocpok"}, /* OCPOK MICVDD , */\ + { 0x13b0, "flag_man_alarm_state"}, /* Alarm state , */\ + { 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ + { 0x13d0, "flag_man_wait_cf_config"}, /* Wait CF config , */\ + { 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x13f0, "flag_man_operating_state"}, /* Operating state , */\ + { 0x1400, "flag_cf_speakererror_left"}, /* Left speaker status , */\ + { 0x1410, "flag_cf_speakererror_right"}, /* Right speaker status , */\ + { 0x1420, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x1433, "man_state"}, /* Device manager status , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x2003, "tdm_usecase"}, /* Usecase setting , */\ + { 0x2040, "tdm_enable"}, /* Enable interface , */\ + { 0x2050, "tdm_mode"}, /* Slave/master , */\ + { 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2073, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ + { 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ + { 0x2103, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ + { 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ + { 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2271, "tdm_txdata_format"}, /* Format unused bits , */\ + { 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots GAINIO , */\ + { 0x22b1, "tdm_txdata_format_unused_slot_sd1"}, /* Format unused slots DIO1 , */\ + { 0x22d1, "tdm_txdata_format_unused_slot_sd2"}, /* Format unused slots DIO2 , */\ + { 0x2300, "tdm_sink0_enable"}, /* Control gainin (not used in DSP) , */\ + { 0x2310, "tdm_sink1_enable"}, /* Control audio left , */\ + { 0x2320, "tdm_sink2_enable"}, /* Control audio right , */\ + { 0x2330, "tdm_source0_enable"}, /* Control gainout (not used in DSP) , */\ + { 0x2340, "tdm_source1_enable"}, /* Control voltage sense right , */\ + { 0x2350, "tdm_source2_enable"}, /* Control current sense right , */\ + { 0x2360, "tdm_source3_enable"}, /* Voltage sense left control , */\ + { 0x2370, "tdm_source4_enable"}, /* Current sense left control , */\ + { 0x2380, "tdm_source5_enable"}, /* DSP out right control , */\ + { 0x2390, "tdm_source6_enable"}, /* DSP out left control , */\ + { 0x23a0, "tdm_source7_enable"}, /* AEC ref left control , */\ + { 0x23b0, "tdm_source8_enable"}, /* AEC ref right control , */\ + { 0x23c0, "tdm_source9_enable"}, /* PDM 1 control , */\ + { 0x23d0, "tdm_source10_enable"}, /* PDM 2 control , */\ + { 0x2401, "tdm_sink0_io"}, /* IO gainin (not used in DSP) , */\ + { 0x2421, "tdm_sink1_io"}, /* IO audio left , */\ + { 0x2441, "tdm_sink2_io"}, /* IO audio right , */\ + { 0x2461, "tdm_source0_io"}, /* IO gainout (not used in DSP) , */\ + { 0x2481, "tdm_source1_io"}, /* IO voltage sense right , */\ + { 0x24a1, "tdm_source2_io"}, /* IO current sense right , */\ + { 0x24c1, "tdm_source3_io"}, /* IO voltage sense left , */\ + { 0x24e1, "tdm_source4_io"}, /* IO current sense left , */\ + { 0x2501, "tdm_source5_io"}, /* IO dspout right , */\ + { 0x2521, "tdm_source6_io"}, /* IO dspout left , */\ + { 0x2541, "tdm_source7_io"}, /* IO AEC ref left control , */\ + { 0x2561, "tdm_source8_io"}, /* IO AEC ref right control , */\ + { 0x2581, "tdm_source9_io"}, /* IO pdm1 , */\ + { 0x25a1, "tdm_source10_io"}, /* IO pdm2 , */\ + { 0x2603, "tdm_sink0_slot"}, /* Position gainin (not used in DSP) , */\ + { 0x2643, "tdm_sink1_slot"}, /* Position audio left , */\ + { 0x2683, "tdm_sink2_slot"}, /* Position audio right , */\ + { 0x26c3, "tdm_source0_slot"}, /* Position gainout (not used in DSP) , */\ + { 0x2703, "tdm_source1_slot"}, /* Position voltage sense right , */\ + { 0x2743, "tdm_source2_slot"}, /* Position current sense right , */\ + { 0x2783, "tdm_source3_slot"}, /* Position voltage sense left , */\ + { 0x27c3, "tdm_source4_slot"}, /* Position current sense left , */\ + { 0x2803, "tdm_source5_slot"}, /* Position dspout right , */\ + { 0x2843, "tdm_source6_slot"}, /* Position dspout left , */\ + { 0x2883, "tdm_source7_slot"}, /* Position AEC ref left control , */\ + { 0x28c3, "tdm_source8_slot"}, /* Position AEC ref right control , */\ + { 0x2903, "tdm_source9_slot"}, /* Position pdm1 , */\ + { 0x2943, "tdm_source10_slot"}, /* Position pdm2 , */\ + { 0x3100, "pdm_mode"}, /* PDM control , */\ + { 0x3111, "pdm_side_tone_sel"}, /* Side tone input , */\ + { 0x3130, "pdm_left_sel"}, /* PDM data selection for left channel during PDM direct mode, */\ + { 0x3140, "pdm_right_sel"}, /* PDM data selection for right channel during PDM direct mode, */\ + { 0x3150, "enbl_micvdd"}, /* Enable MICVDD , */\ + { 0x3160, "bypass_micvdd_ocp"}, /* Bypass control for the MICVDD OCP flag processing , */\ + { 0x3201, "pdm_nbck"}, /* PDM BCK/Fs ratio , */\ + { 0x3223, "pdm_gain"}, /* PDM gain , */\ + { 0x3263, "sel_pdm_out_data"}, /* PDM output selection - RE/FE data combination , */\ + { 0x32a0, "sel_cf_haptic_data"}, /* Select the source for haptic data output (not for customer), */\ + { 0x3307, "haptic_duration"}, /* Duration (ms) , */\ + { 0x3387, "haptic_data"}, /* DC value (FFS) , */\ + { 0x3403, "gpio_datain"}, /* Receiving value , */\ + { 0x3500, "gpio_ctrl"}, /* GPIO master control over GPIO1/2 ports (not for customer), */\ + { 0x3513, "gpio_dir"}, /* Configuration , */\ + { 0x3553, "gpio_dataout"}, /* Transmitting value , */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_pll_lock"}, /* Status PLL lock , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ovpok"}, /* Status OVP alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_clocks_stable"}, /* Status clocks stable , */\ + { 0x4060, "int_out_flag_mtp_busy"}, /* Status MTP busy , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4080, "int_out_flag_cf_speakererror"}, /* Status speaker error , */\ + { 0x4090, "int_out_flag_cold_started"}, /* Status cold start , */\ + { 0x40a0, "int_out_flag_engage"}, /* Status amplifier engage , */\ + { 0x40b0, "int_out_flag_watchdog_reset"}, /* Status watchdog , */\ + { 0x40c0, "int_out_flag_enbl_amp"}, /* Status amplifier enable , */\ + { 0x40d0, "int_out_flag_enbl_ref"}, /* Status Ref enable , */\ + { 0x40e0, "int_out_flag_adc10_ready"}, /* Status Control ADC , */\ + { 0x40f0, "int_out_flag_bod_vddd_nok"}, /* Status BOD , */\ + { 0x4100, "int_out_flag_bst_bstcur"}, /* Status DCDC current limiting , */\ + { 0x4110, "int_out_flag_bst_hiz"}, /* Status DCDC active , */\ + { 0x4120, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4130, "int_out_flag_bst_peakcur"}, /* Status bst peakcur , */\ + { 0x4140, "int_out_flag_bst_voutcomp"}, /* Status DCDC level 1x , */\ + { 0x4150, "int_out_flag_bst_voutcomp86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "int_out_flag_bst_voutcomp93"}, /* Status DCDC level 1.07x , */\ + { 0x4170, "int_out_flag_rcvldop_ready"}, /* Status rcvldop ready , */\ + { 0x4180, "int_out_flag_ocp_alarm_left"}, /* Status ocp alarm left , */\ + { 0x4190, "int_out_flag_ocp_alarm_right"}, /* Status ocp alarm right , */\ + { 0x41a0, "int_out_flag_man_wait_src_settings"}, /* Status Waits HW I2C settings , */\ + { 0x41b0, "int_out_flag_man_wait_cf_config"}, /* Status waits CF config , */\ + { 0x41c0, "int_out_flag_man_start_mute_audio"}, /* Status Audio mute sequence , */\ + { 0x41d0, "int_out_flag_cfma_err"}, /* Status cfma error , */\ + { 0x41e0, "int_out_flag_cfma_ack"}, /* Status cfma ack , */\ + { 0x41f0, "int_out_flag_clk_out_of_range"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "int_out_flag_tdm_error"}, /* Status tdm error , */\ + { 0x4210, "int_out_flag_clip_left"}, /* Status clip left , */\ + { 0x4220, "int_out_flag_clip_right"}, /* Status clip right , */\ + { 0x4230, "int_out_flag_mic_ocpok"}, /* Status mic ocpok , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_pll_lock"}, /* Clear PLL lock , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ovpok"}, /* Clear OVP alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_clocks_stable"}, /* Clear clocks stable , */\ + { 0x4460, "int_in_flag_mtp_busy"}, /* Clear mtp busy , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4480, "int_in_flag_cf_speakererror"}, /* Clear speaker error , */\ + { 0x4490, "int_in_flag_cold_started"}, /* Clear cold started , */\ + { 0x44a0, "int_in_flag_engage"}, /* Clear amplifier engage , */\ + { 0x44b0, "int_in_flag_watchdog_reset"}, /* Clear watchdog , */\ + { 0x44c0, "int_in_flag_enbl_amp"}, /* Clear enbl amp , */\ + { 0x44d0, "int_in_flag_enbl_ref"}, /* Clear ref enable , */\ + { 0x44e0, "int_in_flag_adc10_ready"}, /* Clear control ADC , */\ + { 0x44f0, "int_in_flag_bod_vddd_nok"}, /* Clear BOD , */\ + { 0x4500, "int_in_flag_bst_bstcur"}, /* Clear DCDC current limiting , */\ + { 0x4510, "int_in_flag_bst_hiz"}, /* Clear DCDC active , */\ + { 0x4520, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4530, "int_in_flag_bst_peakcur"}, /* Clear bst peakcur , */\ + { 0x4540, "int_in_flag_bst_voutcomp"}, /* Clear DCDC level 1x , */\ + { 0x4550, "int_in_flag_bst_voutcomp86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "int_in_flag_bst_voutcomp93"}, /* Clear DCDC level 1.07x , */\ + { 0x4570, "int_in_flag_rcvldop_ready"}, /* Clear rcvldop ready , */\ + { 0x4580, "int_in_flag_ocp_alarm_left"}, /* Clear ocp alarm left , */\ + { 0x4590, "int_in_flag_ocp_alarm_right"}, /* Clear ocp alarm right , */\ + { 0x45a0, "int_in_flag_man_wait_src_settings"}, /* Clear wait HW I2C settings , */\ + { 0x45b0, "int_in_flag_man_wait_cf_config"}, /* Clear wait cf config , */\ + { 0x45c0, "int_in_flag_man_start_mute_audio"}, /* Clear audio mute sequence , */\ + { 0x45d0, "int_in_flag_cfma_err"}, /* Clear cfma err , */\ + { 0x45e0, "int_in_flag_cfma_ack"}, /* Clear cfma ack , */\ + { 0x45f0, "int_in_flag_clk_out_of_range"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ + { 0x4610, "int_in_flag_clip_left"}, /* Clear clip left , */\ + { 0x4620, "int_in_flag_clip_right"}, /* Clear clip right , */\ + { 0x4630, "int_in_flag_mic_ocpok"}, /* Clear mic ocpok , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable por , */\ + { 0x4810, "int_enable_flag_pll_lock"}, /* Enable pll lock , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ovpok"}, /* Enable OVP alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_clocks_stable"}, /* Enable clocks stable , */\ + { 0x4860, "int_enable_flag_mtp_busy"}, /* Enable mtp busy , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4880, "int_enable_flag_cf_speakererror"}, /* Enable speaker error , */\ + { 0x4890, "int_enable_flag_cold_started"}, /* Enable cold started , */\ + { 0x48a0, "int_enable_flag_engage"}, /* Enable amplifier engage , */\ + { 0x48b0, "int_enable_flag_watchdog_reset"}, /* Enable watchdog , */\ + { 0x48c0, "int_enable_flag_enbl_amp"}, /* Enable enbl amp , */\ + { 0x48d0, "int_enable_flag_enbl_ref"}, /* Enable ref enable , */\ + { 0x48e0, "int_enable_flag_adc10_ready"}, /* Enable Control ADC , */\ + { 0x48f0, "int_enable_flag_bod_vddd_nok"}, /* Enable BOD , */\ + { 0x4900, "int_enable_flag_bst_bstcur"}, /* Enable DCDC current limiting , */\ + { 0x4910, "int_enable_flag_bst_hiz"}, /* Enable DCDC active , */\ + { 0x4920, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4930, "int_enable_flag_bst_peakcur"}, /* Enable bst peakcur , */\ + { 0x4940, "int_enable_flag_bst_voutcomp"}, /* Enable DCDC level 1x , */\ + { 0x4950, "int_enable_flag_bst_voutcomp86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "int_enable_flag_bst_voutcomp93"}, /* Enable DCDC level 1.07x , */\ + { 0x4970, "int_enable_flag_rcvldop_ready"}, /* Enable rcvldop ready , */\ + { 0x4980, "int_enable_flag_ocp_alarm_left"}, /* Enable ocp alarm left , */\ + { 0x4990, "int_enable_flag_ocp_alarm_right"}, /* Enable ocp alarm right , */\ + { 0x49a0, "int_enable_flag_man_wait_src_settings"}, /* Enable waits HW I2C settings , */\ + { 0x49b0, "int_enable_flag_man_wait_cf_config"}, /* Enable man wait cf config , */\ + { 0x49c0, "int_enable_flag_man_start_mute_audio"}, /* Enable man Audio mute sequence , */\ + { 0x49d0, "int_enable_flag_cfma_err"}, /* Enable cfma err , */\ + { 0x49e0, "int_enable_flag_cfma_ack"}, /* Enable cfma ack , */\ + { 0x49f0, "int_enable_flag_clk_out_of_range"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ + { 0x4a10, "int_enable_flag_clip_left"}, /* Enable clip left , */\ + { 0x4a20, "int_enable_flag_clip_right"}, /* Enable clip right , */\ + { 0x4a30, "int_enable_flag_mic_ocpok"}, /* Enable mic ocpok , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ + { 0x4c10, "int_polarity_flag_pll_lock"}, /* Polarity pll lock , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ovpok"}, /* Polarity OVP alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_clocks_stable"}, /* Polarity clocks stable , */\ + { 0x4c60, "int_polarity_flag_mtp_busy"}, /* Polarity mtp busy , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4c80, "int_polarity_flag_cf_speakererror"}, /* Polarity speaker error , */\ + { 0x4c90, "int_polarity_flag_cold_started"}, /* Polarity cold started , */\ + { 0x4ca0, "int_polarity_flag_engage"}, /* Polarity amplifier engage , */\ + { 0x4cb0, "int_polarity_flag_watchdog_reset"}, /* Polarity watchdog , */\ + { 0x4cc0, "int_polarity_flag_enbl_amp"}, /* Polarity enbl amp , */\ + { 0x4cd0, "int_polarity_flag_enbl_ref"}, /* Polarity ref enable , */\ + { 0x4ce0, "int_polarity_flag_adc10_ready"}, /* Polarity Control ADC , */\ + { 0x4cf0, "int_polarity_flag_bod_vddd_nok"}, /* Polarity BOD , */\ + { 0x4d00, "int_polarity_flag_bst_bstcur"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "int_polarity_flag_bst_hiz"}, /* Polarity DCDC active , */\ + { 0x4d20, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "int_polarity_flag_bst_peakcur"}, /* Polarity bst peakcur , */\ + { 0x4d40, "int_polarity_flag_bst_voutcomp"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "int_polarity_flag_bst_voutcomp86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "int_polarity_flag_bst_voutcomp93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d70, "int_polarity_flag_rcvldop_ready"}, /* Polarity rcvldop ready , */\ + { 0x4d80, "int_polarity_flag_ocp_alarm_left"}, /* Polarity ocp alarm left , */\ + { 0x4d90, "int_polarity_flag_ocp_alarm_right"}, /* Polarity ocp alarm right , */\ + { 0x4da0, "int_polarity_flag_man_wait_src_settings"}, /* Polarity waits HW I2C settings , */\ + { 0x4db0, "int_polarity_flag_man_wait_cf_config"}, /* Polarity man wait cf config , */\ + { 0x4dc0, "int_polarity_flag_man_start_mute_audio"}, /* Polarity man audio mute sequence , */\ + { 0x4dd0, "int_polarity_flag_cfma_err"}, /* Polarity cfma err , */\ + { 0x4de0, "int_polarity_flag_cfma_ack"}, /* Polarity cfma ack , */\ + { 0x4df0, "int_polarity_flag_clk_out_of_range"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ + { 0x4e10, "int_polarity_flag_clip_left"}, /* Polarity clip left , */\ + { 0x4e20, "int_polarity_flag_clip_right"}, /* Polarity clip right , */\ + { 0x4e30, "int_polarity_flag_mic_ocpok"}, /* Polarity mic ocpok , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery protection attack Time , */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery protection threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery protection maximum reduction , */\ + { 0x5082, "vbat_prot_release_time"}, /* Battery protection release time , */\ + { 0x50b1, "vbat_prot_hysterese"}, /* Battery protection hysteresis , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass HW clipper , */\ + { 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ + { 0x5110, "soft_mute"}, /* Soft mute HW , */\ + { 0x5120, "cf_mute_left"}, /* Soft mute FW left , */\ + { 0x5130, "cf_mute_right"}, /* Soft mute FW right , */\ + { 0x5140, "bypass_hp_left"}, /* Bypass HPF left , */\ + { 0x5150, "bypass_hp_right"}, /* Bypass HPF right , */\ + { 0x5160, "enbl_dpsa_left"}, /* Enable DPSA left , */\ + { 0x5170, "enbl_dpsa_right"}, /* Enable DPSA right , */\ + { 0x5187, "cf_volume"}, /* FW volume control for primary audio channel , */\ + { 0x5200, "ctrl_rcv"}, /* Selection receiver , */\ + { 0x5210, "ctrl_rcv_fb_100k"}, /* Selection of feedback resistor for receiver mode (not for customer), */\ + { 0x5222, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5257, "gain"}, /* Amplifier gain , */\ + { 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x52e1, "ctrl_slope"}, /* Set slope , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5340, "clipfast"}, /* Clock selection for HW clipper for battery protection, */\ + { 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x5360, "enbl_low_latency"}, /* CF low latency outputs for add module , */\ + { 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5410, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5420, "fb_hz"}, /* Feedback resistor set to high ohmic , */\ + { 0x5430, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x5503, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5543, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5581, "dpsa_drive"}, /* Control of the number of power stage sections, total of 4 sections. Each section is 1/4 of the total power stages., */\ + { 0x560a, "enbl_amp_left"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually - Left channel, */\ + { 0x56b0, "enbl_engage_left"}, /* Enables/engage power stage and control loop - left channel, */\ + { 0x570a, "enbl_amp_right"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually - Right channel, */\ + { 0x57b0, "enbl_engage_right"}, /* Enables/engage power stage and control loop - right channel, */\ + { 0x5800, "hard_mute_left"}, /* Hard mute - PWM module left , */\ + { 0x5810, "hard_mute_right"}, /* Hard mute - PWM module right , */\ + { 0x5820, "pwm_shape"}, /* PWM shape , */\ + { 0x5830, "pwm_bitlength"}, /* PWM bit length in noise shaper , */\ + { 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ + { 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ + { 0x58b0, "enbl_pwm_phase_shift_left"}, /* Control for pwm phase shift, inverted function - left channel, */\ + { 0x58c0, "enbl_pwm_phase_shift_right"}, /* Control for pwm phase shift - right channel , */\ + { 0x5900, "ctrl_rcvldop_pulldown"}, /* Pulldown of LDO (2.7V) , */\ + { 0x5910, "ctrl_rcvldop_test_comp"}, /* Enable testing of LDO comparator , */\ + { 0x5920, "ctrl_rcvldop_test_loadedldo"}, /* Load connected to rcvldo , */\ + { 0x5930, "enbl_rcvldop"}, /* Enables the LDO (2.7) , */\ + { 0x5a07, "cf_volume_sec"}, /* FW volume control for secondary audio channel , */\ + { 0x5a87, "sw_profile"}, /* Software profile data , */\ + { 0x7002, "boost_volt"}, /* Boost voltage , */\ + { 0x7033, "boost_cur"}, /* Max coil current , */\ + { 0x7071, "bst_coil_value"}, /* Coil Value , */\ + { 0x7090, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x70a0, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x70b2, "dcdc_synchronisation"}, /* DCDC synchronization off + 7 positions , */\ + { 0x70e0, "dcdcoff_mode"}, /* DCDC on/off , */\ + { 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7174, "bst_slopecur"}, /* For testing direct control slope current , */\ + { 0x71c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ + { 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ + { 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7230, "enbl_bst_peakcur"}, /* Enable peak current , */\ + { 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage , */\ + { 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ + { 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x7290, "enbl_bst_windac"}, /* Enable window dac , */\ + { 0x72a5, "bst_windac"}, /* for testing direct control windac , */\ + { 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7332, "bst_freq"}, /* DCDC bost frequency control , */\ + { 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ + { 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ + { 0x8040, "cs_dc_offset"}, /* Current sense decimator offset control , */\ + { 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8110, "invertpwm_left"}, /* Current sense common mode feedback pwm invert control for left channel, */\ + { 0x8122, "cmfb_gain_left"}, /* Current sense common mode feedback control gain for left channel, */\ + { 0x8154, "cmfb_offset_left"}, /* Current sense common mode feedback control offset for left channel, */\ + { 0x8200, "enbl_cmfb_right"}, /* Current sense common mode feedback control for right channel, */\ + { 0x8210, "invertpwm_right"}, /* Current sense common mode feedback pwm invert control for right channel, */\ + { 0x8222, "cmfb_gain_right"}, /* Current sense common mode feedback control gain for right channel, */\ + { 0x8254, "cmfb_offset_right"}, /* Current sense common mode feedback control offset for right channel, */\ + { 0x8305, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP)*signal, */\ + { 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8421, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ + { 0x8440, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x8453, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ + { 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x84a4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ + { 0x8500, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ + { 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ + { 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8600, "enbl_cs_adc_left"}, /* Enable current sense ADC , */\ + { 0x8610, "enbl_cs_inn1_left"}, /* Enable connection of current sense negative1 , */\ + { 0x8630, "enbl_cs_inp1_left"}, /* Enable connection of current sense positive1 , */\ + { 0x8650, "enbl_cs_ldo_left"}, /* Enable current sense LDO , */\ + { 0x8660, "enbl_cs_nofloating_n_left"}, /* Connect current sense negative to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8670, "enbl_cs_nofloating_p_left"}, /* Connect current sense positive to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8680, "enbl_cs_vbatldo_left"}, /* Enable of current sense LDO , */\ + { 0x8700, "enbl_cs_adc_right"}, /* Enable current sense ADC , */\ + { 0x8710, "enbl_cs_inn1_right"}, /* Enable connection of current sense negative1 , */\ + { 0x8730, "enbl_cs_inp1_right"}, /* Enable connection of current sense positive1 , */\ + { 0x8750, "enbl_cs_ldo_right"}, /* Enable current sense LDO , */\ + { 0x8760, "enbl_cs_nofloating_n_right"}, /* Connect current sense negative to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8770, "enbl_cs_nofloating_p_right"}, /* Connect current sense positive to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8780, "enbl_cs_vbatldo_right"}, /* Enable of current sense LDO , */\ + { 0x8800, "volsense_pwm_sel"}, /* Voltage sense PWM source selection control , */\ + { 0x8810, "volsense_dc_offset"}, /* Voltage sense decimator offset control , */\ + { 0x9000, "cf_rst_dsp"}, /* Reset , */\ + { 0x9011, "cf_dmem"}, /* Target memory , */\ + { 0x9030, "cf_aif"}, /* Auto increment , */\ + { 0x9040, "cf_int"}, /* Interrupt - auto clear , */\ + { 0x9050, "cf_cgate_off"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "cf_req_cmd"}, /* Firmware event request rpc command , */\ + { 0x9090, "cf_req_reset"}, /* Firmware event request reset restart , */\ + { 0x90a0, "cf_req_mips"}, /* Firmware event request short on mips , */\ + { 0x90b0, "cf_req_mute_ready"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "cf_req_volume_ready"}, /* Firmware event request volume ready , */\ + { 0x90d0, "cf_req_damage"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "cf_req_calibrate_ready"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "cf_req_reserved"}, /* Firmware event request reserved , */\ + { 0x910f, "cf_madd"}, /* Memory address , */\ + { 0x920f, "cf_mema"}, /* Activate memory access , */\ + { 0x9307, "cf_err"}, /* Error flags , */\ + { 0x9387, "cf_ack"}, /* Acknowledge of requests , */\ + { 0x9380, "cf_ack_cmd"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "cf_ack_reset"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "cf_ack_mips"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "cf_ack_mute_ready"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "cf_ack_volume_ready"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "cf_ack_damage"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "cf_ack_calibrate_ready"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "cf_ack_reserved"}, /* Firmware event acknowledge reserved , */\ + { 0x980f, "ivt_addr0_msb"}, /* Coolflux interrupt vector table address0 MSB , */\ + { 0x990f, "ivt_addr0_lsb"}, /* Coolflux interrupt vector table address0 LSB , */\ + { 0x9a0f, "ivt_addr1_msb"}, /* Coolflux interrupt vector table address1 MSB , */\ + { 0x9b0f, "ivt_addr1_lsb"}, /* Coolflux interrupt vector table address1 LSB , */\ + { 0x9c0f, "ivt_addr2_msb"}, /* Coolflux interrupt vector table address2 MSB , */\ + { 0x9d0f, "ivt_addr2_lsb"}, /* Coolflux interrupt vector table address2 LSB , */\ + { 0x9e0f, "ivt_addr3_msb"}, /* Coolflux interrupt vector table address3 MSB , */\ + { 0x9f0f, "ivt_addr3_lsb"}, /* Coolflux interrupt vector table address3 LSB , */\ + { 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa400, "faim_set_clkws"}, /* Sets the faim controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the faim are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the faim are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb050, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ + { 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ + { 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0xc3d0, "test_abistfft_enbl"}, /* FFT Coolflux , */\ + { 0xc3e0, "test_pwr_switch"}, /* Test mode for digital power switches core sw/mem sw/micvdd sw, */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc660, "bypass_diosw_ovp"}, /* Bypass ovp for memory switch diosw , */\ + { 0xc670, "enbl_powerswitch"}, /* Vddd core power switch control - overrules the manager control, */\ + { 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to GPIO1 (see Digimux list for details), */\ + { 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to GPIO2 (see Digimux list for details), */\ + { 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to GPIO3 (see Digimux list for details), */\ + { 0xc887, "digimuxd_sel"}, /* DigimuxD input selection control routed to GPIO4 (see Digimux list for details), */\ + { 0xc901, "dio1_ehs"}, /* Speed/load setting for DIO1 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc921, "dio2_ehs"}, /* Speed/load setting for DIO2 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc941, "gainio_ehs"}, /* Speed/load setting for GAINIO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc961, "pdmo_ehs"}, /* Speed/load setting for PDMO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc981, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9a1, "tdo_ehs"}, /* Speed/load setting for TDO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9c0, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xca40, "enbl_anamux5"}, /* Enable anamux5 , */\ + { 0xca50, "enbl_anamux6"}, /* Enable anamux6 , */\ + { 0xca60, "enbl_anamux7"}, /* Enable anamux7 , */\ + { 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xcb04, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ + { 0xcb54, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ + { 0xcba4, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ + { 0xcc04, "anamux5"}, /* Anamux selection control - anamux on TEST5 , */\ + { 0xcc54, "anamux6"}, /* Anamux selection control - anamux on TEST6 , */\ + { 0xcca4, "anamux7"}, /* Anamux selection control - anamux on TEST7 , */\ + { 0xcd05, "pll_seli"}, /* PLL SELI - I2C direct PLL control mode only , */\ + { 0xcd64, "pll_selp"}, /* PLL SELP - I2C direct PLL control mode only , */\ + { 0xcdb3, "pll_selr"}, /* PLL SELR - I2C direct PLL control mode only , */\ + { 0xcdf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ + { 0xce09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0xcea0, "pll_mdec_msb"}, /* MSB of pll_mdec - I2C direct PLL control mode only, */\ + { 0xceb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ + { 0xcec0, "enbl_osc"}, /* Enables OSC1M in I2C direct control mode only , */\ + { 0xced0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ + { 0xcee0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ + { 0xcef0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ + { 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ + { 0xd006, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd243, "tsig_gain_left"}, /* Test signal gain for left channel , */\ + { 0xd283, "tsig_gain_right"}, /* Test signal gain for right channel , */\ + { 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd506, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd570, "enbl_clk_out_of_range"}, /* Clock out of range , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf163, "calibr_gain_left"}, /* HW gain module - left channel (2's complement) , */\ + { 0xf1a5, "calibr_offset_left"}, /* Offset for amplifier, HW gain module - left channel (2's complement), */\ + { 0xf203, "calibr_gain_right"}, /* HW gain module - right channel (2's complement) , */\ + { 0xf245, "calibr_offset_right"}, /* Offset for amplifier, HW gain module - right channel (2's complement), */\ + { 0xf2a3, "calibr_rcvldop_trim"}, /* Trimming of LDO (2.7V) , */\ + { 0xf307, "calibr_gain_cs_left"}, /* Current sense gain - left channel (signed two's complement format), */\ + { 0xf387, "calibr_gain_cs_right"}, /* Current sense gain - right channel (signed two's complement format), */\ + { 0xf40f, "calibr_R25C_L"}, /* Ron resistance of left channel speaker coil , */\ + { 0xf50f, "calibr_R25C_R"}, /* Ron resistance of right channel speaker coil , */\ + { 0xf606, "ctrl_offset_a_left"}, /* Offset of left amplifier level shifter A , */\ + { 0xf686, "ctrl_offset_b_left"}, /* Offset of left amplifier level shifter B , */\ + { 0xf706, "ctrl_offset_a_right"}, /* Offset of right amplifier level shifter A , */\ + { 0xf786, "ctrl_offset_b_right"}, /* Offset of right amplifier level shifter B , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable function dcdcoff_mode , */\ + { 0xf910, "mtp_lock_enbl_coolflux"}, /* Disable function enbl_coolflux , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Disable programming of max dcdc boost voltage , */\ + { 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf987, "type_bits_fw"}, /* MTP-control FW - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ + { 0xff05, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa2_irq { + tfa2_irq_stvdds = 0, + tfa2_irq_stplls = 1, + tfa2_irq_stotds = 2, + tfa2_irq_stovds = 3, + tfa2_irq_stuvds = 4, + tfa2_irq_stclks = 5, + tfa2_irq_stmtpb = 6, + tfa2_irq_stnoclk = 7, + tfa2_irq_stspks = 8, + tfa2_irq_stacs = 9, + tfa2_irq_stsws = 10, + tfa2_irq_stwds = 11, + tfa2_irq_stamps = 12, + tfa2_irq_starefs = 13, + tfa2_irq_stadccr = 14, + tfa2_irq_stbodnok = 15, + tfa2_irq_stbstcu = 16, + tfa2_irq_stbsthi = 17, + tfa2_irq_stbstoc = 18, + tfa2_irq_stbstpkcur = 19, + tfa2_irq_stbstvc = 20, + tfa2_irq_stbst86 = 21, + tfa2_irq_stbst93 = 22, + tfa2_irq_strcvld = 23, + tfa2_irq_stocpl = 24, + tfa2_irq_stocpr = 25, + tfa2_irq_stmwsrc = 26, + tfa2_irq_stmwcfc = 27, + tfa2_irq_stmwsmu = 28, + tfa2_irq_stcfmer = 29, + tfa2_irq_stcfmac = 30, + tfa2_irq_stclkoor = 31, + tfa2_irq_sttdmer = 32, + tfa2_irq_stclpl = 33, + tfa2_irq_stclpr = 34, + tfa2_irq_stocpm = 35, + tfa2_irq_max = 36, + tfa2_irq_all = -1 /* all irqs */}; + +#define TFA2_IRQ_NAMETABLE static tfaIrqName_t Tfa2IrqNames[] = {\ + { 0, "STVDDS"},\ + { 1, "STPLLS"},\ + { 2, "STOTDS"},\ + { 3, "STOVDS"},\ + { 4, "STUVDS"},\ + { 5, "STCLKS"},\ + { 6, "STMTPB"},\ + { 7, "STNOCLK"},\ + { 8, "STSPKS"},\ + { 9, "STACS"},\ + { 10, "STSWS"},\ + { 11, "STWDS"},\ + { 12, "STAMPS"},\ + { 13, "STAREFS"},\ + { 14, "STADCCR"},\ + { 15, "STBODNOK"},\ + { 16, "STBSTCU"},\ + { 17, "STBSTHI"},\ + { 18, "STBSTOC"},\ + { 19, "STBSTPKCUR"},\ + { 20, "STBSTVC"},\ + { 21, "STBST86"},\ + { 22, "STBST93"},\ + { 23, "STRCVLD"},\ + { 24, "STOCPL"},\ + { 25, "STOCPR"},\ + { 26, "STMWSRC"},\ + { 27, "STMWCFC"},\ + { 28, "STMWSMU"},\ + { 29, "STCFMER"},\ + { 30, "STCFMAC"},\ + { 31, "STCLKOOR"},\ + { 32, "STTDMER"},\ + { 33, "STCLPL"},\ + { 34, "STCLPR"},\ + { 35, "STOCPM"},\ + { 36, "36"},\ +}; diff --git a/sound/soc/codecs/tfa9872_tfafieldnames.h b/sound/soc/codecs/tfa9872_tfafieldnames.h new file mode 100644 index 000000000000..6dd639e01eac --- /dev/null +++ b/sound/soc/codecs/tfa9872_tfafieldnames.h @@ -0,0 +1,1221 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9872_TFAFIELDNAMES_H +#define _TFA9872_TFAFIELDNAMES_H + +#define TFA9872_I2CVERSION_N1A 26 +#define TFA9872_I2CVERSION_N1B 29 +#define TFA9872_I2CVERSION_N1B2 25 + +typedef enum nxpTfa9872BfEnumList { +TFA9872_BF_PWDN = 0x0000, /*!< Powerdown selection */ +TFA9872_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ +TFA9872_BF_AMPE = 0x0030, /*!< Activate Amplifier */ +TFA9872_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ +TFA9872_BF_INTP = 0x0071, /*!< Interrupt config */ +TFA9872_BF_BYPOCP = 0x00b0, /*!< Bypass OCP */ +TFA9872_BF_TSTOCP = 0x00c0, /*!< OCP testing control */ +TFA9872_BF_MANSCONF = 0x0120, /*!< I2C configured */ +TFA9872_BF_MANAOOSC = 0x0140, /*!< Internal osc off at PWDN */ +TFA9872_BF_MUTETO = 0x01d0, /*!< Time out SB mute sequence */ +TFA9872_BF_RCVNS = 0x01e0, /*!< Noise shaper selection */ +TFA9872_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ +TFA9872_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ +TFA9872_BF_FRACTDEL = 0x0255, /*!< V/I Fractional delay */ +TFA9872_BF_BYPHVBF = 0x02b0, /*!< Bypass HVBAT filter */ +TFA9872_BF_REV = 0x030f, /*!< Revision info */ +TFA9872_BF_REFCKEXT = 0x0401, /*!< PLL external ref clock */ +TFA9872_BF_REFCKSEL = 0x0420, /*!< PLL internal ref clock */ +TFA9872_BF_SSE = 0x0510, /*!< Enable speaker path */ +TFA9872_BF_VSE = 0x0530, /*!< Voltage sense */ +TFA9872_BF_CSE = 0x0550, /*!< Current sense */ +TFA9872_BF_SSPDME = 0x0560, /*!< Sub-system PDM */ +TFA9872_BF_PGAE = 0x0580, /*!< Enable PGA chop clock */ +TFA9872_BF_SSTDME = 0x0590, /*!< Sub-system TDM */ +TFA9872_BF_SSPBSTE = 0x05a0, /*!< Sub-system boost */ +TFA9872_BF_SSADCE = 0x05b0, /*!< Sub-system ADC */ +TFA9872_BF_SSFAIME = 0x05c0, /*!< Sub-system FAIM */ +TFA9872_BF_STGAIN = 0x0d18, /*!< Side tone gain */ +TFA9872_BF_STSMUTE = 0x0da0, /*!< Side tone soft mute */ +TFA9872_BF_ST1C = 0x0db0, /*!< side tone one s complement */ +TFA9872_BF_VDDS = 0x1000, /*!< POR */ +TFA9872_BF_PLLS = 0x1010, /*!< PLL lock */ +TFA9872_BF_OTDS = 0x1020, /*!< OTP alarm */ +TFA9872_BF_OVDS = 0x1030, /*!< OVP alarm */ +TFA9872_BF_UVDS = 0x1040, /*!< UVP alarm */ +TFA9872_BF_CLKS = 0x1050, /*!< Clocks stable */ +TFA9872_BF_MTPB = 0x1060, /*!< MTP busy */ +TFA9872_BF_NOCLK = 0x1070, /*!< Lost clock */ +TFA9872_BF_SWS = 0x10a0, /*!< Amplifier engage */ +TFA9872_BF_AMPS = 0x10c0, /*!< Amplifier enable */ +TFA9872_BF_AREFS = 0x10d0, /*!< References enable */ +TFA9872_BF_ADCCR = 0x10e0, /*!< Control ADC */ +TFA9872_BF_DCIL = 0x1100, /*!< DCDC current limiting */ +TFA9872_BF_DCDCA = 0x1110, /*!< DCDC active */ +TFA9872_BF_DCOCPOK = 0x1120, /*!< DCDC OCP nmos */ +TFA9872_BF_DCHVBAT = 0x1140, /*!< DCDC level 1x */ +TFA9872_BF_DCH114 = 0x1150, /*!< DCDC level 1.14x */ +TFA9872_BF_DCH107 = 0x1160, /*!< DCDC level 1.07x */ +TFA9872_BF_STMUTEB = 0x1170, /*!< side tone (un)mute busy */ +TFA9872_BF_STMUTE = 0x1180, /*!< side tone mute state */ +TFA9872_BF_TDMLUTER = 0x1190, /*!< TDM LUT error */ +TFA9872_BF_TDMSTAT = 0x11a2, /*!< TDM status bits */ +TFA9872_BF_TDMERR = 0x11d0, /*!< TDM error */ +TFA9872_BF_OCPOAP = 0x1300, /*!< OCPOK pmos A */ +TFA9872_BF_OCPOAN = 0x1310, /*!< OCPOK nmos A */ +TFA9872_BF_OCPOBP = 0x1320, /*!< OCPOK pmos B */ +TFA9872_BF_OCPOBN = 0x1330, /*!< OCPOK nmos B */ +TFA9872_BF_CLIPAH = 0x1340, /*!< Clipping A to Vddp */ +TFA9872_BF_CLIPAL = 0x1350, /*!< Clipping A to gnd */ +TFA9872_BF_CLIPBH = 0x1360, /*!< Clipping B to Vddp */ +TFA9872_BF_CLIPBL = 0x1370, /*!< Clipping B to gnd */ +TFA9872_BF_OCDS = 0x1380, /*!< OCP amplifier */ +TFA9872_BF_CLIPS = 0x1390, /*!< Amplifier clipping */ +TFA9872_BF_OCPOKMC = 0x13a0, /*!< OCPOK MICVDD */ +TFA9872_BF_MANALARM = 0x13b0, /*!< Alarm state */ +TFA9872_BF_MANWAIT1 = 0x13c0, /*!< Wait HW I2C settings */ +TFA9872_BF_MANMUTE = 0x13e0, /*!< Audio mute sequence */ +TFA9872_BF_MANOPER = 0x13f0, /*!< Operating state */ +TFA9872_BF_CLKOOR = 0x1420, /*!< External clock status */ +TFA9872_BF_MANSTATE = 0x1433, /*!< Device manager status */ +TFA9872_BF_DCMODE = 0x1471, /*!< DCDC mode status bits */ +TFA9872_BF_BATS = 0x1509, /*!< Battery voltage (V) */ +TFA9872_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ +TFA9872_BF_VDDPS = 0x1709, /*!< IC VDDP voltage ( 1023*VDDP/9.5 V) */ +TFA9872_BF_TDME = 0x2040, /*!< Enable interface */ +TFA9872_BF_TDMMODE = 0x2050, /*!< Slave/master */ +TFA9872_BF_TDMCLINV = 0x2060, /*!< Reception data to BCK clock */ +TFA9872_BF_TDMFSLN = 0x2073, /*!< FS length (master mode only) */ +TFA9872_BF_TDMFSPOL = 0x20b0, /*!< FS polarity */ +TFA9872_BF_TDMNBCK = 0x20c3, /*!< N-BCK's in FS */ +TFA9872_BF_TDMSLOTS = 0x2103, /*!< N-slots in Frame */ +TFA9872_BF_TDMSLLN = 0x2144, /*!< N-bits in slot */ +TFA9872_BF_TDMBRMG = 0x2194, /*!< N-bits remaining */ +TFA9872_BF_TDMDEL = 0x21e0, /*!< data delay to FS */ +TFA9872_BF_TDMADJ = 0x21f0, /*!< data adjustment */ +TFA9872_BF_TDMOOMP = 0x2201, /*!< Received audio compression */ +TFA9872_BF_TDMSSIZE = 0x2224, /*!< Sample size per slot */ +TFA9872_BF_TDMTXDFO = 0x2271, /*!< Format unused bits */ +TFA9872_BF_TDMTXUS0 = 0x2291, /*!< Format unused slots DATAO */ +TFA9872_BF_TDMSPKE = 0x2300, /*!< Control audio tdm channel in 0 (spkr + dcdc) */ +TFA9872_BF_TDMDCE = 0x2310, /*!< Control audio tdm channel in 1 (dcdc) */ +TFA9872_BF_TDMCSE = 0x2330, /*!< current sense vbat temperature and vddp feedback */ +TFA9872_BF_TDMVSE = 0x2340, /*!< Voltage sense vbat temperature and vddp feedback */ +TFA9872_BF_TDMSPKS = 0x2603, /*!< tdm slot for sink 0 (speaker + dcdc) */ +TFA9872_BF_TDMDCS = 0x2643, /*!< tdm slot for sink 1 (dcdc) */ +TFA9872_BF_TDMCSS = 0x26c3, /*!< Slot Position of current sense vbat temperature and vddp feedback */ +TFA9872_BF_TDMVSS = 0x2703, /*!< Slot Position of Voltage sense vbat temperature and vddp feedback */ +TFA9872_BF_PDMSTSEL = 0x3111, /*!< Side tone input */ +TFA9872_BF_ISTVDDS = 0x4000, /*!< Status POR */ +TFA9872_BF_ISTPLLS = 0x4010, /*!< Status PLL lock */ +TFA9872_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ +TFA9872_BF_ISTOVDS = 0x4030, /*!< Status OVP alarm */ +TFA9872_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ +TFA9872_BF_ISTCLKS = 0x4050, /*!< Status clocks stable */ +TFA9872_BF_ISTMTPB = 0x4060, /*!< Status MTP busy */ +TFA9872_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ +TFA9872_BF_ISTSWS = 0x40a0, /*!< Status amplifier engage */ +TFA9872_BF_ISTAMPS = 0x40c0, /*!< Status amplifier enable */ +TFA9872_BF_ISTAREFS = 0x40d0, /*!< Status Ref enable */ +TFA9872_BF_ISTADCCR = 0x40e0, /*!< Status Control ADC */ +TFA9872_BF_ISTBSTCU = 0x4100, /*!< Status DCDC current limiting */ +TFA9872_BF_ISTBSTHI = 0x4110, /*!< Status DCDC active */ +TFA9872_BF_ISTBSTOC = 0x4120, /*!< Status DCDC OCP */ +TFA9872_BF_ISTBSTPKCUR = 0x4130, /*!< Status bst peakcur */ +TFA9872_BF_ISTBSTVC = 0x4140, /*!< Status DCDC level 1x */ +TFA9872_BF_ISTBST86 = 0x4150, /*!< Status DCDC level 1.14x */ +TFA9872_BF_ISTBST93 = 0x4160, /*!< Status DCDC level 1.07x */ +TFA9872_BF_ISTOCPR = 0x4190, /*!< Status ocp alarm */ +TFA9872_BF_ISTMWSRC = 0x41a0, /*!< Status Waits HW I2C settings */ +TFA9872_BF_ISTMWSMU = 0x41c0, /*!< Status Audio mute sequence */ +TFA9872_BF_ISTCLKOOR = 0x41f0, /*!< Status flag_clk_out_of_range */ +TFA9872_BF_ISTTDMER = 0x4200, /*!< Status tdm error */ +TFA9872_BF_ISTCLPR = 0x4220, /*!< Status clip */ +TFA9872_BF_ISTLP0 = 0x4240, /*!< Status low power mode0 */ +TFA9872_BF_ISTLP1 = 0x4250, /*!< Status low power mode1 */ +TFA9872_BF_ISTLA = 0x4260, /*!< Status low noise detection */ +TFA9872_BF_ISTVDDPH = 0x4270, /*!< Status VDDP greater than VBAT */ +TFA9872_BF_ICLVDDS = 0x4400, /*!< Clear POR */ +TFA9872_BF_ICLPLLS = 0x4410, /*!< Clear PLL lock */ +TFA9872_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ +TFA9872_BF_ICLOVDS = 0x4430, /*!< Clear OVP alarm */ +TFA9872_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ +TFA9872_BF_ICLCLKS = 0x4450, /*!< Clear clocks stable */ +TFA9872_BF_ICLMTPB = 0x4460, /*!< Clear mtp busy */ +TFA9872_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ +TFA9872_BF_ICLSWS = 0x44a0, /*!< Clear amplifier engage */ +TFA9872_BF_ICLAMPS = 0x44c0, /*!< Clear enbl amp */ +TFA9872_BF_ICLAREFS = 0x44d0, /*!< Clear ref enable */ +TFA9872_BF_ICLADCCR = 0x44e0, /*!< Clear control ADC */ +TFA9872_BF_ICLBSTCU = 0x4500, /*!< Clear DCDC current limiting */ +TFA9872_BF_ICLBSTHI = 0x4510, /*!< Clear DCDC active */ +TFA9872_BF_ICLBSTOC = 0x4520, /*!< Clear DCDC OCP */ +TFA9872_BF_ICLBSTPC = 0x4530, /*!< Clear bst peakcur */ +TFA9872_BF_ICLBSTVC = 0x4540, /*!< Clear DCDC level 1x */ +TFA9872_BF_ICLBST86 = 0x4550, /*!< Clear DCDC level 1.14x */ +TFA9872_BF_ICLBST93 = 0x4560, /*!< Clear DCDC level 1.07x */ +TFA9872_BF_ICLOCPR = 0x4590, /*!< Clear ocp alarm */ +TFA9872_BF_ICLMWSRC = 0x45a0, /*!< Clear wait HW I2C settings */ +TFA9872_BF_ICLMWSMU = 0x45c0, /*!< Clear audio mute sequence */ +TFA9872_BF_ICLCLKOOR = 0x45f0, /*!< Clear flag_clk_out_of_range */ +TFA9872_BF_ICLTDMER = 0x4600, /*!< Clear tdm error */ +TFA9872_BF_ICLCLPR = 0x4620, /*!< Clear clip */ +TFA9872_BF_ICLLP0 = 0x4640, /*!< Clear low power mode0 */ +TFA9872_BF_ICLLP1 = 0x4650, /*!< Clear low power mode1 */ +TFA9872_BF_ICLLA = 0x4660, /*!< Clear low noise detection */ +TFA9872_BF_ICLVDDPH = 0x4670, /*!< Clear VDDP greater then VBAT */ +TFA9872_BF_IEVDDS = 0x4800, /*!< Enable por */ +TFA9872_BF_IEPLLS = 0x4810, /*!< Enable pll lock */ +TFA9872_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ +TFA9872_BF_IEOVDS = 0x4830, /*!< Enable OVP alarm */ +TFA9872_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ +TFA9872_BF_IECLKS = 0x4850, /*!< Enable clocks stable */ +TFA9872_BF_IEMTPB = 0x4860, /*!< Enable mtp busy */ +TFA9872_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ +TFA9872_BF_IESWS = 0x48a0, /*!< Enable amplifier engage */ +TFA9872_BF_IEAMPS = 0x48c0, /*!< Enable enbl amp */ +TFA9872_BF_IEAREFS = 0x48d0, /*!< Enable ref enable */ +TFA9872_BF_IEADCCR = 0x48e0, /*!< Enable Control ADC */ +TFA9872_BF_IEBSTCU = 0x4900, /*!< Enable DCDC current limiting */ +TFA9872_BF_IEBSTHI = 0x4910, /*!< Enable DCDC active */ +TFA9872_BF_IEBSTOC = 0x4920, /*!< Enable DCDC OCP */ +TFA9872_BF_IEBSTPC = 0x4930, /*!< Enable bst peakcur */ +TFA9872_BF_IEBSTVC = 0x4940, /*!< Enable DCDC level 1x */ +TFA9872_BF_IEBST86 = 0x4950, /*!< Enable DCDC level 1.14x */ +TFA9872_BF_IEBST93 = 0x4960, /*!< Enable DCDC level 1.07x */ +TFA9872_BF_IEOCPR = 0x4990, /*!< Enable ocp alarm */ +TFA9872_BF_IEMWSRC = 0x49a0, /*!< Enable waits HW I2C settings */ +TFA9872_BF_IEMWSMU = 0x49c0, /*!< Enable man Audio mute sequence */ +TFA9872_BF_IECLKOOR = 0x49f0, /*!< Enable flag_clk_out_of_range */ +TFA9872_BF_IETDMER = 0x4a00, /*!< Enable tdm error */ +TFA9872_BF_IECLPR = 0x4a20, /*!< Enable clip */ +TFA9872_BF_IELP0 = 0x4a40, /*!< Enable low power mode0 */ +TFA9872_BF_IELP1 = 0x4a50, /*!< Enable low power mode1 */ +TFA9872_BF_IELA = 0x4a60, /*!< Enable low noise detection */ +TFA9872_BF_IEVDDPH = 0x4a70, /*!< Enable VDDP greater tehn VBAT */ +TFA9872_BF_IPOVDDS = 0x4c00, /*!< Polarity por */ +TFA9872_BF_IPOPLLS = 0x4c10, /*!< Polarity pll lock */ +TFA9872_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ +TFA9872_BF_IPOOVDS = 0x4c30, /*!< Polarity OVP alarm */ +TFA9872_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ +TFA9872_BF_IPOCLKS = 0x4c50, /*!< Polarity clocks stable */ +TFA9872_BF_IPOMTPB = 0x4c60, /*!< Polarity mtp busy */ +TFA9872_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ +TFA9872_BF_IPOSWS = 0x4ca0, /*!< Polarity amplifier engage */ +TFA9872_BF_IPOAMPS = 0x4cc0, /*!< Polarity enbl amp */ +TFA9872_BF_IPOAREFS = 0x4cd0, /*!< Polarity ref enable */ +TFA9872_BF_IPOADCCR = 0x4ce0, /*!< Polarity Control ADC */ +TFA9872_BF_IPOBSTCU = 0x4d00, /*!< Polarity DCDC current limiting */ +TFA9872_BF_IPOBSTHI = 0x4d10, /*!< Polarity DCDC active */ +TFA9872_BF_IPOBSTOC = 0x4d20, /*!< Polarity DCDC OCP */ +TFA9872_BF_IPOBSTPC = 0x4d30, /*!< Polarity bst peakcur */ +TFA9872_BF_IPOBSTVC = 0x4d40, /*!< Polarity DCDC level 1x */ +TFA9872_BF_IPOBST86 = 0x4d50, /*!< Polarity DCDC level 1.14x */ +TFA9872_BF_IPOBST93 = 0x4d60, /*!< Polarity DCDC level 1.07x */ +TFA9872_BF_IPOOCPR = 0x4d90, /*!< Polarity ocp alarm */ +TFA9872_BF_IPOMWSRC = 0x4da0, /*!< Polarity waits HW I2C settings */ +TFA9872_BF_IPOMWSMU = 0x4dc0, /*!< Polarity man audio mute sequence */ +TFA9872_BF_IPCLKOOR = 0x4df0, /*!< Polarity flag_clk_out_of_range */ +TFA9872_BF_IPOTDMER = 0x4e00, /*!< Polarity tdm error */ +TFA9872_BF_IPOCLPR = 0x4e20, /*!< Polarity clip right */ +TFA9872_BF_IPOLP0 = 0x4e40, /*!< Polarity low power mode0 */ +TFA9872_BF_IPOLP1 = 0x4e50, /*!< Polarity low power mode1 */ +TFA9872_BF_IPOLA = 0x4e60, /*!< Polarity low noise mode */ +TFA9872_BF_IPOVDDPH = 0x4e70, /*!< Polarity VDDP greater than VBAT */ +TFA9872_BF_BSSCR = 0x5001, /*!< Battery Safeguard attack time */ +TFA9872_BF_BSST = 0x5023, /*!< Battery Safeguard threshold voltage level */ +TFA9872_BF_BSSRL = 0x5061, /*!< Battery Safeguard maximum reduction */ +TFA9872_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ +TFA9872_BF_BSSBY = 0x50f0, /*!< Bypass battery safeguard */ +TFA9872_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ +TFA9872_BF_INTSMUTE = 0x5110, /*!< Soft mute HW */ +TFA9872_BF_HPFBYP = 0x5150, /*!< Bypass HPF */ +TFA9872_BF_DPSA = 0x5170, /*!< Enable DPSA */ +TFA9872_BF_CLIPCTRL = 0x5222, /*!< Clip control setting */ +TFA9872_BF_AMPGAIN = 0x5257, /*!< Amplifier gain */ +TFA9872_BF_SLOPEE = 0x52d0, /*!< Enables slope control */ +TFA9872_BF_SLOPESET = 0x52e0, /*!< Slope speed setting (bin. coded) */ +TFA9872_BF_PGAGAIN = 0x6081, /*!< PGA gain selection */ +TFA9872_BF_PGALPE = 0x60b0, /*!< Lowpass enable */ +TFA9872_BF_LPM0BYP = 0x6110, /*!< bypass low power idle mode */ +TFA9872_BF_TDMDCG = 0x6123, /*!< Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE) */ +TFA9872_BF_TDMSPKG = 0x6163, /*!< Total gain depending on INPLEV setting (channel 0) */ +TFA9872_BF_STIDLEEN = 0x61b0, /*!< enable idle feature for channel 1 */ +TFA9872_BF_LNMODE = 0x62e1, /*!< ctrl select mode */ +TFA9872_BF_LPM1MODE = 0x64e1, /*!< low power mode control */ +TFA9872_BF_LPM1DIS = 0x65c0, /*!< low power mode1 detector control */ +TFA9872_BF_TDMSRCMAP = 0x6801, /*!< tdm source mapping */ +TFA9872_BF_TDMSRCAS = 0x6821, /*!< Sensed value A */ +TFA9872_BF_TDMSRCBS = 0x6841, /*!< Sensed value B */ +TFA9872_BF_ANCSEL = 0x6881, /*!< anc input */ +TFA9872_BF_ANC1C = 0x68a0, /*!< ANC one s complement */ +TFA9872_BF_SAMMODE = 0x6901, /*!< sam enable */ +TFA9872_BF_SAMSEL = 0x6920, /*!< sam source */ +TFA9872_BF_PDMOSELH = 0x6931, /*!< pdm out value when pdm_clk is higth */ +TFA9872_BF_PDMOSELL = 0x6951, /*!< pdm out value when pdm_clk is low */ +TFA9872_BF_SAMOSEL = 0x6970, /*!< ram output on mode sam and audio */ +TFA9872_BF_LP0 = 0x6e00, /*!< low power mode 0 detection */ +TFA9872_BF_LP1 = 0x6e10, /*!< low power mode 1 detection */ +TFA9872_BF_LA = 0x6e20, /*!< low amplitude detection */ +TFA9872_BF_VDDPH = 0x6e30, /*!< vddp greater than vbat */ +TFA9872_BF_DELCURCOMP = 0x6f02, /*!< delay to allign compensation signal with current sense signal */ +TFA9872_BF_SIGCURCOMP = 0x6f40, /*!< polarity of compensation for current sense */ +TFA9872_BF_ENCURCOMP = 0x6f50, /*!< enable current sense compensation */ +TFA9872_BF_SELCLPPWM = 0x6f60, /*!< Select pwm clip flag */ +TFA9872_BF_LVLCLPPWM = 0x6f72, /*!< set the amount of pwm pulse that may be skipped before clip-flag is triggered */ +TFA9872_BF_DCVOS = 0x7002, /*!< Second boost voltage level */ +TFA9872_BF_DCMCC = 0x7033, /*!< Max coil current */ +TFA9872_BF_DCCV = 0x7071, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ +TFA9872_BF_DCIE = 0x7090, /*!< Adaptive boost mode */ +TFA9872_BF_DCSR = 0x70a0, /*!< Soft ramp up/down */ +TFA9872_BF_DCDIS = 0x70e0, /*!< DCDC on/off */ +TFA9872_BF_DCPWM = 0x70f0, /*!< DCDC PWM only mode */ +TFA9872_BF_DCVOF = 0x7402, /*!< 1st boost voltage level */ +TFA9872_BF_DCTRACK = 0x7430, /*!< Boost algorithm selection, effective only when boost_intelligent is set to 1 */ +TFA9872_BF_DCTRIP = 0x7444, /*!< 1st Adaptive boost trip levels, effective only when DCIE is set to 1 */ +TFA9872_BF_DCHOLD = 0x7494, /*!< Hold time for DCDC booster, effective only when boost_intelligent is set to 1 */ +TFA9872_BF_DCTRIP2 = 0x7534, /*!< 2nd Adaptive boost trip levels, effective only when DCIE is set to 1 */ +TFA9872_BF_DCTRIPT = 0x7584, /*!< Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ +TFA9872_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ +TFA9872_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ +TFA9872_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ +TFA9872_BF_CMTPI = 0xa350, /*!< Start copying all the data from mtp to I2C mtp registers */ +TFA9872_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp */ +TFA9872_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ +TFA9872_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ +TFA9872_BF_EXTTS = 0xb108, /*!< External temperature (C) */ +TFA9872_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ +TFA9872_BF_SWPROFIL = 0xee0f, /*!< Software profile data */ +TFA9872_BF_SWVSTEP = 0xef0f, /*!< Software vstep information */ +TFA9872_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ +TFA9872_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ +TFA9872_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ +TFA9872_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ +TFA9872_BF_USERDEF = 0xf042, /*!< Calibration delta current limit DCDC */ +TFA9872_BF_CUSTINFO = 0xf078, /*!< Reserved space for allowing customer to store speaker information */ +TFA9872_BF_R25C = 0xf50f, /*!< Ron resistance of speaker coil */ +} nxpTfa9872BfEnumList_t; +#define TFA9872_NAMETABLE static tfaBfName_t Tfa9872DatasheetNames[] = {\ +{ 0x0, "PWDN"}, /* Powerdown selection , */\ +{ 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ +{ 0x30, "AMPE"}, /* Activate Amplifier , */\ +{ 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ +{ 0x71, "INTP"}, /* Interrupt config , */\ +{ 0xb0, "BYPOCP"}, /* Bypass OCP , */\ +{ 0xc0, "TSTOCP"}, /* OCP testing control , */\ +{ 0x120, "MANSCONF"}, /* I2C configured , */\ +{ 0x140, "MANAOOSC"}, /* Internal osc off at PWDN , */\ +{ 0x1d0, "MUTETO"}, /* Time out SB mute sequence , */\ +{ 0x1e0, "RCVNS"}, /* Noise shaper selection , */\ +{ 0x203, "AUDFS"}, /* Sample rate (fs) , */\ +{ 0x240, "INPLEV"}, /* TDM output attenuation , */\ +{ 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ +{ 0x2b0, "BYPHVBF"}, /* Bypass HVBAT filter , */\ +{ 0x30f, "REV"}, /* Revision info , */\ +{ 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ +{ 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ +{ 0x510, "SSE"}, /* Enable speaker path , */\ +{ 0x530, "VSE"}, /* Voltage sense , */\ +{ 0x550, "CSE"}, /* Current sense , */\ +{ 0x560, "SSPDME"}, /* Sub-system PDM , */\ +{ 0x580, "PGAE"}, /* Enable PGA chop clock , */\ +{ 0x590, "SSTDME"}, /* Sub-system TDM , */\ +{ 0x5a0, "SSPBSTE"}, /* Sub-system boost , */\ +{ 0x5b0, "SSADCE"}, /* Sub-system ADC , */\ +{ 0x5c0, "SSFAIME"}, /* Sub-system FAIM , */\ +{ 0xd18, "STGAIN"}, /* Side tone gain , */\ +{ 0xda0, "STSMUTE"}, /* Side tone soft mute , */\ +{ 0xdb0, "ST1C"}, /* side tone one s complement , */\ +{ 0x1000, "VDDS"}, /* POR , */\ +{ 0x1010, "PLLS"}, /* PLL lock , */\ +{ 0x1020, "OTDS"}, /* OTP alarm , */\ +{ 0x1030, "OVDS"}, /* OVP alarm , */\ +{ 0x1040, "UVDS"}, /* UVP alarm , */\ +{ 0x1050, "CLKS"}, /* Clocks stable , */\ +{ 0x1060, "MTPB"}, /* MTP busy , */\ +{ 0x1070, "NOCLK"}, /* Lost clock , */\ +{ 0x10a0, "SWS"}, /* Amplifier engage , */\ +{ 0x10c0, "AMPS"}, /* Amplifier enable , */\ +{ 0x10d0, "AREFS"}, /* References enable , */\ +{ 0x10e0, "ADCCR"}, /* Control ADC , */\ +{ 0x1100, "DCIL"}, /* DCDC current limiting , */\ +{ 0x1110, "DCDCA"}, /* DCDC active , */\ +{ 0x1120, "DCOCPOK"}, /* DCDC OCP nmos , */\ +{ 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ +{ 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ +{ 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ +{ 0x1170, "STMUTEB"}, /* side tone (un)mute busy , */\ +{ 0x1180, "STMUTE"}, /* side tone mute state , */\ +{ 0x1190, "TDMLUTER"}, /* TDM LUT error , */\ +{ 0x11a2, "TDMSTAT"}, /* TDM status bits , */\ +{ 0x11d0, "TDMERR"}, /* TDM error , */\ +{ 0x1300, "OCPOAP"}, /* OCPOK pmos A , */\ +{ 0x1310, "OCPOAN"}, /* OCPOK nmos A , */\ +{ 0x1320, "OCPOBP"}, /* OCPOK pmos B , */\ +{ 0x1330, "OCPOBN"}, /* OCPOK nmos B , */\ +{ 0x1340, "CLIPAH"}, /* Clipping A to Vddp , */\ +{ 0x1350, "CLIPAL"}, /* Clipping A to gnd , */\ +{ 0x1360, "CLIPBH"}, /* Clipping B to Vddp , */\ +{ 0x1370, "CLIPBL"}, /* Clipping B to gnd , */\ +{ 0x1380, "OCDS"}, /* OCP amplifier , */\ +{ 0x1390, "CLIPS"}, /* Amplifier clipping , */\ +{ 0x13a0, "OCPOKMC"}, /* OCPOK MICVDD , */\ +{ 0x13b0, "MANALARM"}, /* Alarm state , */\ +{ 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ +{ 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ +{ 0x13f0, "MANOPER"}, /* Operating state , */\ +{ 0x1420, "CLKOOR"}, /* External clock status , */\ +{ 0x1433, "MANSTATE"}, /* Device manager status , */\ +{ 0x1471, "DCMODE"}, /* DCDC mode status bits , */\ +{ 0x1509, "BATS"}, /* Battery voltage (V) , */\ +{ 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ +{ 0x1709, "VDDPS"}, /* IC VDDP voltage ( 1023*VDDP/9.5 V) , */\ +{ 0x2040, "TDME"}, /* Enable interface , */\ +{ 0x2050, "TDMMODE"}, /* Slave/master , */\ +{ 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ +{ 0x2073, "TDMFSLN"}, /* FS length (master mode only) , */\ +{ 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ +{ 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ +{ 0x2103, "TDMSLOTS"}, /* N-slots in Frame , */\ +{ 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ +{ 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ +{ 0x21e0, "TDMDEL"}, /* data delay to FS , */\ +{ 0x21f0, "TDMADJ"}, /* data adjustment , */\ +{ 0x2201, "TDMOOMP"}, /* Received audio compression , */\ +{ 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ +{ 0x2271, "TDMTXDFO"}, /* Format unused bits , */\ +{ 0x2291, "TDMTXUS0"}, /* Format unused slots DATAO , */\ +{ 0x2300, "TDMSPKE"}, /* Control audio tdm channel in 0 (spkr + dcdc) , */\ +{ 0x2310, "TDMDCE"}, /* Control audio tdm channel in 1 (dcdc) , */\ +{ 0x2330, "TDMCSE"}, /* current sense vbat temperature and vddp feedback , */\ +{ 0x2340, "TDMVSE"}, /* Voltage sense vbat temperature and vddp feedback , */\ +{ 0x2603, "TDMSPKS"}, /* tdm slot for sink 0 (speaker + dcdc) , */\ +{ 0x2643, "TDMDCS"}, /* tdm slot for sink 1 (dcdc) , */\ +{ 0x26c3, "TDMCSS"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ +{ 0x2703, "TDMVSS"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ +{ 0x3111, "PDMSTSEL"}, /* Side tone input , */\ +{ 0x4000, "ISTVDDS"}, /* Status POR , */\ +{ 0x4010, "ISTPLLS"}, /* Status PLL lock , */\ +{ 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ +{ 0x4030, "ISTOVDS"}, /* Status OVP alarm , */\ +{ 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ +{ 0x4050, "ISTCLKS"}, /* Status clocks stable , */\ +{ 0x4060, "ISTMTPB"}, /* Status MTP busy , */\ +{ 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ +{ 0x40a0, "ISTSWS"}, /* Status amplifier engage , */\ +{ 0x40c0, "ISTAMPS"}, /* Status amplifier enable , */\ +{ 0x40d0, "ISTAREFS"}, /* Status Ref enable , */\ +{ 0x40e0, "ISTADCCR"}, /* Status Control ADC , */\ +{ 0x4100, "ISTBSTCU"}, /* Status DCDC current limiting , */\ +{ 0x4110, "ISTBSTHI"}, /* Status DCDC active , */\ +{ 0x4120, "ISTBSTOC"}, /* Status DCDC OCP , */\ +{ 0x4130, "ISTBSTPKCUR"}, /* Status bst peakcur , */\ +{ 0x4140, "ISTBSTVC"}, /* Status DCDC level 1x , */\ +{ 0x4150, "ISTBST86"}, /* Status DCDC level 1.14x , */\ +{ 0x4160, "ISTBST93"}, /* Status DCDC level 1.07x , */\ +{ 0x4190, "ISTOCPR"}, /* Status ocp alarm , */\ +{ 0x41a0, "ISTMWSRC"}, /* Status Waits HW I2C settings , */\ +{ 0x41c0, "ISTMWSMU"}, /* Status Audio mute sequence , */\ +{ 0x41f0, "ISTCLKOOR"}, /* Status flag_clk_out_of_range , */\ +{ 0x4200, "ISTTDMER"}, /* Status tdm error , */\ +{ 0x4220, "ISTCLPR"}, /* Status clip , */\ +{ 0x4240, "ISTLP0"}, /* Status low power mode0 , */\ +{ 0x4250, "ISTLP1"}, /* Status low power mode1 , */\ +{ 0x4260, "ISTLA"}, /* Status low noise detection , */\ +{ 0x4270, "ISTVDDPH"}, /* Status VDDP greater than VBAT , */\ +{ 0x4400, "ICLVDDS"}, /* Clear POR , */\ +{ 0x4410, "ICLPLLS"}, /* Clear PLL lock , */\ +{ 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ +{ 0x4430, "ICLOVDS"}, /* Clear OVP alarm , */\ +{ 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ +{ 0x4450, "ICLCLKS"}, /* Clear clocks stable , */\ +{ 0x4460, "ICLMTPB"}, /* Clear mtp busy , */\ +{ 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ +{ 0x44a0, "ICLSWS"}, /* Clear amplifier engage , */\ +{ 0x44c0, "ICLAMPS"}, /* Clear enbl amp , */\ +{ 0x44d0, "ICLAREFS"}, /* Clear ref enable , */\ +{ 0x44e0, "ICLADCCR"}, /* Clear control ADC , */\ +{ 0x4500, "ICLBSTCU"}, /* Clear DCDC current limiting , */\ +{ 0x4510, "ICLBSTHI"}, /* Clear DCDC active , */\ +{ 0x4520, "ICLBSTOC"}, /* Clear DCDC OCP , */\ +{ 0x4530, "ICLBSTPC"}, /* Clear bst peakcur , */\ +{ 0x4540, "ICLBSTVC"}, /* Clear DCDC level 1x , */\ +{ 0x4550, "ICLBST86"}, /* Clear DCDC level 1.14x , */\ +{ 0x4560, "ICLBST93"}, /* Clear DCDC level 1.07x , */\ +{ 0x4590, "ICLOCPR"}, /* Clear ocp alarm , */\ +{ 0x45a0, "ICLMWSRC"}, /* Clear wait HW I2C settings , */\ +{ 0x45c0, "ICLMWSMU"}, /* Clear audio mute sequence , */\ +{ 0x45f0, "ICLCLKOOR"}, /* Clear flag_clk_out_of_range , */\ +{ 0x4600, "ICLTDMER"}, /* Clear tdm error , */\ +{ 0x4620, "ICLCLPR"}, /* Clear clip , */\ +{ 0x4640, "ICLLP0"}, /* Clear low power mode0 , */\ +{ 0x4650, "ICLLP1"}, /* Clear low power mode1 , */\ +{ 0x4660, "ICLLA"}, /* Clear low noise detection , */\ +{ 0x4670, "ICLVDDPH"}, /* Clear VDDP greater then VBAT , */\ +{ 0x4800, "IEVDDS"}, /* Enable por , */\ +{ 0x4810, "IEPLLS"}, /* Enable pll lock , */\ +{ 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ +{ 0x4830, "IEOVDS"}, /* Enable OVP alarm , */\ +{ 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ +{ 0x4850, "IECLKS"}, /* Enable clocks stable , */\ +{ 0x4860, "IEMTPB"}, /* Enable mtp busy , */\ +{ 0x4870, "IENOCLK"}, /* Enable lost clk , */\ +{ 0x48a0, "IESWS"}, /* Enable amplifier engage , */\ +{ 0x48c0, "IEAMPS"}, /* Enable enbl amp , */\ +{ 0x48d0, "IEAREFS"}, /* Enable ref enable , */\ +{ 0x48e0, "IEADCCR"}, /* Enable Control ADC , */\ +{ 0x4900, "IEBSTCU"}, /* Enable DCDC current limiting , */\ +{ 0x4910, "IEBSTHI"}, /* Enable DCDC active , */\ +{ 0x4920, "IEBSTOC"}, /* Enable DCDC OCP , */\ +{ 0x4930, "IEBSTPC"}, /* Enable bst peakcur , */\ +{ 0x4940, "IEBSTVC"}, /* Enable DCDC level 1x , */\ +{ 0x4950, "IEBST86"}, /* Enable DCDC level 1.14x , */\ +{ 0x4960, "IEBST93"}, /* Enable DCDC level 1.07x , */\ +{ 0x4990, "IEOCPR"}, /* Enable ocp alarm , */\ +{ 0x49a0, "IEMWSRC"}, /* Enable waits HW I2C settings , */\ +{ 0x49c0, "IEMWSMU"}, /* Enable man Audio mute sequence , */\ +{ 0x49f0, "IECLKOOR"}, /* Enable flag_clk_out_of_range , */\ +{ 0x4a00, "IETDMER"}, /* Enable tdm error , */\ +{ 0x4a20, "IECLPR"}, /* Enable clip , */\ +{ 0x4a40, "IELP0"}, /* Enable low power mode0 , */\ +{ 0x4a50, "IELP1"}, /* Enable low power mode1 , */\ +{ 0x4a60, "IELA"}, /* Enable low noise detection , */\ +{ 0x4a70, "IEVDDPH"}, /* Enable VDDP greater tehn VBAT , */\ +{ 0x4c00, "IPOVDDS"}, /* Polarity por , */\ +{ 0x4c10, "IPOPLLS"}, /* Polarity pll lock , */\ +{ 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ +{ 0x4c30, "IPOOVDS"}, /* Polarity OVP alarm , */\ +{ 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ +{ 0x4c50, "IPOCLKS"}, /* Polarity clocks stable , */\ +{ 0x4c60, "IPOMTPB"}, /* Polarity mtp busy , */\ +{ 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ +{ 0x4ca0, "IPOSWS"}, /* Polarity amplifier engage , */\ +{ 0x4cc0, "IPOAMPS"}, /* Polarity enbl amp , */\ +{ 0x4cd0, "IPOAREFS"}, /* Polarity ref enable , */\ +{ 0x4ce0, "IPOADCCR"}, /* Polarity Control ADC , */\ +{ 0x4d00, "IPOBSTCU"}, /* Polarity DCDC current limiting , */\ +{ 0x4d10, "IPOBSTHI"}, /* Polarity DCDC active , */\ +{ 0x4d20, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ +{ 0x4d30, "IPOBSTPC"}, /* Polarity bst peakcur , */\ +{ 0x4d40, "IPOBSTVC"}, /* Polarity DCDC level 1x , */\ +{ 0x4d50, "IPOBST86"}, /* Polarity DCDC level 1.14x , */\ +{ 0x4d60, "IPOBST93"}, /* Polarity DCDC level 1.07x , */\ +{ 0x4d90, "IPOOCPR"}, /* Polarity ocp alarm , */\ +{ 0x4da0, "IPOMWSRC"}, /* Polarity waits HW I2C settings , */\ +{ 0x4dc0, "IPOMWSMU"}, /* Polarity man audio mute sequence , */\ +{ 0x4df0, "IPCLKOOR"}, /* Polarity flag_clk_out_of_range , */\ +{ 0x4e00, "IPOTDMER"}, /* Polarity tdm error , */\ +{ 0x4e20, "IPOCLPR"}, /* Polarity clip right , */\ +{ 0x4e40, "IPOLP0"}, /* Polarity low power mode0 , */\ +{ 0x4e50, "IPOLP1"}, /* Polarity low power mode1 , */\ +{ 0x4e60, "IPOLA"}, /* Polarity low noise mode , */\ +{ 0x4e70, "IPOVDDPH"}, /* Polarity VDDP greater than VBAT , */\ +{ 0x5001, "BSSCR"}, /* Battery Safeguard attack time , */\ +{ 0x5023, "BSST"}, /* Battery Safeguard threshold voltage level , */\ +{ 0x5061, "BSSRL"}, /* Battery Safeguard maximum reduction , */\ +{ 0x50e0, "BSSR"}, /* Battery voltage read out , */\ +{ 0x50f0, "BSSBY"}, /* Bypass battery safeguard , */\ +{ 0x5100, "BSSS"}, /* Vbat prot steepness , */\ +{ 0x5110, "INTSMUTE"}, /* Soft mute HW , */\ +{ 0x5150, "HPFBYP"}, /* Bypass HPF , */\ +{ 0x5170, "DPSA"}, /* Enable DPSA , */\ +{ 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ +{ 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ +{ 0x52d0, "SLOPEE"}, /* Enables slope control , */\ +{ 0x52e0, "SLOPESET"}, /* Slope speed setting (bin. coded) , */\ +{ 0x6081, "PGAGAIN"}, /* PGA gain selection , */\ +{ 0x60b0, "PGALPE"}, /* Lowpass enable , */\ +{ 0x6110, "LPM0BYP"}, /* bypass low power idle mode , */\ +{ 0x6123, "TDMDCG"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ +{ 0x6163, "TDMSPKG"}, /* Total gain depending on INPLEV setting (channel 0), */\ +{ 0x61b0, "STIDLEEN"}, /* enable idle feature for channel 1 , */\ +{ 0x62e1, "LNMODE"}, /* ctrl select mode , */\ +{ 0x64e1, "LPM1MODE"}, /* low power mode control , */\ +{ 0x65c0, "LPM1DIS"}, /* low power mode1 detector control , */\ +{ 0x6801, "TDMSRCMAP"}, /* tdm source mapping , */\ +{ 0x6821, "TDMSRCAS"}, /* Sensed value A , */\ +{ 0x6841, "TDMSRCBS"}, /* Sensed value B , */\ +{ 0x6881, "ANCSEL"}, /* anc input , */\ +{ 0x68a0, "ANC1C"}, /* ANC one s complement , */\ +{ 0x6901, "SAMMODE"}, /* sam enable , */\ +{ 0x6920, "SAMSEL"}, /* sam source , */\ +{ 0x6931, "PDMOSELH"}, /* pdm out value when pdm_clk is higth , */\ +{ 0x6951, "PDMOSELL"}, /* pdm out value when pdm_clk is low , */\ +{ 0x6970, "SAMOSEL"}, /* ram output on mode sam and audio , */\ +{ 0x6e00, "LP0"}, /* low power mode 0 detection , */\ +{ 0x6e10, "LP1"}, /* low power mode 1 detection , */\ +{ 0x6e20, "LA"}, /* low amplitude detection , */\ +{ 0x6e30, "VDDPH"}, /* vddp greater than vbat , */\ +{ 0x6f02, "DELCURCOMP"}, /* delay to allign compensation signal with current sense signal, */\ +{ 0x6f40, "SIGCURCOMP"}, /* polarity of compensation for current sense , */\ +{ 0x6f50, "ENCURCOMP"}, /* enable current sense compensation , */\ +{ 0x6f60, "SELCLPPWM"}, /* Select pwm clip flag , */\ +{ 0x6f72, "LVLCLPPWM"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ +{ 0x7002, "DCVOS"}, /* Second boost voltage level , */\ +{ 0x7033, "DCMCC"}, /* Max coil current , */\ +{ 0x7071, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ +{ 0x7090, "DCIE"}, /* Adaptive boost mode , */\ +{ 0x70a0, "DCSR"}, /* Soft ramp up/down , */\ +{ 0x70e0, "DCDIS"}, /* DCDC on/off , */\ +{ 0x70f0, "DCPWM"}, /* DCDC PWM only mode , */\ +{ 0x7402, "DCVOF"}, /* 1st boost voltage level , */\ +{ 0x7430, "DCTRACK"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ +{ 0x7444, "DCTRIP"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7494, "DCHOLD"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ +{ 0x7534, "DCTRIP2"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7584, "DCTRIPT"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ +{ 0xa107, "MTPK"}, /* MTP KEY2 register , */\ +{ 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ +{ 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ +{ 0xa350, "CMTPI"}, /* Start copying all the data from mtp to I2C mtp registers, */\ +{ 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ +{ 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ +{ 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ +{ 0xb108, "EXTTS"}, /* External temperature (C) , */\ +{ 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ +{ 0xee0f, "SWPROFIL"}, /* Software profile data , */\ +{ 0xef0f, "SWVSTEP"}, /* Software vstep information , */\ +{ 0xf000, "MTPOTC"}, /* Calibration schedule , */\ +{ 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ +{ 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ +{ 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ +{ 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ +{ 0xf078, "CUSTINFO"}, /* Reserved space for allowing customer to store speaker information, */\ +{ 0xf50f, "R25C"}, /* Ron resistance of speaker coil , */\ +{ 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9872_BITNAMETABLE static tfaBfName_t Tfa9872BitNames[] = {\ +{ 0x0, "powerdown"}, /* Powerdown selection , */\ +{ 0x10, "reset"}, /* I2C Reset - Auto clear , */\ +{ 0x30, "enbl_amplifier"}, /* Activate Amplifier , */\ +{ 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ +{ 0x71, "int_pad_io"}, /* Interrupt config , */\ +{ 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ +{ 0xc0, "test_ocp"}, /* OCP testing control , */\ +{ 0x120, "src_set_configured"}, /* I2C configured , */\ +{ 0x140, "enbl_osc1m_auto_off"}, /* Internal osc off at PWDN , */\ +{ 0x1d0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ +{ 0x203, "audio_fs"}, /* Sample rate (fs) , */\ +{ 0x240, "input_level"}, /* TDM output attenuation , */\ +{ 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ +{ 0x2b0, "bypass_hvbat_filter"}, /* Bypass HVBAT filter , */\ +{ 0x2d0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ +{ 0x30f, "device_rev"}, /* Revision info , */\ +{ 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ +{ 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ +{ 0x510, "enbl_spkr_ss"}, /* Enable speaker path , */\ +{ 0x530, "enbl_volsense"}, /* Voltage sense , */\ +{ 0x550, "enbl_cursense"}, /* Current sense , */\ +{ 0x560, "enbl_pdm_ss"}, /* Sub-system PDM , */\ +{ 0x580, "enbl_pga_chop"}, /* Enable PGA chop clock , */\ +{ 0x590, "enbl_tdm_ss"}, /* Sub-system TDM , */\ +{ 0x5a0, "enbl_bst_ss"}, /* Sub-system boost , */\ +{ 0x5b0, "enbl_adc_ss"}, /* Sub-system ADC , */\ +{ 0x5c0, "enbl_faim_ss"}, /* Sub-system FAIM , */\ +{ 0xd18, "side_tone_gain"}, /* Side tone gain , */\ +{ 0xda0, "mute_side_tone"}, /* Side tone soft mute , */\ +{ 0xdb0, "side_tone_1scomplement"}, /* side tone one s complement , */\ +{ 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ +{ 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ +{ 0x1000, "flag_por"}, /* POR , */\ +{ 0x1010, "flag_pll_lock"}, /* PLL lock , */\ +{ 0x1020, "flag_otpok"}, /* OTP alarm , */\ +{ 0x1030, "flag_ovpok"}, /* OVP alarm , */\ +{ 0x1040, "flag_uvpok"}, /* UVP alarm , */\ +{ 0x1050, "flag_clocks_stable"}, /* Clocks stable , */\ +{ 0x1060, "flag_mtp_busy"}, /* MTP busy , */\ +{ 0x1070, "flag_lost_clk"}, /* Lost clock , */\ +{ 0x10a0, "flag_engage"}, /* Amplifier engage , */\ +{ 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ +{ 0x10d0, "flag_enbl_ref"}, /* References enable , */\ +{ 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ +{ 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ +{ 0x1110, "flag_bst_hiz"}, /* DCDC active , */\ +{ 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos , */\ +{ 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ +{ 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ +{ 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ +{ 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ +{ 0x1170, "flag_soft_mute_busy"}, /* side tone (un)mute busy , */\ +{ 0x1180, "flag_soft_mute_state"}, /* side tone mute state , */\ +{ 0x1190, "flag_tdm_lut_error"}, /* TDM LUT error , */\ +{ 0x11a2, "flag_tdm_status"}, /* TDM status bits , */\ +{ 0x11d0, "flag_tdm_error"}, /* TDM error , */\ +{ 0x1300, "flag_ocpokap"}, /* OCPOK pmos A , */\ +{ 0x1310, "flag_ocpokan"}, /* OCPOK nmos A , */\ +{ 0x1320, "flag_ocpokbp"}, /* OCPOK pmos B , */\ +{ 0x1330, "flag_ocpokbn"}, /* OCPOK nmos B , */\ +{ 0x1340, "flag_clipa_high"}, /* Clipping A to Vddp , */\ +{ 0x1350, "flag_clipa_low"}, /* Clipping A to gnd , */\ +{ 0x1360, "flag_clipb_high"}, /* Clipping B to Vddp , */\ +{ 0x1370, "flag_clipb_low"}, /* Clipping B to gnd , */\ +{ 0x1380, "flag_ocp_alarm"}, /* OCP amplifier , */\ +{ 0x1390, "flag_clip"}, /* Amplifier clipping , */\ +{ 0x13b0, "flag_man_alarm_state"}, /* Alarm state , */\ +{ 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ +{ 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ +{ 0x13f0, "flag_man_operating_state"}, /* Operating state , */\ +{ 0x1420, "flag_clk_out_of_range"}, /* External clock status , */\ +{ 0x1433, "man_state"}, /* Device manager status , */\ +{ 0x1471, "status_bst_mode"}, /* DCDC mode status bits , */\ +{ 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ +{ 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ +{ 0x1709, "vddp_adc"}, /* IC VDDP voltage ( 1023*VDDP/9.5 V) , */\ +{ 0x2040, "tdm_enable"}, /* Enable interface , */\ +{ 0x2050, "tdm_mode"}, /* Slave/master , */\ +{ 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ +{ 0x2073, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ +{ 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ +{ 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ +{ 0x2103, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ +{ 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ +{ 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ +{ 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ +{ 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ +{ 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ +{ 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ +{ 0x2271, "tdm_txdata_format"}, /* Format unused bits , */\ +{ 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots DATAO , */\ +{ 0x2300, "tdm_sink0_enable"}, /* Control audio tdm channel in 0 (spkr + dcdc) , */\ +{ 0x2310, "tdm_sink1_enable"}, /* Control audio tdm channel in 1 (dcdc) , */\ +{ 0x2330, "tdm_source0_enable"}, /* current sense vbat temperature and vddp feedback , */\ +{ 0x2340, "tdm_source1_enable"}, /* Voltage sense vbat temperature and vddp feedback , */\ +{ 0x2603, "tdm_sink0_slot"}, /* tdm slot for sink 0 (speaker + dcdc) , */\ +{ 0x2643, "tdm_sink1_slot"}, /* tdm slot for sink 1 (dcdc) , */\ +{ 0x26c3, "tdm_source0_slot"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ +{ 0x2703, "tdm_source1_slot"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ +{ 0x3111, "pdm_side_tone_sel"}, /* Side tone input , */\ +{ 0x3201, "pdm_nbck"}, /* PDM BCK/Fs ratio , */\ +{ 0x4000, "int_out_flag_por"}, /* Status POR , */\ +{ 0x4010, "int_out_flag_pll_lock"}, /* Status PLL lock , */\ +{ 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ +{ 0x4030, "int_out_flag_ovpok"}, /* Status OVP alarm , */\ +{ 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ +{ 0x4050, "int_out_flag_clocks_stable"}, /* Status clocks stable , */\ +{ 0x4060, "int_out_flag_mtp_busy"}, /* Status MTP busy , */\ +{ 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ +{ 0x40a0, "int_out_flag_engage"}, /* Status amplifier engage , */\ +{ 0x40c0, "int_out_flag_enbl_amp"}, /* Status amplifier enable , */\ +{ 0x40d0, "int_out_flag_enbl_ref"}, /* Status Ref enable , */\ +{ 0x40e0, "int_out_flag_adc10_ready"}, /* Status Control ADC , */\ +{ 0x4100, "int_out_flag_bst_bstcur"}, /* Status DCDC current limiting , */\ +{ 0x4110, "int_out_flag_bst_hiz"}, /* Status DCDC active , */\ +{ 0x4120, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ +{ 0x4130, "int_out_flag_bst_peakcur"}, /* Status bst peakcur , */\ +{ 0x4140, "int_out_flag_bst_voutcomp"}, /* Status DCDC level 1x , */\ +{ 0x4150, "int_out_flag_bst_voutcomp86"}, /* Status DCDC level 1.14x , */\ +{ 0x4160, "int_out_flag_bst_voutcomp93"}, /* Status DCDC level 1.07x , */\ +{ 0x4190, "int_out_flag_ocp_alarm"}, /* Status ocp alarm , */\ +{ 0x41a0, "int_out_flag_man_wait_src_settings"}, /* Status Waits HW I2C settings , */\ +{ 0x41c0, "int_out_flag_man_start_mute_audio"}, /* Status Audio mute sequence , */\ +{ 0x41f0, "int_out_flag_clk_out_of_range"}, /* Status flag_clk_out_of_range , */\ +{ 0x4200, "int_out_flag_tdm_error"}, /* Status tdm error , */\ +{ 0x4220, "int_out_flag_clip"}, /* Status clip , */\ +{ 0x4240, "int_out_flag_lp_detect_mode0"}, /* Status low power mode0 , */\ +{ 0x4250, "int_out_flag_lp_detect_mode1"}, /* Status low power mode1 , */\ +{ 0x4260, "int_out_flag_low_amplitude"}, /* Status low noise detection , */\ +{ 0x4270, "int_out_flag_vddp_gt_vbat"}, /* Status VDDP greater than VBAT , */\ +{ 0x4400, "int_in_flag_por"}, /* Clear POR , */\ +{ 0x4410, "int_in_flag_pll_lock"}, /* Clear PLL lock , */\ +{ 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ +{ 0x4430, "int_in_flag_ovpok"}, /* Clear OVP alarm , */\ +{ 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ +{ 0x4450, "int_in_flag_clocks_stable"}, /* Clear clocks stable , */\ +{ 0x4460, "int_in_flag_mtp_busy"}, /* Clear mtp busy , */\ +{ 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ +{ 0x44a0, "int_in_flag_engage"}, /* Clear amplifier engage , */\ +{ 0x44c0, "int_in_flag_enbl_amp"}, /* Clear enbl amp , */\ +{ 0x44d0, "int_in_flag_enbl_ref"}, /* Clear ref enable , */\ +{ 0x44e0, "int_in_flag_adc10_ready"}, /* Clear control ADC , */\ +{ 0x4500, "int_in_flag_bst_bstcur"}, /* Clear DCDC current limiting , */\ +{ 0x4510, "int_in_flag_bst_hiz"}, /* Clear DCDC active , */\ +{ 0x4520, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ +{ 0x4530, "int_in_flag_bst_peakcur"}, /* Clear bst peakcur , */\ +{ 0x4540, "int_in_flag_bst_voutcomp"}, /* Clear DCDC level 1x , */\ +{ 0x4550, "int_in_flag_bst_voutcomp86"}, /* Clear DCDC level 1.14x , */\ +{ 0x4560, "int_in_flag_bst_voutcomp93"}, /* Clear DCDC level 1.07x , */\ +{ 0x4590, "int_in_flag_ocp_alarm"}, /* Clear ocp alarm , */\ +{ 0x45a0, "int_in_flag_man_wait_src_settings"}, /* Clear wait HW I2C settings , */\ +{ 0x45c0, "int_in_flag_man_start_mute_audio"}, /* Clear audio mute sequence , */\ +{ 0x45f0, "int_in_flag_clk_out_of_range"}, /* Clear flag_clk_out_of_range , */\ +{ 0x4600, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ +{ 0x4620, "int_in_flag_clip"}, /* Clear clip , */\ +{ 0x4640, "int_in_flag_lp_detect_mode0"}, /* Clear low power mode0 , */\ +{ 0x4650, "int_in_flag_lp_detect_mode1"}, /* Clear low power mode1 , */\ +{ 0x4660, "int_in_flag_low_amplitude"}, /* Clear low noise detection , */\ +{ 0x4670, "int_in_flag_vddp_gt_vbat"}, /* Clear VDDP greater then VBAT , */\ +{ 0x4800, "int_enable_flag_por"}, /* Enable por , */\ +{ 0x4810, "int_enable_flag_pll_lock"}, /* Enable pll lock , */\ +{ 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ +{ 0x4830, "int_enable_flag_ovpok"}, /* Enable OVP alarm , */\ +{ 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ +{ 0x4850, "int_enable_flag_clocks_stable"}, /* Enable clocks stable , */\ +{ 0x4860, "int_enable_flag_mtp_busy"}, /* Enable mtp busy , */\ +{ 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ +{ 0x48a0, "int_enable_flag_engage"}, /* Enable amplifier engage , */\ +{ 0x48c0, "int_enable_flag_enbl_amp"}, /* Enable enbl amp , */\ +{ 0x48d0, "int_enable_flag_enbl_ref"}, /* Enable ref enable , */\ +{ 0x48e0, "int_enable_flag_adc10_ready"}, /* Enable Control ADC , */\ +{ 0x4900, "int_enable_flag_bst_bstcur"}, /* Enable DCDC current limiting , */\ +{ 0x4910, "int_enable_flag_bst_hiz"}, /* Enable DCDC active , */\ +{ 0x4920, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ +{ 0x4930, "int_enable_flag_bst_peakcur"}, /* Enable bst peakcur , */\ +{ 0x4940, "int_enable_flag_bst_voutcomp"}, /* Enable DCDC level 1x , */\ +{ 0x4950, "int_enable_flag_bst_voutcomp86"}, /* Enable DCDC level 1.14x , */\ +{ 0x4960, "int_enable_flag_bst_voutcomp93"}, /* Enable DCDC level 1.07x , */\ +{ 0x4990, "int_enable_flag_ocp_alarm"}, /* Enable ocp alarm , */\ +{ 0x49a0, "int_enable_flag_man_wait_src_settings"}, /* Enable waits HW I2C settings , */\ +{ 0x49c0, "int_enable_flag_man_start_mute_audio"}, /* Enable man Audio mute sequence , */\ +{ 0x49f0, "int_enable_flag_clk_out_of_range"}, /* Enable flag_clk_out_of_range , */\ +{ 0x4a00, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ +{ 0x4a20, "int_enable_flag_clip"}, /* Enable clip , */\ +{ 0x4a40, "int_enable_flag_lp_detect_mode0"}, /* Enable low power mode0 , */\ +{ 0x4a50, "int_enable_flag_lp_detect_mode1"}, /* Enable low power mode1 , */\ +{ 0x4a60, "int_enable_flag_low_amplitude"}, /* Enable low noise detection , */\ +{ 0x4a70, "int_enable_flag_vddp_gt_vbat"}, /* Enable VDDP greater tehn VBAT , */\ +{ 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ +{ 0x4c10, "int_polarity_flag_pll_lock"}, /* Polarity pll lock , */\ +{ 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ +{ 0x4c30, "int_polarity_flag_ovpok"}, /* Polarity OVP alarm , */\ +{ 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ +{ 0x4c50, "int_polarity_flag_clocks_stable"}, /* Polarity clocks stable , */\ +{ 0x4c60, "int_polarity_flag_mtp_busy"}, /* Polarity mtp busy , */\ +{ 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ +{ 0x4ca0, "int_polarity_flag_engage"}, /* Polarity amplifier engage , */\ +{ 0x4cc0, "int_polarity_flag_enbl_amp"}, /* Polarity enbl amp , */\ +{ 0x4cd0, "int_polarity_flag_enbl_ref"}, /* Polarity ref enable , */\ +{ 0x4ce0, "int_polarity_flag_adc10_ready"}, /* Polarity Control ADC , */\ +{ 0x4d00, "int_polarity_flag_bst_bstcur"}, /* Polarity DCDC current limiting , */\ +{ 0x4d10, "int_polarity_flag_bst_hiz"}, /* Polarity DCDC active , */\ +{ 0x4d20, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ +{ 0x4d30, "int_polarity_flag_bst_peakcur"}, /* Polarity bst peakcur , */\ +{ 0x4d40, "int_polarity_flag_bst_voutcomp"}, /* Polarity DCDC level 1x , */\ +{ 0x4d50, "int_polarity_flag_bst_voutcomp86"}, /* Polarity DCDC level 1.14x , */\ +{ 0x4d60, "int_polarity_flag_bst_voutcomp93"}, /* Polarity DCDC level 1.07x , */\ +{ 0x4d90, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ +{ 0x4da0, "int_polarity_flag_man_wait_src_settings"}, /* Polarity waits HW I2C settings , */\ +{ 0x4dc0, "int_polarity_flag_man_start_mute_audio"}, /* Polarity man audio mute sequence , */\ +{ 0x4df0, "int_polarity_flag_clk_out_of_range"}, /* Polarity flag_clk_out_of_range , */\ +{ 0x4e00, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ +{ 0x4e20, "int_polarity_flag_clip"}, /* Polarity clip right , */\ +{ 0x4e40, "int_polarity_flag_lp_detect_mode0"}, /* Polarity low power mode0 , */\ +{ 0x4e50, "int_polarity_flag_lp_detect_mode1"}, /* Polarity low power mode1 , */\ +{ 0x4e60, "int_polarity_flag_low_amplitude"}, /* Polarity low noise mode , */\ +{ 0x4e70, "int_polarity_flag_vddp_gt_vbat"}, /* Polarity VDDP greater than VBAT , */\ +{ 0x5001, "vbat_prot_attack_time"}, /* Battery Safeguard attack time , */\ +{ 0x5023, "vbat_prot_thlevel"}, /* Battery Safeguard threshold voltage level , */\ +{ 0x5061, "vbat_prot_max_reduct"}, /* Battery Safeguard maximum reduction , */\ +{ 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ +{ 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ +{ 0x50f0, "bypass_clipper"}, /* Bypass battery safeguard , */\ +{ 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ +{ 0x5110, "soft_mute"}, /* Soft mute HW , */\ +{ 0x5150, "bypass_hp"}, /* Bypass HPF , */\ +{ 0x5170, "enbl_dpsa"}, /* Enable DPSA , */\ +{ 0x5222, "ctrl_cc"}, /* Clip control setting , */\ +{ 0x5257, "gain"}, /* Amplifier gain , */\ +{ 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ +{ 0x52e0, "ctrl_slope"}, /* Slope speed setting (bin. coded) , */\ +{ 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ +{ 0x5321, "dpsa_release"}, /* DPSA Release time , */\ +{ 0x5340, "clipfast"}, /* Clock selection for HW clipper for Battery Safeguard, */\ +{ 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ +{ 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ +{ 0x5410, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ +{ 0x5420, "fb_hz"}, /* Feedback resistor set to high ohmic , */\ +{ 0x5430, "icomp_engage"}, /* Engage of icomp , */\ +{ 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ +{ 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ +{ 0x5503, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ +{ 0x5543, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ +{ 0x5582, "dpsa_drive"}, /* Drive setting (bin. coded) , */\ +{ 0x570a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually, */\ +{ 0x57b0, "enbl_engage"}, /* Enables/engage power stage and control loop , */\ +{ 0x57c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ +{ 0x5810, "hard_mute"}, /* Hard mute - PWM , */\ +{ 0x5820, "pwm_shape"}, /* PWM shape , */\ +{ 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ +{ 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ +{ 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ +{ 0x58c0, "enbl_pwm_phase_shift"}, /* Control for pwm phase shift , */\ +{ 0x6081, "pga_gain_set"}, /* PGA gain selection , */\ +{ 0x60b0, "pga_lowpass_enable"}, /* Lowpass enable , */\ +{ 0x60c0, "pga_pwr_enable"}, /* Power enable, directcontrol mode only , */\ +{ 0x60d0, "pga_switch_enable"}, /* Switch enable, directcontrol mode only , */\ +{ 0x60e0, "pga_switch_aux_enable"}, /* Switch enable aux, directcontrol mode only , */\ +{ 0x6100, "force_idle"}, /* force low power in idle mode , */\ +{ 0x6110, "bypass_idle"}, /* bypass low power idle mode , */\ +{ 0x6123, "ctrl_attl"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ +{ 0x6163, "ctrl_attr"}, /* Total gain depending on INPLEV setting (channel 0), */\ +{ 0x61a0, "idle_cnt"}, /* idle counter , */\ +{ 0x61b0, "enbl_idle_ch1"}, /* enable idle feature for channel 1 , */\ +{ 0x6265, "zero_lvl"}, /* low noise gain switch zero trigger level , */\ +{ 0x62c1, "ctrl_fb_classd"}, /* class D gain ctrl_fb_50k ctrl_fb_100k , */\ +{ 0x62e1, "lownoisegain_mode"}, /* ctrl select mode , */\ +{ 0x6305, "threshold_lvl"}, /* low noise gain switch trigger level , */\ +{ 0x6365, "hold_time"}, /* ctrl hold time before low audio is reckoned to be low audio, */\ +{ 0x6405, "lpm1_cal_offset"}, /* low power mode1 detector ctrl cal_offset from gain module , */\ +{ 0x6465, "lpm1_zero_lvl"}, /* low power mode1 zero crossing detection level , */\ +{ 0x64e1, "lpm1_mode"}, /* low power mode control , */\ +{ 0x6505, "lpm1_threshold_lvl"}, /* low power mode1 amplitude trigger level , */\ +{ 0x6565, "lpm1_hold_time"}, /* low power mode1 detector ctrl hold time before low audio is reckoned to be low audio, */\ +{ 0x65c0, "disable_low_power_mode"}, /* low power mode1 detector control , */\ +{ 0x6600, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ +{ 0x6611, "dcdc_ctrl_maxzercnt"}, /* DCDC. Number of zero current flags to count before going to pfm mode, */\ +{ 0x6656, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ +{ 0x66c0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ +{ 0x6700, "enbl_minion"}, /* Enables minion (small) power stage , */\ +{ 0x6713, "vth_vddpvbat"}, /* select vddp-vbat thres signal , */\ +{ 0x6750, "lpen_vddpvbat"}, /* select vddp-vbat filtred vs unfiltered compare , */\ +{ 0x6801, "tdm_source_mapping"}, /* tdm source mapping , */\ +{ 0x6821, "tdm_sourcea_frame_sel"}, /* Sensed value A , */\ +{ 0x6841, "tdm_sourceb_frame_sel"}, /* Sensed value B , */\ +{ 0x6881, "pdm_anc_sel"}, /* anc input , */\ +{ 0x68a0, "anc_1scomplement"}, /* ANC one s complement , */\ +{ 0x6901, "sam_mode"}, /* sam enable , */\ +{ 0x6920, "sam_src"}, /* sam source , */\ +{ 0x6931, "pdmdat_h_sel"}, /* pdm out value when pdm_clk is higth , */\ +{ 0x6951, "pdmdat_l_sel"}, /* pdm out value when pdm_clk is low , */\ +{ 0x6970, "sam_spkr_sel"}, /* ram output on mode sam and audio , */\ +{ 0x6a02, "rst_min_vbat_delay"}, /* rst_min_vbat delay (nb fs) , */\ +{ 0x6b00, "disable_auto_engage"}, /* disable auto engange , */\ +{ 0x6b10, "sel_tdm_data_valid"}, /* select tdm valid for speaker subsystem , */\ +{ 0x6c02, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ +{ 0x6c32, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ +{ 0x6c69, "spare_out"}, /* spare_out , */\ +{ 0x6d0f, "spare_in"}, /* spare_in , */\ +{ 0x6e00, "flag_lp_detect_mode0"}, /* low power mode 0 detection , */\ +{ 0x6e10, "flag_lp_detect_mode1"}, /* low power mode 1 detection , */\ +{ 0x6e20, "flag_low_amplitude"}, /* low amplitude detection , */\ +{ 0x6e30, "flag_vddp_gt_vbat"}, /* vddp greater than vbat , */\ +{ 0x6f02, "cursense_comp_delay"}, /* delay to allign compensation signal with current sense signal, */\ +{ 0x6f40, "cursense_comp_sign"}, /* polarity of compensation for current sense , */\ +{ 0x6f50, "enbl_cursense_comp"}, /* enable current sense compensation , */\ +{ 0x6f60, "sel_clip_pwms"}, /* Select pwm clip flag , */\ +{ 0x6f72, "pwms_clip_lvl"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ +{ 0x7002, "scnd_boost_voltage"}, /* Second boost voltage level , */\ +{ 0x7033, "boost_cur"}, /* Max coil current , */\ +{ 0x7071, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ +{ 0x7090, "boost_intel"}, /* Adaptive boost mode , */\ +{ 0x70a0, "boost_speed"}, /* Soft ramp up/down , */\ +{ 0x70e0, "dcdcoff_mode"}, /* DCDC on/off , */\ +{ 0x70f0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ +{ 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ +{ 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ +{ 0x7174, "bst_slopecur"}, /* For testing direct control slope current , */\ +{ 0x71c1, "bst_slope"}, /* Boost slope speed , */\ +{ 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ +{ 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ +{ 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ +{ 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ +{ 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ +{ 0x7230, "enbl_bst_peakcur"}, /* Enable peak current , */\ +{ 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage , */\ +{ 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ +{ 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ +{ 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ +{ 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ +{ 0x7290, "enbl_bst_windac"}, /* Enable window dac , */\ +{ 0x72a5, "bst_windac"}, /* for testing direct control windac , */\ +{ 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ +{ 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ +{ 0x7331, "bst_freq"}, /* DCDC boost frequency control , */\ +{ 0x7402, "frst_boost_voltage"}, /* 1st boost voltage level , */\ +{ 0x7430, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ +{ 0x7444, "boost_trip_lvl_1st"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7494, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ +{ 0x74e0, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ +{ 0x74f0, "ignore_flag_voutcomp86"}, /* Ignore flag_voutcomp86 , */\ +{ 0x7502, "track_decay"}, /* DCDC Boost decay speed after a peak value, effective only when boost_track is set to 1, */\ +{ 0x7534, "boost_trip_lvl_2nd"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7584, "boost_trip_lvl_track"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ +{ 0x7620, "pga_test_ldo_bypass"}, /* bypass internal PGA LDO , */\ +{ 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ +{ 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ +{ 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ +{ 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ +{ 0x8087, "cs_gain"}, /* Current sense gain , */\ +{ 0x8200, "enbl_cmfb"}, /* Current sense common mode feedback control , */\ +{ 0x8210, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ +{ 0x8222, "cmfb_gain"}, /* Current sense common mode feedback control gain , */\ +{ 0x8254, "cmfb_offset"}, /* Current sense common mode feedback control offset , */\ +{ 0x82a0, "cs_sam_set"}, /* Enable SAM input for current sense , */\ +{ 0x8305, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP)*signal, */\ +{ 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ +{ 0x8421, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ +{ 0x8440, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ +{ 0x8453, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ +{ 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ +{ 0x84a4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ +{ 0x8500, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ +{ 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ +{ 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ +{ 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ +{ 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ +{ 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ +{ 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ +{ 0x8700, "enbl_cs_adc"}, /* Enable current sense ADC , */\ +{ 0x8710, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 , */\ +{ 0x8720, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 , */\ +{ 0x8730, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ +{ 0x8740, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 , */\ +{ 0x8750, "enbl_cs_ldo"}, /* Enable current sense LDO , */\ +{ 0x8760, "enbl_cs_nofloating_n"}, /* Connect current sense negative to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ +{ 0x8770, "enbl_cs_nofloating_p"}, /* Connect current sense positive to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ +{ 0x8780, "enbl_cs_vbatldo"}, /* Enable of current sense LDO , */\ +{ 0x8800, "volsense_pwm_sel"}, /* Voltage sense PWM source selection control , */\ +{ 0x8810, "vol_cur_sense_dc_offset"}, /* voltage and current sense decimator offset control, */\ +{ 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ +{ 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ +{ 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ +{ 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ +{ 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ +{ 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ +{ 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ +{ 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ +{ 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ +{ 0xa400, "faim_set_clkws"}, /* Sets the faim controller clock wait state register, */\ +{ 0xa410, "faim_sel_evenrows"}, /* All even rows of the faim are selected, active high, */\ +{ 0xa420, "faim_sel_oddrows"}, /* All odd rows of the faim are selected, all rows in combination with sel_evenrows, */\ +{ 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ +{ 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ +{ 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ +{ 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ +{ 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ +{ 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ +{ 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ +{ 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ +{ 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ +{ 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ +{ 0xb050, "bypass_otp"}, /* Bypass OTP , */\ +{ 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ +{ 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ +{ 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ +{ 0xb108, "ext_temp"}, /* External temperature (C) , */\ +{ 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ +{ 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ +{ 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ +{ 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ +{ 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ +{ 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ +{ 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ +{ 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ +{ 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ +{ 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ +{ 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ +{ 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ +{ 0xc300, "bypasslatch"}, /* Bypass latch , */\ +{ 0xc311, "sourcea"}, /* Set OUTA to , */\ +{ 0xc331, "sourceb"}, /* Set OUTB to , */\ +{ 0xc350, "inverta"}, /* Invert pwma test signal , */\ +{ 0xc360, "invertb"}, /* Invert pwmb test signal , */\ +{ 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ +{ 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ +{ 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ +{ 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ +{ 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ +{ 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ +{ 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ +{ 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ +{ 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ +{ 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ +{ 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ +{ 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ +{ 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ +{ 0xc510, "test_discrete"}, /* Test function noise measurement , */\ +{ 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ +{ 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ +{ 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ +{ 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ +{ 0xc5b0, "pga_test_enable"}, /* Enable PGA test mode , */\ +{ 0xc5c0, "pga_test_offset_enable"}, /* Enable PGA test offset , */\ +{ 0xc5d0, "pga_test_shortinput_enable"}, /* Enable PGA test shortinput , */\ +{ 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ +{ 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ +{ 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ +{ 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to DATAO (see Digimux list for details), */\ +{ 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to INT (see Digimux list for details), */\ +{ 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to PDMDAT (see Digimux list for details), */\ +{ 0xc981, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xc9c0, "hs_mode"}, /* I2C high speed mode control , */\ +{ 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ +{ 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ +{ 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ +{ 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ +{ 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ +{ 0xcb04, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ +{ 0xcb54, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ +{ 0xcba4, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ +{ 0xcd05, "pll_seli"}, /* PLL SELI - I2C direct PLL control mode only , */\ +{ 0xcd64, "pll_selp"}, /* PLL SELP - I2C direct PLL control mode only , */\ +{ 0xcdb3, "pll_selr"}, /* PLL SELR - I2C direct PLL control mode only , */\ +{ 0xcdf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ +{ 0xce09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ +{ 0xcea0, "pll_mdec_msb"}, /* MSB of pll_mdec - I2C direct PLL control mode only, */\ +{ 0xceb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ +{ 0xcec0, "enbl_osc"}, /* Enables OSC1M in I2C direct control mode only , */\ +{ 0xced0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ +{ 0xcee0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ +{ 0xcef0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ +{ 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ +{ 0xd006, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ +{ 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ +{ 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ +{ 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ +{ 0xd283, "tsig_gain"}, /* Test signal gain , */\ +{ 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ +{ 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ +{ 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ +{ 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ +{ 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ +{ 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ +{ 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ +{ 0xd507, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ +{ 0xd580, "enbl_clk_out_of_range"}, /* Clock out of range , */\ +{ 0xd621, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ +{ 0xd641, "clkdiv_muxa_sel"}, /* DCDC MUXA clock divider selection in direct clock control mode, */\ +{ 0xd661, "clkdiv_muxb_sel"}, /* DCDC MUXB clock divider selection in direct clock control mode, */\ +{ 0xd701, "pdmdat_ehs"}, /* Speed/load setting for PDMDAT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xd721, "datao_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xd740, "bck_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xd750, "datai_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xd760, "pdmclk_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xd800, "source_in_testmode"}, /* tdm source in test mode (return only current and voltage sense), */\ +{ 0xd810, "gainatt_feedback"}, /* gainatt feedback to tdm , */\ +{ 0xd822, "test_parametric_io"}, /* test io parametric , */\ +{ 0xd850, "ctrl_bst_clk_lp1"}, /* boost clock control in low power mode1 , */\ +{ 0xd861, "test_spare_out1"}, /* test spare out 1 , */\ +{ 0xd880, "bst_dcmbst"}, /* dcm boost , */\ +{ 0xd890, "pdm_loopback"}, /* pdm loop back to tdm , */\ +{ 0xd8a1, "force_pga_clock"}, /* force pga clock , */\ +{ 0xd8c3, "test_spare_out2"}, /* test spare out 1 , */\ +{ 0xee0f, "sw_profile"}, /* Software profile data , */\ +{ 0xef0f, "sw_vstep"}, /* Software vstep information , */\ +{ 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ +{ 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ +{ 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ +{ 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ +{ 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ +{ 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ +{ 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ +{ 0xf163, "spare_mpt1_9_6"}, /* HW gain module - left channel (2's complement) , */\ +{ 0xf1a5, "spare_mpt1_15_10"}, /* Offset for amplifier, HW gain module - left channel (2's complement), */\ +{ 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ +{ 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ +{ 0xf2a3, "spare_mpt2_13_10"}, /* Trimming of LDO (2.7V) , */\ +{ 0xf307, "spare_mpt3_7_0"}, /* SPARE , */\ +{ 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ +{ 0xf40f, "spare_mtp4_15_0"}, /* SPARE , */\ +{ 0xf50f, "calibr_R25C_R"}, /* Ron resistance of speaker coil , */\ +{ 0xf606, "spare_mpt6_6_0"}, /* SPARE , */\ +{ 0xf686, "spare_mpt6_14_8"}, /* Offset of left amplifier level shifter B , */\ +{ 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ +{ 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ +{ 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ +{ 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ +{ 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ +{ 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ +{ 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable function dcdcoff_mode , */\ +{ 0xf910, "disable_sam_mode"}, /* Disable same mode , */\ +{ 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ +{ 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Disable programming of max dcdc boost voltage , */\ +{ 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ +{ 0xf980, "mtp_enbl_amp_in_state_alarm"}, /* Enbl_amp in alarm state , */\ +{ 0xf990, "mtp_enbl_pwm_delay_clock_gating"}, /* pwm delay clock auto gating , */\ +{ 0xf9a0, "mtp_enbl_ocp_clock_gating"}, /* ocpclock auto gating , */\ +{ 0xf9b0, "mtp_gate_cgu_clock_for_test"}, /* cgu test clock control , */\ +{ 0xf9c3, "spare_mtp9_15_12"}, /* MTP-control FW - See Firmware I2C API document for details, */\ +{ 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ +{ 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ +{ 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ +{ 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ +{ 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ +{ 0xff07, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ +{ 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa9872_irq { +tfa9872_irq_stvdds = 0, +tfa9872_irq_stplls = 1, +tfa9872_irq_stotds = 2, +tfa9872_irq_stovds = 3, +tfa9872_irq_stuvds = 4, +tfa9872_irq_stclks = 5, +tfa9872_irq_stmtpb = 6, +tfa9872_irq_stnoclk = 7, +tfa9872_irq_stsws = 10, +tfa9872_irq_stamps = 12, +tfa9872_irq_starefs = 13, +tfa9872_irq_stadccr = 14, +tfa9872_irq_stbstcu = 16, +tfa9872_irq_stbsthi = 17, +tfa9872_irq_stbstoc = 18, +tfa9872_irq_stbstpkcur = 19, +tfa9872_irq_stbstvc = 20, +tfa9872_irq_stbst86 = 21, +tfa9872_irq_stbst93 = 22, +tfa9872_irq_stocpr = 25, +tfa9872_irq_stmwsrc = 26, +tfa9872_irq_stmwsmu = 28, +tfa9872_irq_stclkoor = 31, +tfa9872_irq_sttdmer = 32, +tfa9872_irq_stclpr = 34, +tfa9872_irq_stlp0 = 36, +tfa9872_irq_stlp1 = 37, +tfa9872_irq_stla = 38, +tfa9872_irq_stvddph = 39, +tfa9872_irq_max = 40, +tfa9872_irq_all = -1 /* all irqs */}; + +#define TFA9872_IRQ_NAMETABLE static tfaIrqName_t Tfa9872IrqNames[] = {\ +{ 0, "STVDDS"},\ +{ 1, "STPLLS"},\ +{ 2, "STOTDS"},\ +{ 3, "STOVDS"},\ +{ 4, "STUVDS"},\ +{ 5, "STCLKS"},\ +{ 6, "STMTPB"},\ +{ 7, "STNOCLK"},\ +{ 8, "8"},\ +{ 9, "9"},\ +{ 10, "STSWS"},\ +{ 11, "11"},\ +{ 12, "STAMPS"},\ +{ 13, "STAREFS"},\ +{ 14, "STADCCR"},\ +{ 15, "15"},\ +{ 16, "STBSTCU"},\ +{ 17, "STBSTHI"},\ +{ 18, "STBSTOC"},\ +{ 19, "STBSTPKCUR"},\ +{ 20, "STBSTVC"},\ +{ 21, "STBST86"},\ +{ 22, "STBST93"},\ +{ 23, "23"},\ +{ 24, "24"},\ +{ 25, "STOCPR"},\ +{ 26, "STMWSRC"},\ +{ 27, "27"},\ +{ 28, "STMWSMU"},\ +{ 29, "29"},\ +{ 30, "30"},\ +{ 31, "STCLKOOR"},\ +{ 32, "STTDMER"},\ +{ 33, "33"},\ +{ 34, "STCLPR"},\ +{ 35, "35"},\ +{ 36, "STLP0"},\ +{ 37, "STLP1"},\ +{ 38, "STLA"},\ +{ 39, "STVDDPH"},\ +{ 40, "40"},\ +}; +#endif /* _TFA9872_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa9874_tfafieldnames.h b/sound/soc/codecs/tfa9874_tfafieldnames.h new file mode 100644 index 000000000000..5c6a23361c1f --- /dev/null +++ b/sound/soc/codecs/tfa9874_tfafieldnames.h @@ -0,0 +1,836 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9874_TFAFIELDNAMES_H +#define _TFA9874_TFAFIELDNAMES_H + + +#define TFA9874_I2CVERSION 1.16 + +typedef enum nxpTfa9874BfEnumList { +TFA9874_BF_PWDN = 0x0000, /*!< Powerdown selection */ +TFA9874_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ +TFA9874_BF_AMPE = 0x0030, /*!< Activate Amplifier */ +TFA9874_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ +TFA9874_BF_INTP = 0x0071, /*!< Interrupt config */ +TFA9874_BF_BYPOCP = 0x00b0, /*!< Bypass OCP */ +TFA9874_BF_TSTOCP = 0x00c0, /*!< OCP testing control */ +TFA9874_BF_MANSCONF = 0x0120, /*!< I2C configured */ +TFA9874_BF_MANAOOSC = 0x0140, /*!< Internal osc off at PWDN */ +TFA9874_BF_MUTETO = 0x01d0, /*!< Time out SB mute sequence */ +TFA9874_BF_OPENMTP = 0x01e0, /*!< Control for FAIM protection */ +TFA9874_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ +TFA9874_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ +TFA9874_BF_FRACTDEL = 0x0255, /*!< V/I Fractional delay */ +TFA9874_BF_REV = 0x030f, /*!< Revision info */ +TFA9874_BF_REFCKEXT = 0x0401, /*!< PLL external ref clock */ +TFA9874_BF_REFCKSEL = 0x0420, /*!< PLL internal ref clock */ +TFA9874_BF_SSFAIME = 0x05c0, /*!< Sub-system FAIM */ +TFA9874_BF_AMPOCRT = 0x0802, /*!< Amplifier on-off criteria for shutdown */ +TFA9874_BF_VDDS = 0x1000, /*!< POR */ +TFA9874_BF_DCOCPOK = 0x1010, /*!< DCDC OCP nmos (sticky register , clear on read) */ +TFA9874_BF_OTDS = 0x1020, /*!< OTP alarm (sticky register , clear on read) */ +TFA9874_BF_OCDS = 0x1030, /*!< OCP amplifier (sticky register , clear on read) */ +TFA9874_BF_UVDS = 0x1040, /*!< UVP alarm (sticky register , clear on read) */ +TFA9874_BF_MANALARM = 0x1050, /*!< Alarm state */ +TFA9874_BF_TDMERR = 0x1060, /*!< TDM error */ +TFA9874_BF_NOCLK = 0x1070, /*!< Lost clock (sticky register , clear on read) */ +TFA9874_BF_DCIL = 0x1100, /*!< DCDC current limiting */ +TFA9874_BF_DCDCA = 0x1110, /*!< DCDC active (sticky register , clear on read) */ +TFA9874_BF_DCHVBAT = 0x1130, /*!< DCDC level 1x */ +TFA9874_BF_DCH114 = 0x1140, /*!< DCDC level 1.14x */ +TFA9874_BF_DCH107 = 0x1150, /*!< DCDC level 1.07x */ +TFA9874_BF_PLLS = 0x1160, /*!< PLL lock */ +TFA9874_BF_CLKS = 0x1170, /*!< Clocks stable */ +TFA9874_BF_TDMLUTER = 0x1180, /*!< TDM LUT error */ +TFA9874_BF_TDMSTAT = 0x1192, /*!< TDM status bits */ +TFA9874_BF_MTPB = 0x11c0, /*!< MTP busy */ +TFA9874_BF_SWS = 0x11d0, /*!< Amplifier engage */ +TFA9874_BF_AMPS = 0x11e0, /*!< Amplifier enable */ +TFA9874_BF_AREFS = 0x11f0, /*!< References enable */ +TFA9874_BF_OCPOAP = 0x1300, /*!< OCPOK pmos A */ +TFA9874_BF_OCPOAN = 0x1310, /*!< OCPOK nmos A */ +TFA9874_BF_OCPOBP = 0x1320, /*!< OCPOK pmos B */ +TFA9874_BF_OCPOBN = 0x1330, /*!< OCPOK nmos B */ +TFA9874_BF_OVDS = 0x1380, /*!< OVP alarm */ +TFA9874_BF_CLIPS = 0x1390, /*!< Amplifier clipping */ +TFA9874_BF_ADCCR = 0x13a0, /*!< Control ADC */ +TFA9874_BF_MANWAIT1 = 0x13c0, /*!< Wait HW I2C settings */ +TFA9874_BF_MANMUTE = 0x13e0, /*!< Audio mute sequence */ +TFA9874_BF_MANOPER = 0x13f0, /*!< Operating state */ +TFA9874_BF_CLKOOR = 0x1420, /*!< External clock status */ +TFA9874_BF_MANSTATE = 0x1433, /*!< Device manager status */ +TFA9874_BF_DCMODE = 0x1471, /*!< DCDC mode status bits */ +TFA9874_BF_BATS = 0x1509, /*!< Battery voltage (V) */ +TFA9874_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ +TFA9874_BF_VDDPS = 0x1709, /*!< IC VDDP voltage ( 1023*VDDP/13 V) */ +TFA9874_BF_TDME = 0x2040, /*!< Enable interface */ +TFA9874_BF_TDMMODE = 0x2050, /*!< Slave/master */ +TFA9874_BF_TDMCLINV = 0x2060, /*!< Reception data to BCK clock */ +TFA9874_BF_TDMFSLN = 0x2073, /*!< FS length (master mode only) */ +TFA9874_BF_TDMFSPOL = 0x20b0, /*!< FS polarity */ +TFA9874_BF_TDMNBCK = 0x20c3, /*!< N-BCK's in FS */ +TFA9874_BF_TDMSLOTS = 0x2103, /*!< N-slots in Frame */ +TFA9874_BF_TDMSLLN = 0x2144, /*!< N-bits in slot */ +TFA9874_BF_TDMBRMG = 0x2194, /*!< N-bits remaining */ +TFA9874_BF_TDMDEL = 0x21e0, /*!< data delay to FS */ +TFA9874_BF_TDMADJ = 0x21f0, /*!< data adjustment */ +TFA9874_BF_TDMOOMP = 0x2201, /*!< Received audio compression */ +TFA9874_BF_TDMSSIZE = 0x2224, /*!< Sample size per slot */ +TFA9874_BF_TDMTXDFO = 0x2271, /*!< Format unused bits */ +TFA9874_BF_TDMTXUS0 = 0x2291, /*!< Format unused slots DATAO */ +TFA9874_BF_TDMSPKE = 0x2300, /*!< Control audio tdm channel in 0 (spkr + dcdc) */ +TFA9874_BF_TDMDCE = 0x2310, /*!< Control audio tdm channel in 1 (dcdc) */ +TFA9874_BF_TDMCSE = 0x2330, /*!< current sense vbat temperature and vddp feedback */ +TFA9874_BF_TDMVSE = 0x2340, /*!< Voltage sense vbat temperature and vddp feedback */ +TFA9874_BF_TDMSPKS = 0x2603, /*!< tdm slot for sink 0 (speaker + dcdc) */ +TFA9874_BF_TDMDCS = 0x2643, /*!< tdm slot for sink 1 (dcdc) */ +TFA9874_BF_TDMCSS = 0x26c3, /*!< Slot Position of current sense vbat temperature and vddp feedback */ +TFA9874_BF_TDMVSS = 0x2703, /*!< Slot Position of Voltage sense vbat temperature and vddp feedback */ +TFA9874_BF_ISTVDDS = 0x4000, /*!< Status POR */ +TFA9874_BF_ISTBSTOC = 0x4010, /*!< Status DCDC OCP */ +TFA9874_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ +TFA9874_BF_ISTOCPR = 0x4030, /*!< Status ocp alarm */ +TFA9874_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ +TFA9874_BF_ISTMANALARM = 0x4050, /*!< Status nanager Alarm state */ +TFA9874_BF_ISTTDMER = 0x4060, /*!< Status tdm error */ +TFA9874_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ +TFA9874_BF_ICLVDDS = 0x4400, /*!< Clear POR */ +TFA9874_BF_ICLBSTOC = 0x4410, /*!< Clear DCDC OCP */ +TFA9874_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ +TFA9874_BF_ICLOCPR = 0x4430, /*!< Clear ocp alarm */ +TFA9874_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ +TFA9874_BF_ICLMANALARM = 0x4450, /*!< clear nanager Alarm state */ +TFA9874_BF_ICLTDMER = 0x4460, /*!< Clear tdm error */ +TFA9874_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ +TFA9874_BF_IEVDDS = 0x4800, /*!< Enable por */ +TFA9874_BF_IEBSTOC = 0x4810, /*!< Enable DCDC OCP */ +TFA9874_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ +TFA9874_BF_IEOCPR = 0x4830, /*!< Enable ocp alarm */ +TFA9874_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ +TFA9874_BF_IEMANALARM = 0x4850, /*!< Enable nanager Alarm state */ +TFA9874_BF_IETDMER = 0x4860, /*!< Enable tdm error */ +TFA9874_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ +TFA9874_BF_IPOVDDS = 0x4c00, /*!< Polarity por */ +TFA9874_BF_IPOBSTOC = 0x4c10, /*!< Polarity DCDC OCP */ +TFA9874_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ +TFA9874_BF_IPOOCPR = 0x4c30, /*!< Polarity ocp alarm */ +TFA9874_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ +TFA9874_BF_IPOMANALARM = 0x4c50, /*!< Polarity nanager Alarm state */ +TFA9874_BF_IPOTDMER = 0x4c60, /*!< Polarity tdm error */ +TFA9874_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ +TFA9874_BF_BSSCR = 0x5001, /*!< Battery Safeguard attack time */ +TFA9874_BF_BSST = 0x5023, /*!< Battery Safeguard threshold voltage level */ +TFA9874_BF_BSSRL = 0x5061, /*!< Battery Safeguard maximum reduction */ +TFA9874_BF_VBATFLTL = 0x5080, /*!< vbat filter limit */ +TFA9874_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ +TFA9874_BF_BSSBY = 0x50f0, /*!< Bypass battery safeguard */ +TFA9874_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ +TFA9874_BF_HPFBYP = 0x5150, /*!< Bypass HPF */ +TFA9874_BF_DPSA = 0x5170, /*!< Enable DPSA */ +TFA9874_BF_CLIPCTRL = 0x5222, /*!< Clip control setting */ +TFA9874_BF_AMPGAIN = 0x5257, /*!< Amplifier gain */ +TFA9874_BF_SLOPEE = 0x52d0, /*!< Enables slope control */ +TFA9874_BF_SLOPESET = 0x52e0, /*!< Slope speed setting (bin. coded) */ +TFA9874_BF_TDMDCG = 0x6123, /*!< Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE) */ +TFA9874_BF_TDMSPKG = 0x6163, /*!< Total gain depending on INPLEV setting (channel 0) */ +TFA9874_BF_LNMODE = 0x62e1, /*!< ctrl select mode */ +TFA9874_BF_LPM1MODE = 0x64e1, /*!< low power mode control */ +TFA9874_BF_TDMSRCMAP = 0x6802, /*!< tdm source mapping */ +TFA9874_BF_TDMSRCAS = 0x6831, /*!< Sensed value A */ +TFA9874_BF_TDMSRCBS = 0x6851, /*!< Sensed value B */ +TFA9874_BF_TDMSRCACLIP = 0x6871, /*!< clip information (analog /digital) for source0 */ +TFA9874_BF_TDMSRCBCLIP = 0x6891, /*!< clip information (analog /digital) for source1 */ +TFA9874_BF_LP1 = 0x6e10, /*!< low power mode 1 detection */ +TFA9874_BF_LA = 0x6e20, /*!< low amplitude detection */ +TFA9874_BF_VDDPH = 0x6e30, /*!< vddp greater than vbat */ +TFA9874_BF_DELCURCOMP = 0x6f02, /*!< delay to allign compensation signal with current sense signal */ +TFA9874_BF_SIGCURCOMP = 0x6f40, /*!< polarity of compensation for current sense */ +TFA9874_BF_ENCURCOMP = 0x6f50, /*!< enable current sense compensation */ +TFA9874_BF_LVLCLPPWM = 0x6f72, /*!< set the amount of pwm pulse that may be skipped before clip-flag is triggered */ +TFA9874_BF_DCMCC = 0x7033, /*!< Max coil current */ +TFA9874_BF_DCCV = 0x7071, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ +TFA9874_BF_DCIE = 0x7090, /*!< Adaptive boost mode */ +TFA9874_BF_DCSR = 0x70a0, /*!< Soft ramp up/down */ +TFA9874_BF_DCDIS = 0x70e0, /*!< DCDC on/off */ +TFA9874_BF_DCPWM = 0x70f0, /*!< DCDC PWM only mode */ +TFA9874_BF_DCTRACK = 0x7430, /*!< Boost algorithm selection, effective only when boost_intelligent is set to 1 */ +TFA9874_BF_DCTRIP = 0x7444, /*!< 1st Adaptive boost trip levels, effective only when DCIE is set to 1 */ +TFA9874_BF_DCHOLD = 0x7494, /*!< Hold time for DCDC booster, effective only when boost_intelligent is set to 1 */ +TFA9874_BF_DCINT = 0x74e0, /*!< Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1 */ +TFA9874_BF_DCTRIP2 = 0x7534, /*!< 2nd Adaptive boost trip levels, effective only when DCIE is set to 1 */ +TFA9874_BF_DCTRIPT = 0x7584, /*!< Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ +TFA9874_BF_DCTRIPHYSTE = 0x75f0, /*!< Enable hysteresis on booster trip levels */ +TFA9874_BF_DCVOF = 0x7635, /*!< First boost voltage level */ +TFA9874_BF_DCVOS = 0x7695, /*!< Second boost voltage level */ +TFA9874_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ +TFA9874_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ +TFA9874_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ +TFA9874_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp */ +TFA9874_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ +TFA9874_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ +TFA9874_BF_EXTTS = 0xb108, /*!< External temperature (C) */ +TFA9874_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ +TFA9874_BF_SWPROFIL = 0xee0f, /*!< Software profile data */ +TFA9874_BF_SWVSTEP = 0xef0f, /*!< Software vstep information */ +TFA9874_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ +TFA9874_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ +TFA9874_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ +TFA9874_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ +TFA9874_BF_USERDEF = 0xf042, /*!< Calibration delta current limit DCDC */ +TFA9874_BF_CUSTINFO = 0xf078, /*!< Reserved space for allowing customer to store speaker information */ +TFA9874_BF_R25C = 0xf50f, /*!< Ron resistance of speaker coil */ +} nxpTfa9874BfEnumList_t; +#define TFA9874_NAMETABLE static tfaBfName_t Tfa9874DatasheetNames[] = {\ +{ 0x0, "PWDN"}, /* Powerdown selection , */\ +{ 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ +{ 0x30, "AMPE"}, /* Activate Amplifier , */\ +{ 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ +{ 0x71, "INTP"}, /* Interrupt config , */\ +{ 0xb0, "BYPOCP"}, /* Bypass OCP , */\ +{ 0xc0, "TSTOCP"}, /* OCP testing control , */\ +{ 0x120, "MANSCONF"}, /* I2C configured , */\ +{ 0x140, "MANAOOSC"}, /* Internal osc off at PWDN , */\ +{ 0x1d0, "MUTETO"}, /* Time out SB mute sequence , */\ +{ 0x1e0, "OPENMTP"}, /* Control for FAIM protection , */\ +{ 0x203, "AUDFS"}, /* Sample rate (fs) , */\ +{ 0x240, "INPLEV"}, /* TDM output attenuation , */\ +{ 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ +{ 0x30f, "REV"}, /* Revision info , */\ +{ 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ +{ 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ +{ 0x5c0, "SSFAIME"}, /* Sub-system FAIM , */\ +{ 0x802, "AMPOCRT"}, /* Amplifier on-off criteria for shutdown , */\ +{ 0x1000, "VDDS"}, /* POR , */\ +{ 0x1010, "DCOCPOK"}, /* DCDC OCP nmos (sticky register , clear on read) , */\ +{ 0x1020, "OTDS"}, /* OTP alarm (sticky register , clear on read) , */\ +{ 0x1030, "OCDS"}, /* OCP amplifier (sticky register , clear on read), */\ +{ 0x1040, "UVDS"}, /* UVP alarm (sticky register , clear on read) , */\ +{ 0x1050, "MANALARM"}, /* Alarm state , */\ +{ 0x1060, "TDMERR"}, /* TDM error , */\ +{ 0x1070, "NOCLK"}, /* Lost clock (sticky register , clear on read) , */\ +{ 0x1100, "DCIL"}, /* DCDC current limiting , */\ +{ 0x1110, "DCDCA"}, /* DCDC active (sticky register , clear on read) , */\ +{ 0x1130, "DCHVBAT"}, /* DCDC level 1x , */\ +{ 0x1140, "DCH114"}, /* DCDC level 1.14x , */\ +{ 0x1150, "DCH107"}, /* DCDC level 1.07x , */\ +{ 0x1160, "PLLS"}, /* PLL lock , */\ +{ 0x1170, "CLKS"}, /* Clocks stable , */\ +{ 0x1180, "TDMLUTER"}, /* TDM LUT error , */\ +{ 0x1192, "TDMSTAT"}, /* TDM status bits , */\ +{ 0x11c0, "MTPB"}, /* MTP busy , */\ +{ 0x11d0, "SWS"}, /* Amplifier engage , */\ +{ 0x11e0, "AMPS"}, /* Amplifier enable , */\ +{ 0x11f0, "AREFS"}, /* References enable , */\ +{ 0x1300, "OCPOAP"}, /* OCPOK pmos A , */\ +{ 0x1310, "OCPOAN"}, /* OCPOK nmos A , */\ +{ 0x1320, "OCPOBP"}, /* OCPOK pmos B , */\ +{ 0x1330, "OCPOBN"}, /* OCPOK nmos B , */\ +{ 0x1380, "OVDS"}, /* OVP alarm , */\ +{ 0x1390, "CLIPS"}, /* Amplifier clipping , */\ +{ 0x13a0, "ADCCR"}, /* Control ADC , */\ +{ 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ +{ 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ +{ 0x13f0, "MANOPER"}, /* Operating state , */\ +{ 0x1420, "CLKOOR"}, /* External clock status , */\ +{ 0x1433, "MANSTATE"}, /* Device manager status , */\ +{ 0x1471, "DCMODE"}, /* DCDC mode status bits , */\ +{ 0x1509, "BATS"}, /* Battery voltage (V) , */\ +{ 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ +{ 0x1709, "VDDPS"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ +{ 0x2040, "TDME"}, /* Enable interface , */\ +{ 0x2050, "TDMMODE"}, /* Slave/master , */\ +{ 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ +{ 0x2073, "TDMFSLN"}, /* FS length (master mode only) , */\ +{ 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ +{ 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ +{ 0x2103, "TDMSLOTS"}, /* N-slots in Frame , */\ +{ 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ +{ 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ +{ 0x21e0, "TDMDEL"}, /* data delay to FS , */\ +{ 0x21f0, "TDMADJ"}, /* data adjustment , */\ +{ 0x2201, "TDMOOMP"}, /* Received audio compression , */\ +{ 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ +{ 0x2271, "TDMTXDFO"}, /* Format unused bits , */\ +{ 0x2291, "TDMTXUS0"}, /* Format unused slots DATAO , */\ +{ 0x2300, "TDMSPKE"}, /* Control audio tdm channel in 0 (spkr + dcdc) , */\ +{ 0x2310, "TDMDCE"}, /* Control audio tdm channel in 1 (dcdc) , */\ +{ 0x2330, "TDMCSE"}, /* current sense vbat temperature and vddp feedback , */\ +{ 0x2340, "TDMVSE"}, /* Voltage sense vbat temperature and vddp feedback , */\ +{ 0x2603, "TDMSPKS"}, /* tdm slot for sink 0 (speaker + dcdc) , */\ +{ 0x2643, "TDMDCS"}, /* tdm slot for sink 1 (dcdc) , */\ +{ 0x26c3, "TDMCSS"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ +{ 0x2703, "TDMVSS"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ +{ 0x4000, "ISTVDDS"}, /* Status POR , */\ +{ 0x4010, "ISTBSTOC"}, /* Status DCDC OCP , */\ +{ 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ +{ 0x4030, "ISTOCPR"}, /* Status ocp alarm , */\ +{ 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ +{ 0x4050, "ISTMANALARM"}, /* Status nanager Alarm state , */\ +{ 0x4060, "ISTTDMER"}, /* Status tdm error , */\ +{ 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ +{ 0x4400, "ICLVDDS"}, /* Clear POR , */\ +{ 0x4410, "ICLBSTOC"}, /* Clear DCDC OCP , */\ +{ 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ +{ 0x4430, "ICLOCPR"}, /* Clear ocp alarm , */\ +{ 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ +{ 0x4450, "ICLMANALARM"}, /* clear nanager Alarm state , */\ +{ 0x4460, "ICLTDMER"}, /* Clear tdm error , */\ +{ 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ +{ 0x4800, "IEVDDS"}, /* Enable por , */\ +{ 0x4810, "IEBSTOC"}, /* Enable DCDC OCP , */\ +{ 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ +{ 0x4830, "IEOCPR"}, /* Enable ocp alarm , */\ +{ 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ +{ 0x4850, "IEMANALARM"}, /* Enable nanager Alarm state , */\ +{ 0x4860, "IETDMER"}, /* Enable tdm error , */\ +{ 0x4870, "IENOCLK"}, /* Enable lost clk , */\ +{ 0x4c00, "IPOVDDS"}, /* Polarity por , */\ +{ 0x4c10, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ +{ 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ +{ 0x4c30, "IPOOCPR"}, /* Polarity ocp alarm , */\ +{ 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ +{ 0x4c50, "IPOMANALARM"}, /* Polarity nanager Alarm state , */\ +{ 0x4c60, "IPOTDMER"}, /* Polarity tdm error , */\ +{ 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ +{ 0x5001, "BSSCR"}, /* Battery Safeguard attack time , */\ +{ 0x5023, "BSST"}, /* Battery Safeguard threshold voltage level , */\ +{ 0x5061, "BSSRL"}, /* Battery Safeguard maximum reduction , */\ +{ 0x5080, "VBATFLTL"}, /* vbat filter limit , */\ +{ 0x50e0, "BSSR"}, /* Battery voltage read out , */\ +{ 0x50f0, "BSSBY"}, /* Bypass battery safeguard , */\ +{ 0x5100, "BSSS"}, /* Vbat prot steepness , */\ +{ 0x5150, "HPFBYP"}, /* Bypass HPF , */\ +{ 0x5170, "DPSA"}, /* Enable DPSA , */\ +{ 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ +{ 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ +{ 0x52d0, "SLOPEE"}, /* Enables slope control , */\ +{ 0x52e0, "SLOPESET"}, /* Slope speed setting (bin. coded) , */\ +{ 0x6123, "TDMDCG"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ +{ 0x6163, "TDMSPKG"}, /* Total gain depending on INPLEV setting (channel 0), */\ +{ 0x62e1, "LNMODE"}, /* ctrl select mode , */\ +{ 0x64e1, "LPM1MODE"}, /* low power mode control , */\ +{ 0x6802, "TDMSRCMAP"}, /* tdm source mapping , */\ +{ 0x6831, "TDMSRCAS"}, /* Sensed value A , */\ +{ 0x6851, "TDMSRCBS"}, /* Sensed value B , */\ +{ 0x6871, "TDMSRCACLIP"}, /* clip information (analog /digital) for source0 , */\ +{ 0x6891, "TDMSRCBCLIP"}, /* clip information (analog /digital) for source1 , */\ +{ 0x6e10, "LP1"}, /* low power mode 1 detection , */\ +{ 0x6e20, "LA"}, /* low amplitude detection , */\ +{ 0x6e30, "VDDPH"}, /* vddp greater than vbat , */\ +{ 0x6f02, "DELCURCOMP"}, /* delay to allign compensation signal with current sense signal, */\ +{ 0x6f40, "SIGCURCOMP"}, /* polarity of compensation for current sense , */\ +{ 0x6f50, "ENCURCOMP"}, /* enable current sense compensation , */\ +{ 0x6f72, "LVLCLPPWM"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ +{ 0x7033, "DCMCC"}, /* Max coil current , */\ +{ 0x7071, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ +{ 0x7090, "DCIE"}, /* Adaptive boost mode , */\ +{ 0x70a0, "DCSR"}, /* Soft ramp up/down , */\ +{ 0x70e0, "DCDIS"}, /* DCDC on/off , */\ +{ 0x70f0, "DCPWM"}, /* DCDC PWM only mode , */\ +{ 0x7430, "DCTRACK"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ +{ 0x7444, "DCTRIP"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7494, "DCHOLD"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ +{ 0x74e0, "DCINT"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ +{ 0x7534, "DCTRIP2"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7584, "DCTRIPT"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ +{ 0x75f0, "DCTRIPHYSTE"}, /* Enable hysteresis on booster trip levels , */\ +{ 0x7635, "DCVOF"}, /* First boost voltage level , */\ +{ 0x7695, "DCVOS"}, /* Second boost voltage level , */\ +{ 0xa107, "MTPK"}, /* MTP KEY2 register , */\ +{ 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ +{ 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ +{ 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ +{ 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ +{ 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ +{ 0xb108, "EXTTS"}, /* External temperature (C) , */\ +{ 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ +{ 0xee0f, "SWPROFIL"}, /* Software profile data , */\ +{ 0xef0f, "SWVSTEP"}, /* Software vstep information , */\ +{ 0xf000, "MTPOTC"}, /* Calibration schedule , */\ +{ 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ +{ 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ +{ 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ +{ 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ +{ 0xf078, "CUSTINFO"}, /* Reserved space for allowing customer to store speaker information, */\ +{ 0xf50f, "R25C"}, /* Ron resistance of speaker coil , */\ +{ 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9874_BITNAMETABLE static tfaBfName_t Tfa9874BitNames[] = {\ +{ 0x0, "powerdown"}, /* Powerdown selection , */\ +{ 0x10, "reset"}, /* I2C Reset - Auto clear , */\ +{ 0x30, "enbl_amplifier"}, /* Activate Amplifier , */\ +{ 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ +{ 0x71, "int_pad_io"}, /* Interrupt config , */\ +{ 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ +{ 0xc0, "test_ocp"}, /* OCP testing control , */\ +{ 0x120, "src_set_configured"}, /* I2C configured , */\ +{ 0x140, "enbl_osc1m_auto_off"}, /* Internal osc off at PWDN , */\ +{ 0x1d0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ +{ 0x1e0, "unprotect_faim"}, /* Control for FAIM protection , */\ +{ 0x203, "audio_fs"}, /* Sample rate (fs) , */\ +{ 0x240, "input_level"}, /* TDM output attenuation , */\ +{ 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ +{ 0x2d0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ +{ 0x30f, "device_rev"}, /* Revision info , */\ +{ 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ +{ 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ +{ 0x5c0, "enbl_faim_ss"}, /* Sub-system FAIM , */\ +{ 0x802, "ctrl_on2off_criterion"}, /* Amplifier on-off criteria for shutdown , */\ +{ 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ +{ 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ +{ 0x1000, "flag_por"}, /* POR , */\ +{ 0x1010, "flag_bst_ocpok"}, /* DCDC OCP nmos (sticky register , clear on read) , */\ +{ 0x1020, "flag_otpok"}, /* OTP alarm (sticky register , clear on read) , */\ +{ 0x1030, "flag_ocp_alarm"}, /* OCP amplifier (sticky register , clear on read), */\ +{ 0x1040, "flag_uvpok"}, /* UVP alarm (sticky register , clear on read) , */\ +{ 0x1050, "flag_man_alarm_state"}, /* Alarm state , */\ +{ 0x1060, "flag_tdm_error"}, /* TDM error , */\ +{ 0x1070, "flag_lost_clk"}, /* Lost clock (sticky register , clear on read) , */\ +{ 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ +{ 0x1110, "flag_bst_hiz"}, /* DCDC active (sticky register , clear on read) , */\ +{ 0x1120, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ +{ 0x1130, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ +{ 0x1140, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ +{ 0x1150, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ +{ 0x1160, "flag_pll_lock"}, /* PLL lock , */\ +{ 0x1170, "flag_clocks_stable"}, /* Clocks stable , */\ +{ 0x1180, "flag_tdm_lut_error"}, /* TDM LUT error , */\ +{ 0x1192, "flag_tdm_status"}, /* TDM status bits , */\ +{ 0x11c0, "flag_mtp_busy"}, /* MTP busy , */\ +{ 0x11d0, "flag_engage"}, /* Amplifier engage , */\ +{ 0x11e0, "flag_enbl_amp"}, /* Amplifier enable , */\ +{ 0x11f0, "flag_enbl_ref"}, /* References enable , */\ +{ 0x1300, "flag_ocpokap"}, /* OCPOK pmos A , */\ +{ 0x1310, "flag_ocpokan"}, /* OCPOK nmos A , */\ +{ 0x1320, "flag_ocpokbp"}, /* OCPOK pmos B , */\ +{ 0x1330, "flag_ocpokbn"}, /* OCPOK nmos B , */\ +{ 0x1380, "flag_ovpok"}, /* OVP alarm , */\ +{ 0x1390, "flag_clip"}, /* Amplifier clipping , */\ +{ 0x13a0, "flag_adc10_ready"}, /* Control ADC , */\ +{ 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ +{ 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ +{ 0x13f0, "flag_man_operating_state"}, /* Operating state , */\ +{ 0x1420, "flag_clk_out_of_range"}, /* External clock status , */\ +{ 0x1433, "man_state"}, /* Device manager status , */\ +{ 0x1471, "status_bst_mode"}, /* DCDC mode status bits , */\ +{ 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ +{ 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ +{ 0x1709, "vddp_adc"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ +{ 0x2040, "tdm_enable"}, /* Enable interface , */\ +{ 0x2050, "tdm_mode"}, /* Slave/master , */\ +{ 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ +{ 0x2073, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ +{ 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ +{ 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ +{ 0x2103, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ +{ 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ +{ 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ +{ 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ +{ 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ +{ 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ +{ 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ +{ 0x2271, "tdm_txdata_format"}, /* Format unused bits , */\ +{ 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots DATAO , */\ +{ 0x2300, "tdm_sink0_enable"}, /* Control audio tdm channel in 0 (spkr + dcdc) , */\ +{ 0x2310, "tdm_sink1_enable"}, /* Control audio tdm channel in 1 (dcdc) , */\ +{ 0x2330, "tdm_source0_enable"}, /* current sense vbat temperature and vddp feedback , */\ +{ 0x2340, "tdm_source1_enable"}, /* Voltage sense vbat temperature and vddp feedback , */\ +{ 0x2603, "tdm_sink0_slot"}, /* tdm slot for sink 0 (speaker + dcdc) , */\ +{ 0x2643, "tdm_sink1_slot"}, /* tdm slot for sink 1 (dcdc) , */\ +{ 0x26c3, "tdm_source0_slot"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ +{ 0x2703, "tdm_source1_slot"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ +{ 0x4000, "int_out_flag_por"}, /* Status POR , */\ +{ 0x4010, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ +{ 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ +{ 0x4030, "int_out_flag_ocp_alarm"}, /* Status ocp alarm , */\ +{ 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ +{ 0x4050, "int_out_flag_man_alarm_state"}, /* Status nanager Alarm state , */\ +{ 0x4060, "int_out_flag_tdm_error"}, /* Status tdm error , */\ +{ 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ +{ 0x4400, "int_in_flag_por"}, /* Clear POR , */\ +{ 0x4410, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ +{ 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ +{ 0x4430, "int_in_flag_ocp_alarm"}, /* Clear ocp alarm , */\ +{ 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ +{ 0x4450, "int_in_flag_man_alarm_state"}, /* clear nanager Alarm state , */\ +{ 0x4460, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ +{ 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ +{ 0x4800, "int_enable_flag_por"}, /* Enable por , */\ +{ 0x4810, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ +{ 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ +{ 0x4830, "int_enable_flag_ocp_alarm"}, /* Enable ocp alarm , */\ +{ 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ +{ 0x4850, "int_enable_flag_man_alarm_state"}, /* Enable nanager Alarm state , */\ +{ 0x4860, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ +{ 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ +{ 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ +{ 0x4c10, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ +{ 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ +{ 0x4c30, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ +{ 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ +{ 0x4c50, "int_polarity_flag_man_alarm_state"}, /* Polarity nanager Alarm state , */\ +{ 0x4c60, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ +{ 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ +{ 0x5001, "vbat_prot_attack_time"}, /* Battery Safeguard attack time , */\ +{ 0x5023, "vbat_prot_thlevel"}, /* Battery Safeguard threshold voltage level , */\ +{ 0x5061, "vbat_prot_max_reduct"}, /* Battery Safeguard maximum reduction , */\ +{ 0x5080, "vbat_flt_limit"}, /* vbat filter limit , */\ +{ 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ +{ 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ +{ 0x50f0, "bypass_clipper"}, /* Bypass battery safeguard , */\ +{ 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ +{ 0x5150, "bypass_hp"}, /* Bypass HPF , */\ +{ 0x5170, "enbl_dpsa"}, /* Enable DPSA , */\ +{ 0x5222, "ctrl_cc"}, /* Clip control setting , */\ +{ 0x5257, "gain"}, /* Amplifier gain , */\ +{ 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ +{ 0x52e0, "ctrl_slope"}, /* Slope speed setting (bin. coded) , */\ +{ 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ +{ 0x5321, "dpsa_release"}, /* DPSA Release time , */\ +{ 0x5340, "clipfast"}, /* Clock selection for HW clipper for Battery Safeguard, */\ +{ 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ +{ 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ +{ 0x5410, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ +{ 0x5430, "icomp_engage"}, /* Engage of icomp , */\ +{ 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ +{ 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ +{ 0x5503, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ +{ 0x5543, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ +{ 0x5582, "dpsa_drive"}, /* Drive setting (bin. coded) , */\ +{ 0x5690, "sel_pwm_delay_src"}, /* Control for selection for PWM delay line source , */\ +{ 0x56a1, "enbl_odd_up_even_down"}, /* Control for PWM reference sawtooth generartion , */\ +{ 0x570a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually, */\ +{ 0x57b0, "enbl_engage"}, /* Enables/engage power stage and control loop , */\ +{ 0x57c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ +{ 0x5810, "hard_mute"}, /* Hard mute - PWM , */\ +{ 0x5820, "pwm_shape"}, /* PWM shape , */\ +{ 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ +{ 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ +{ 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ +{ 0x58c0, "enbl_pwm_phase_shift"}, /* Control for pwm phase shift , */\ +{ 0x6123, "ctrl_attl"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ +{ 0x6163, "ctrl_attr"}, /* Total gain depending on INPLEV setting (channel 0), */\ +{ 0x6265, "zero_lvl"}, /* low noise gain switch zero trigger level , */\ +{ 0x62c1, "ctrl_fb_resistor"}, /* Select amplifier feedback resistor connection , */\ +{ 0x62e1, "lownoisegain_mode"}, /* ctrl select mode , */\ +{ 0x6305, "threshold_lvl"}, /* low noise gain switch trigger level , */\ +{ 0x6365, "hold_time"}, /* ctrl hold time before low audio is reckoned to be low audio, */\ +{ 0x6405, "lpm1_cal_offset"}, /* low power mode1 detector ctrl cal_offset from gain module , */\ +{ 0x6465, "lpm1_zero_lvl"}, /* low power mode1 zero crossing detection level , */\ +{ 0x64e1, "lpm1_mode"}, /* low power mode control , */\ +{ 0x6505, "lpm1_threshold_lvl"}, /* low power mode1 amplitude trigger level , */\ +{ 0x6565, "lpm1_hold_time"}, /* low power mode1 detector ctrl hold time before low audio is reckoned to be low audio, */\ +{ 0x65c0, "disable_low_power_mode"}, /* low power mode1 detector control , */\ +{ 0x6600, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ +{ 0x6611, "dcdc_ctrl_maxzercnt"}, /* DCDC. Number of zero current flags to count before going to pfm mode, */\ +{ 0x6656, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ +{ 0x66c0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ +{ 0x6700, "enbl_minion"}, /* Enables minion (small) power stage , */\ +{ 0x6713, "vth_vddpvbat"}, /* select vddp-vbat thres signal , */\ +{ 0x6750, "lpen_vddpvbat"}, /* select vddp-vbat filtred vs unfiltered compare , */\ +{ 0x6761, "ctrl_rfb"}, /* Feedback resistor selection - I2C direct mode , */\ +{ 0x6802, "tdm_source_mapping"}, /* tdm source mapping , */\ +{ 0x6831, "tdm_sourcea_frame_sel"}, /* Sensed value A , */\ +{ 0x6851, "tdm_sourceb_frame_sel"}, /* Sensed value B , */\ +{ 0x6871, "tdm_source0_clip_sel"}, /* clip information (analog /digital) for source0 , */\ +{ 0x6891, "tdm_source1_clip_sel"}, /* clip information (analog /digital) for source1 , */\ +{ 0x6a02, "rst_min_vbat_delay"}, /* rst_min_vbat delay (nb fs) , */\ +{ 0x6b00, "disable_auto_engage"}, /* disable auto engange , */\ +{ 0x6b10, "disable_engage"}, /* disable engange , */\ +{ 0x6c02, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ +{ 0x6c32, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ +{ 0x6c69, "spare_out"}, /* spare_out , */\ +{ 0x6d0f, "spare_in"}, /* spare_in , */\ +{ 0x6e10, "flag_lp_detect_mode1"}, /* low power mode 1 detection , */\ +{ 0x6e20, "flag_low_amplitude"}, /* low amplitude detection , */\ +{ 0x6e30, "flag_vddp_gt_vbat"}, /* vddp greater than vbat , */\ +{ 0x6f02, "cursense_comp_delay"}, /* delay to allign compensation signal with current sense signal, */\ +{ 0x6f40, "cursense_comp_sign"}, /* polarity of compensation for current sense , */\ +{ 0x6f50, "enbl_cursense_comp"}, /* enable current sense compensation , */\ +{ 0x6f72, "pwms_clip_lvl"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ +{ 0x7033, "boost_cur"}, /* Max coil current , */\ +{ 0x7071, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ +{ 0x7090, "boost_intel"}, /* Adaptive boost mode , */\ +{ 0x70a0, "boost_speed"}, /* Soft ramp up/down , */\ +{ 0x70e0, "dcdcoff_mode"}, /* DCDC on/off , */\ +{ 0x70f0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ +{ 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ +{ 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ +{ 0x7174, "bst_slopecur"}, /* For testing direct control slope current , */\ +{ 0x71c1, "bst_slope"}, /* Boost slope speed , */\ +{ 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ +{ 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ +{ 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ +{ 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ +{ 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ +{ 0x7230, "enbl_bst_peakcur"}, /* Enable peak current , */\ +{ 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage , */\ +{ 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ +{ 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ +{ 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ +{ 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ +{ 0x7290, "enbl_bst_windac"}, /* Enable window dac , */\ +{ 0x72a5, "bst_windac"}, /* for testing direct control windac , */\ +{ 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ +{ 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ +{ 0x7331, "bst_freq"}, /* DCDC boost frequency control , */\ +{ 0x7360, "bst_use_new_zercur_detect"}, /* Enable new zero current detection for boost control, */\ +{ 0x7430, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ +{ 0x7444, "boost_trip_lvl_1st"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7494, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ +{ 0x74e0, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ +{ 0x74f0, "ignore_flag_voutcomp86"}, /* Determines the maximum PWM frequency be the most efficient in relation to the Booster inductor value, */\ +{ 0x7534, "boost_trip_lvl_2nd"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ +{ 0x7584, "boost_trip_lvl_track"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ +{ 0x75f0, "enbl_trip_hyst"}, /* Enable hysteresis on booster trip levels , */\ +{ 0x7635, "frst_boost_voltage"}, /* First boost voltage level , */\ +{ 0x7695, "scnd_boost_voltage"}, /* Second boost voltage level , */\ +{ 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ +{ 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ +{ 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ +{ 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ +{ 0x8087, "cs_gain"}, /* Current sense gain , */\ +{ 0x8210, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ +{ 0x8305, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP)*signal, */\ +{ 0x8364, "cs_ktemp2"}, /* Second order temperature compensation coefficient , */\ +{ 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ +{ 0x8421, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ +{ 0x8440, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ +{ 0x8453, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ +{ 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ +{ 0x84a4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ +{ 0x8500, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ +{ 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ +{ 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ +{ 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ +{ 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ +{ 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ +{ 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ +{ 0x8700, "enbl_cs_adc"}, /* Enable current sense ADC , */\ +{ 0x8710, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 , */\ +{ 0x8720, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 , */\ +{ 0x8730, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ +{ 0x8740, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 , */\ +{ 0x8750, "enbl_cs_ldo"}, /* Enable current sense LDO , */\ +{ 0x8780, "enbl_cs_vbatldo"}, /* Enable of current sense LDO , */\ +{ 0x8790, "enbl_dc_filter"}, /* Control for enabling the DC blocking filter for voltage and current sense, */\ +{ 0x8801, "volsense_pwm_sel"}, /* Voltage sense source selection control , */\ +{ 0x8850, "vs_gain_control"}, /* Voltage sense gain control , */\ +{ 0x8860, "vs_bypass_gc"}, /* Bypasses the VS gain correction , */\ +{ 0x8870, "vs_igen_supply"}, /* Switch internal supply of current generator , */\ +{ 0x8887, "vs_gain"}, /* voltage sense gain , */\ +{ 0x8c00, "vs_adc_bsoinv"}, /* Bitstream inversion for voltage sense ADC , */\ +{ 0x8c40, "vs_adc_nortz"}, /* Return to zero for voltage sense ADC , */\ +{ 0x8c90, "vs_adc_slowdel"}, /* Select delay for voltage sense ADC (internal decision circuitry), */\ +{ 0x8d10, "vs_classd_tran_skip"}, /* Skip voltage sense connection during a classD amplifier transition, */\ +{ 0x8d30, "vs_inn_short"}, /* Short voltage sense negative to common mode , */\ +{ 0x8d40, "vs_inp_short"}, /* Short voltage sense positive to common mode , */\ +{ 0x8d50, "vs_ldo_bypass"}, /* Bypass voltage sense LDO , */\ +{ 0x8d60, "vs_ldo_pulldown"}, /* Pull down voltage sense LDO, only valid if left_enbl_cs_ldo is high, */\ +{ 0x8d74, "vs_ldo_voset"}, /* Voltage sense LDO voltage level setting (two's complement), */\ +{ 0x8f00, "enbl_vs_adc"}, /* Enable voltage sense ADC (Direct Control only only others done by manager), */\ +{ 0x8f10, "enbl_vs_inn1"}, /* Enable connection of voltage sense negative1 , */\ +{ 0x8f20, "enbl_vs_inn2"}, /* Enable connection of voltage sense negative2 , */\ +{ 0x8f30, "enbl_vs_inp1"}, /* Enable connection of voltage sense positive1 , */\ +{ 0x8f40, "enbl_vs_inp2"}, /* Enable connection of voltage sense positive2 , */\ +{ 0x8f50, "enbl_vs_ldo"}, /* Enable voltage sense LDO (Direct Control only only others done by manager), */\ +{ 0x8f80, "enbl_vs_vbatldo"}, /* Enable of voltage sense LDO (Direct Control only others done by manager), */\ +{ 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ +{ 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ +{ 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ +{ 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ +{ 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ +{ 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ +{ 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ +{ 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ +{ 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ +{ 0xa400, "faim_set_clkws"}, /* Sets the faim controller clock wait state register, */\ +{ 0xa410, "faim_sel_evenrows"}, /* All even rows of the faim are selected, active high, */\ +{ 0xa420, "faim_sel_oddrows"}, /* All odd rows of the faim are selected, all rows in combination with sel_evenrows, */\ +{ 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ +{ 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ +{ 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ +{ 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ +{ 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ +{ 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ +{ 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ +{ 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ +{ 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ +{ 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ +{ 0xb050, "bypass_otp"}, /* Bypass OTP , */\ +{ 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ +{ 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ +{ 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ +{ 0xb108, "ext_temp"}, /* External temperature (C) , */\ +{ 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ +{ 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ +{ 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ +{ 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ +{ 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ +{ 0xc0c0, "use_direct_vs_ctrls"}, /* voltage sense Direct control to overrule several functions for testing, */\ +{ 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ +{ 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ +{ 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ +{ 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ +{ 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ +{ 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ +{ 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ +{ 0xc300, "bypasslatch"}, /* Bypass latch , */\ +{ 0xc311, "sourcea"}, /* Set OUTA to , */\ +{ 0xc331, "sourceb"}, /* Set OUTB to , */\ +{ 0xc350, "inverta"}, /* Invert pwma test signal , */\ +{ 0xc360, "invertb"}, /* Invert pwmb test signal , */\ +{ 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ +{ 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ +{ 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ +{ 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ +{ 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ +{ 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ +{ 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ +{ 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ +{ 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ +{ 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ +{ 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ +{ 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ +{ 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ +{ 0xc510, "test_discrete"}, /* Test function noise measurement , */\ +{ 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ +{ 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ +{ 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ +{ 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ +{ 0xc580, "test_enbl_vs"}, /* Enable for digimux mode of voltage sense , */\ +{ 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ +{ 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ +{ 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ +{ 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to DATAO (see Digimux list for details), */\ +{ 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to INT (see Digimux list for details), */\ +{ 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to PDMDAT (see Digimux list for details), */\ +{ 0xc981, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xc9c0, "hs_mode"}, /* I2C high speed mode control , */\ +{ 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ +{ 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ +{ 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ +{ 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ +{ 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ +{ 0xcb04, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ +{ 0xcb53, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ +{ 0xcba3, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ +{ 0xcd05, "pll_seli"}, /* PLL SELI - I2C direct PLL control mode only , */\ +{ 0xcd64, "pll_selp"}, /* PLL SELP - I2C direct PLL control mode only , */\ +{ 0xcdb3, "pll_selr"}, /* PLL SELR - I2C direct PLL control mode only , */\ +{ 0xcdf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ +{ 0xce09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ +{ 0xcea0, "pll_mdec_msb"}, /* MSB of pll_mdec - I2C direct PLL control mode only, */\ +{ 0xceb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ +{ 0xcec0, "enbl_osc"}, /* Enables OSC1M in I2C direct control mode only , */\ +{ 0xced0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ +{ 0xcee0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ +{ 0xcef0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ +{ 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ +{ 0xd006, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ +{ 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ +{ 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ +{ 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ +{ 0xd283, "tsig_gain"}, /* Test signal gain , */\ +{ 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ +{ 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ +{ 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ +{ 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ +{ 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ +{ 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ +{ 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ +{ 0xd507, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ +{ 0xd580, "enbl_clk_out_of_range"}, /* Clock out of range , */\ +{ 0xd621, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ +{ 0xd641, "clkdiv_muxa_sel"}, /* DCDC MUXA clock divider selection in direct clock control mode, */\ +{ 0xd661, "clkdiv_muxb_sel"}, /* DCDC MUXB clock divider selection in direct clock control mode, */\ +{ 0xd721, "datao_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ +{ 0xd740, "bck_ehs"}, /* High-speed and standard/fast mode selection for BCK IO cell (see IIC3V3 IO cell datasheet), */\ +{ 0xd750, "datai_ehs"}, /* High-speed and standard/fast mode selection for DATAI IO cell (see IIC3V3 IO cell datasheet), */\ +{ 0xd800, "source_in_testmode"}, /* tdm source in test mode (return only current and voltage sense), */\ +{ 0xd810, "gainatt_feedback"}, /* gainatt feedback to tdm , */\ +{ 0xd822, "test_parametric_io"}, /* test io parametric , */\ +{ 0xd850, "ctrl_bst_clk_lp1"}, /* boost clock control in low power mode1 , */\ +{ 0xd861, "test_spare_out1"}, /* test spare out 1 , */\ +{ 0xd880, "bst_dcmbst"}, /* dcm boost , */\ +{ 0xd8c3, "test_spare_out2"}, /* test spare out 1 , */\ +{ 0xee0f, "sw_profile"}, /* Software profile data , */\ +{ 0xef0f, "sw_vstep"}, /* Software vstep information , */\ +{ 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ +{ 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ +{ 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ +{ 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ +{ 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ +{ 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ +{ 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ +{ 0xf169, "spare_mpt1_15_6"}, /* SPARE , */\ +{ 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ +{ 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ +{ 0xf2a5, "spare_mtp2_15_10"}, /* SPARE , */\ +{ 0xf307, "calibr_gain_vs"}, /* Voltage sense gain , */\ +{ 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ +{ 0xf407, "spare_mtp4_15_0"}, /* SPARE , */\ +{ 0xf487, "vs_trim"}, /* VS Trimming , */\ +{ 0xf50f, "calibr_R25C_R"}, /* Ron resistance of speaker coil , */\ +{ 0xf60f, "spare_mpt6_6_0"}, /* SPARE , */\ +{ 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ +{ 0xf770, "spare_mtp7_07"}, /* SPARE , */\ +{ 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ +{ 0xf7f0, "spare_mtp7_15"}, /* SPARE , */\ +{ 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ +{ 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ +{ 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ +{ 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ +{ 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable function dcdcoff_mode , */\ +{ 0xf910, "spare_mtp9_1"}, /* SPARE , */\ +{ 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ +{ 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Force Boost in follower mode , */\ +{ 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ +{ 0xf980, "spare_mtp9_8"}, /* SPARE , */\ +{ 0xf990, "mtp_enbl_pwm_delay_clock_gating"}, /* pwm delay clock auto gating , */\ +{ 0xf9a0, "mtp_enbl_ocp_clock_gating"}, /* ocpclock auto gating , */\ +{ 0xf9b0, "mtp_gate_cgu_clock_for_test"}, /* cgu test clock control , */\ +{ 0xf9c0, "mtp_tdm_pad_sel"}, /* tdm pad selection , */\ +{ 0xf9d2, "spare_mtp9_15_12"}, /* MTP-control FW - See Firmware I2C API document for details, */\ +{ 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ +{ 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ +{ 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ +{ 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ +{ 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ +{ 0xff07, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ +{ 0xff87, "spare_mtp7_15_08"}, /* SPARE , */\ +{ 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa9874_irq { + tfa9874_irq_stvdds = 0, + tfa9874_irq_stbstoc = 1, + tfa9874_irq_stotds = 2, + tfa9874_irq_stocpr = 3, + tfa9874_irq_stuvds = 4, + tfa9874_irq_stmanalarm = 5, + tfa9874_irq_sttdmer = 6, + tfa9874_irq_stnoclk = 7, + tfa9874_irq_max = 8, + tfa9874_irq_all = -1 /* all irqs */}; + +#define TFA9874_IRQ_NAMETABLE static tfaIrqName_t Tfa9874IrqNames[] = {\ + { 0, "STVDDS"},\ + { 1, "STBSTOC"},\ + { 2, "STOTDS"},\ + { 3, "STOCPR"},\ + { 4, "STUVDS"},\ + { 5, "STMANALARM"},\ + { 6, "STTDMER"},\ + { 7, "STNOCLK"},\ + { 8, "8"},\ +}; +#endif /* _TFA9874_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa9878_tfafieldnames.h b/sound/soc/codecs/tfa9878_tfafieldnames.h new file mode 100644 index 000000000000..f626372b07c9 --- /dev/null +++ b/sound/soc/codecs/tfa9878_tfafieldnames.h @@ -0,0 +1,973 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9878_TFAFIELDNAMES_H +#define _TFA9878_TFAFIELDNAMES_H + + +#define TFA9878_I2CVERSION 12 + +typedef enum nxpTfa9878BfEnumList { + TFA9878_BF_PWDN = 0x0000, /*!< Powerdown selection */ + TFA9878_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA9878_BF_AMPE = 0x0030, /*!< Activate Amplifier */ + TFA9878_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ + TFA9878_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA9878_BF_FSSSEL = 0x0090, /*!< Audio sample reference */ + TFA9878_BF_BYPOCP = 0x00b0, /*!< Bypass OCP */ + TFA9878_BF_TSTOCP = 0x00c0, /*!< OCP testing control */ + TFA9878_BF_AMPINSEL = 0x0101, /*!< Amplifier input selection */ + TFA9878_BF_MANSCONF = 0x0120, /*!< I2C configured */ + TFA9878_BF_DCINSEL = 0x0131, /*!< VAMP_OUT2 input selection */ + TFA9878_BF_MUTETO = 0x0160, /*!< Time out SB mute sequence */ + TFA9878_BF_MANROBOD = 0x0170, /*!< Reaction on BOD */ + TFA9878_BF_BODE = 0x0180, /*!< Enable BOD (only in direct control mode) */ + TFA9878_BF_BODHYS = 0x0190, /*!< Enable Hysteresis of BOD */ + TFA9878_BF_BODFILT = 0x01a1, /*!< BOD filter */ + TFA9878_BF_BODTHLVL = 0x01c1, /*!< BOD threshold */ + TFA9878_BF_OPENMTP = 0x01e0, /*!< Control for FAIM protection */ + TFA9878_BF_DISFCRBST = 0x01f0, /*!< disable boost control with FRCBST */ + TFA9878_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ + TFA9878_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ + TFA9878_BF_FRACTDEL = 0x0255, /*!< V/I Fractional delay */ + TFA9878_BF_AMPINPSEL = 0x02b1, /*!< amp input selection */ + TFA9878_BF_PDMRATE = 0x02d0, /*!< Pdm rate */ + TFA9878_BF_REV = 0x030f, /*!< Revision info */ + TFA9878_BF_REFCKEXT = 0x0401, /*!< PLL external ref clock */ + TFA9878_BF_REFCKSEL = 0x0420, /*!< PLL internal ref clock */ + TFA9878_BF_SWCLKSEL = 0x0432, /*!< Sound Wire clock frequnecy */ + TFA9878_BF_MANAOOSC = 0x0460, /*!< Internal osc off at PWDN */ + TFA9878_BF_FSSYNCEN = 0x0480, /*!< Enable FS synchronisation for clock divider */ + TFA9878_BF_CLKREFSYNCEN = 0x0490, /*!< Enable PLL reference clock synchronisation for clock divider */ + TFA9878_BF_AUTOFROSEL = 0x04a0, /*!< override automatic OSC selection mechanism */ + TFA9878_BF_SWFRSYNC = 0x04b0, /*!< Selection SW signal reference for Stream Synchronization */ + TFA9878_BF_CGUSYNCDCG = 0x0500, /*!< Clock gating control for CGU synchronisation module */ + TFA9878_BF_FRCCLKSPKR = 0x0510, /*!< force active the speaker sub-system clock when in idle power */ + TFA9878_BF_SSFAIME = 0x05c0, /*!< Sub-system FAIM */ + TFA9878_BF_CLKCHKLO = 0x0707, /*!< Clock check Low Threshold */ + TFA9878_BF_CLKCHKHI = 0x0787, /*!< Clock check Higher Threshold */ + TFA9878_BF_AMPOCRT = 0x0802, /*!< Amplifier on-off criteria for shutdown */ + TFA9878_BF_VDDS = 0x1000, /*!< POR */ + TFA9878_BF_DCOCPOK = 0x1010, /*!< DCDC OCP nmos (sticky register , clear on read) */ + TFA9878_BF_OTDS = 0x1020, /*!< OTP alarm (sticky register , clear on read) */ + TFA9878_BF_OCDS = 0x1030, /*!< OCP amplifier (sticky register , clear on read) */ + TFA9878_BF_UVDS = 0x1040, /*!< UVP alarm (sticky register , clear on read) */ + TFA9878_BF_MANALARM = 0x1050, /*!< Alarm state */ + TFA9878_BF_CLKS = 0x1060, /*!< Clocks stable */ + TFA9878_BF_MTPB = 0x1070, /*!< MTP busy */ + TFA9878_BF_NOCLK = 0x1080, /*!< Lost clock (sticky register , clear on read) */ + TFA9878_BF_BODNOK = 0x1090, /*!< BOD Flag - VDD NOT OK */ + TFA9878_BF_TDMERR = 0x10a0, /*!< TDM error */ + TFA9878_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA9878_BF_DCDCA = 0x1110, /*!< DCDC active (sticky register , clear on read) */ + TFA9878_BF_DCDCPC = 0x1120, /*!< Indicates current is max in DC-to-DC converter */ + TFA9878_BF_DCHVBAT = 0x1130, /*!< DCDC level 1x */ + TFA9878_BF_DCH114 = 0x1140, /*!< DCDC level 1.14x */ + TFA9878_BF_DCH107 = 0x1150, /*!< DCDC level 1.07x */ + TFA9878_BF_PLLS = 0x1160, /*!< PLL lock */ + TFA9878_BF_TDMLUTER = 0x1180, /*!< TDM LUT error */ + TFA9878_BF_CLKOOR = 0x11c0, /*!< External clock status */ + TFA9878_BF_SWS = 0x11d0, /*!< Amplifier engage */ + TFA9878_BF_AMPS = 0x11e0, /*!< Amplifier enable */ + TFA9878_BF_AREFS = 0x11f0, /*!< References enable */ + TFA9878_BF_OCPOAP = 0x1300, /*!< OCPOK pmos B */ + TFA9878_BF_OCPOAN = 0x1310, /*!< OCPOK pmos A */ + TFA9878_BF_OCPOBP = 0x1320, /*!< OCPOK nmos B */ + TFA9878_BF_OCPOBN = 0x1330, /*!< OCPOK nmos A */ + TFA9878_BF_OVDS = 0x1380, /*!< OVP alarm */ + TFA9878_BF_CLIPS = 0x1390, /*!< Amplifier clipping */ + TFA9878_BF_ADCCR = 0x13a0, /*!< Control ADC */ + TFA9878_BF_MANWAIT1 = 0x13c0, /*!< Wait HW I2C settings */ + TFA9878_BF_MANMUTE = 0x13e0, /*!< Audio mute sequence */ + TFA9878_BF_MANOPER = 0x13f0, /*!< Operating state */ + TFA9878_BF_TDMSTAT = 0x1402, /*!< TDM status bits */ + TFA9878_BF_MANSTATE = 0x1433, /*!< Device manager status */ + TFA9878_BF_AMPSTE = 0x1473, /*!< Amplifier control status */ + TFA9878_BF_DCMODE = 0x14b1, /*!< DCDC mode status bits */ + TFA9878_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA9878_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA9878_BF_VDDPS = 0x1709, /*!< IC VDDP voltage ( 1023*VDDP/13 V) */ + TFA9878_BF_TDME = 0x2000, /*!< Enable interface */ + TFA9878_BF_TDMSLOTS = 0x2013, /*!< N-slots in Frame */ + TFA9878_BF_TDMCLINV = 0x2060, /*!< Reception data to BCK clock */ + TFA9878_BF_TDMFSLN = 0x2073, /*!< FS length */ + TFA9878_BF_TDMFSPOL = 0x20b0, /*!< FS polarity */ + TFA9878_BF_TDMNBCK = 0x20c3, /*!< N-BCK's in FS */ + TFA9878_BF_TDMSLLN = 0x2144, /*!< N-bits in slot */ + TFA9878_BF_TDMBRMG = 0x2194, /*!< N-bits remaining */ + TFA9878_BF_TDMDEL = 0x21e0, /*!< data delay to FS */ + TFA9878_BF_TDMADJ = 0x21f0, /*!< data adjustment */ + TFA9878_BF_TDMOOMP = 0x2201, /*!< Received audio compression */ + TFA9878_BF_TDMSSIZE = 0x2224, /*!< Sample size per slot */ + TFA9878_BF_TDMTXDFO = 0x2271, /*!< Format unused bits */ + TFA9878_BF_TDMTXUS0 = 0x2291, /*!< Format unused slots DATAO */ + TFA9878_BF_TDMSPKE = 0x2300, /*!< Control audio tdm channel in 0 */ + TFA9878_BF_TDMDCE = 0x2310, /*!< Control audio tdm channel in 1 */ + TFA9878_BF_TDMCSE = 0x2330, /*!< current sense vbat temperature and vddp feedback */ + TFA9878_BF_TDMVSE = 0x2340, /*!< Voltage sense vbat temperature and vddp feedback */ + TFA9878_BF_TDMSPKS = 0x2603, /*!< tdm slot for sink 0 */ + TFA9878_BF_TDMDCS = 0x2643, /*!< tdm slot for sink 1 */ + TFA9878_BF_TDMCSS = 0x26c3, /*!< Slot Position of current sense vbat temperature and vddp feedback */ + TFA9878_BF_TDMVSS = 0x2703, /*!< Slot Position of Voltage sense vbat temperature and vddp feedback */ + TFA9878_BF_ISTVDDS = 0x4000, /*!< Status POR */ + TFA9878_BF_ISTBSTOC = 0x4010, /*!< Status DCDC OCP */ + TFA9878_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ + TFA9878_BF_ISTOCPR = 0x4030, /*!< Status ocp alarm */ + TFA9878_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ + TFA9878_BF_ISTMANALARM = 0x4050, /*!< Status nanager Alarm state */ + TFA9878_BF_ISTTDMER = 0x4060, /*!< Status tdm error */ + TFA9878_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ + TFA9878_BF_ISTBODNOK = 0x4080, /*!< Status BOD event */ + TFA9878_BF_ICLVDDS = 0x4400, /*!< Clear POR */ + TFA9878_BF_ICLBSTOC = 0x4410, /*!< Clear DCDC OCP */ + TFA9878_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ + TFA9878_BF_ICLOCPR = 0x4430, /*!< Clear ocp alarm */ + TFA9878_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ + TFA9878_BF_ICLMANALARM = 0x4450, /*!< Clear manager Alarm state */ + TFA9878_BF_ICLTDMER = 0x4460, /*!< Clear tdm error */ + TFA9878_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ + TFA9878_BF_ICLBODNOK = 0x4480, /*!< Clear BOD event */ + TFA9878_BF_IEVDDS = 0x4800, /*!< Enable por */ + TFA9878_BF_IEBSTOC = 0x4810, /*!< Enable DCDC OCP */ + TFA9878_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ + TFA9878_BF_IEOCPR = 0x4830, /*!< Enable ocp alarm */ + TFA9878_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ + TFA9878_BF_IEMANALARM = 0x4850, /*!< Enable nanager Alarm state */ + TFA9878_BF_IETDMER = 0x4860, /*!< Enable tdm error */ + TFA9878_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ + TFA9878_BF_IEBODNOK = 0x4880, /*!< Enable BOD trigger */ + TFA9878_BF_IPOVDDS = 0x4c00, /*!< Polarity por */ + TFA9878_BF_IPOBSTOC = 0x4c10, /*!< Polarity DCDC OCP */ + TFA9878_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ + TFA9878_BF_IPOOCPR = 0x4c30, /*!< Polarity ocp alarm */ + TFA9878_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ + TFA9878_BF_IPOMANALARM = 0x4c50, /*!< Polarity nanager Alarm state */ + TFA9878_BF_IPOTDMER = 0x4c60, /*!< Polarity tdm error */ + TFA9878_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ + TFA9878_BF_IPOBODNOK = 0x4c80, /*!< Polarity BOD trigger */ + TFA9878_BF_BSSCR = 0x5001, /*!< Battery Safeguard attack time (with K = 1 at sample rate fs of 32kHz, 44,1 kHz or 48kHz ; with K = 2 at sample rate fs 16 kHz . With K =0.5 at sample rate of 96 kHz) */ + TFA9878_BF_BSST = 0x5023, /*!< Battery Safeguard threshold voltage level */ + TFA9878_BF_BSSRL = 0x5061, /*!< Battery Safeguard maximum reduction */ + TFA9878_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA9878_BF_BSSBY = 0x50f0, /*!< Bypass battery safeguard */ + TFA9878_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ + TFA9878_BF_HPFBYP = 0x5150, /*!< Bypass HPF */ + TFA9878_BF_DPSA = 0x5170, /*!< Enable DPSA */ + TFA9878_BF_CLIPCTRL = 0x5222, /*!< Clip control setting */ + TFA9878_BF_AMPGAIN = 0x5257, /*!< Amplifier gain */ + TFA9878_BF_SLOPEE = 0x52d0, /*!< Enables slope control */ + TFA9878_BF_SLOPESET = 0x52e0, /*!< Slope speed setting (bin. coded) */ + TFA9878_BF_BYPDLYLINE = 0x52f0, /*!< Bypass the interpolator delay line */ + TFA9878_BF_TDMDCG = 0x5f23, /*!< Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE) */ + TFA9878_BF_TDMSPKG = 0x5f63, /*!< Total gain depending on INPLEV setting (channel 0) */ + TFA9878_BF_IPM = 0x60e1, /*!< Idle power mode control */ + TFA9878_BF_LNMODE = 0x62e1, /*!< ctrl select mode */ + TFA9878_BF_LPM1MODE = 0x64e1, /*!< low power mode control */ + TFA9878_BF_TDMSRCMAP = 0x6802, /*!< tdm source mapping */ + TFA9878_BF_TDMSRCAS = 0x6831, /*!< Sensed value A */ + TFA9878_BF_TDMSRCBS = 0x6851, /*!< Sensed value B */ + TFA9878_BF_TDMSRCACLIP = 0x6871, /*!< clip information (analog /digital) for source0 */ + TFA9878_BF_TDMSRCBCLIP = 0x6891, /*!< clip information (analog /digital) for source1 */ + TFA9878_BF_LP0 = 0x6e00, /*!< Idle power mode */ + TFA9878_BF_LP1 = 0x6e10, /*!< low power mode 1 detection */ + TFA9878_BF_LA = 0x6e20, /*!< low amplitude detection */ + TFA9878_BF_VDDPH = 0x6e30, /*!< vddp greater than vbat */ + TFA9878_BF_DELCURCOMP = 0x6f02, /*!< delay to allign compensation signal with current sense signal */ + TFA9878_BF_SIGCURCOMP = 0x6f40, /*!< polarity of compensation for current sense */ + TFA9878_BF_ENCURCOMP = 0x6f50, /*!< enable current sense compensation */ + TFA9878_BF_LVLCLPPWM = 0x6f72, /*!< set the amount of pwm pulse that may be skipped before clip-flag is triggered */ + TFA9878_BF_DCMCC = 0x7003, /*!< Max coil current */ + TFA9878_BF_DCCV = 0x7041, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ + TFA9878_BF_DCIE = 0x7060, /*!< Adaptive boost mode */ + TFA9878_BF_DCSR = 0x7070, /*!< Soft ramp up/down */ + TFA9878_BF_DCOVL = 0x7085, /*!< Threshold level to activate active overshoot control */ + TFA9878_BF_DCDIS = 0x70e0, /*!< DCDC on/off */ + TFA9878_BF_DCPWM = 0x70f0, /*!< DCDC PWM only mode */ + TFA9878_BF_DCTRACK = 0x7430, /*!< Boost algorithm selection, effective only when boost_intelligent is set to 1 */ + TFA9878_BF_DCTRIP = 0x7444, /*!< 1st Adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9878_BF_DCHOLD = 0x7494, /*!< Hold time for DCDC booster, effective only when boost_intelligent is set to 1 */ + TFA9878_BF_DCINT = 0x74e0, /*!< Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1 */ + TFA9878_BF_DCTRIP2 = 0x7534, /*!< 2nd Adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9878_BF_DCTRIPT = 0x7584, /*!< Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ + TFA9878_BF_DCTRIPHYSTE = 0x75f0, /*!< Enable hysteresis on booster trip levels */ + TFA9878_BF_DCVOF = 0x7635, /*!< First boost voltage level */ + TFA9878_BF_DCVOS = 0x7695, /*!< Second boost voltage level */ + TFA9878_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ + TFA9878_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ + TFA9878_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ + TFA9878_BF_MTPADDR = 0xa302, /*!< MTP address from I2C register for read/writing mtp in manual single word mode */ + TFA9878_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ + TFA9878_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ + TFA9878_BF_MTPWRMSB = 0xa70f, /*!< MSB word of write data for MTP manual write */ + TFA9878_BF_MTPWRLSB = 0xa80f, /*!< LSB word of write data for MTP manual write */ + TFA9878_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA9878_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA9878_BF_PLLINSI = 0xcd05, /*!< PLL INSELI - PLL direct bandwidth control mode only with pll_bandsel set to 1 */ + TFA9878_BF_PLLINSP = 0xcd64, /*!< PLL INSELP - PLL direct bandwidth control mode only with pll_bandsel set to 1 */ + TFA9878_BF_PLLINSR = 0xcdb3, /*!< PLL INSELR - PLL direct bandwidth control mode only with pll_bandsel set to 1 */ + TFA9878_BF_PLLBDSEL = 0xcdf0, /*!< PLL bandwidth selection control, USE WITH CAUTION */ + TFA9878_BF_PLLNDEC = 0xce09, /*!< PLL NDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLMDECM = 0xcea0, /*!< MSB of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLBP = 0xceb0, /*!< PLL bypass control during functional mode */ + TFA9878_BF_PLLDI = 0xcec0, /*!< PLL directi control in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLDO = 0xced0, /*!< PLL directo control in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLCLKSTB = 0xcee0, /*!< PLL FRM clock stable control in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLFRM = 0xcef0, /*!< PLL free running mode control in functional mode */ + TFA9878_BF_PLLMDECL = 0xcf0f, /*!< Bits 15..0 of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLPDEC = 0xd006, /*!< PLL PDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9878_BF_PLLDCTRL = 0xd070, /*!< Enabled PLL direct control mode, overrules the PLL LUT with I2C register values */ + TFA9878_BF_PLLLIMOFF = 0xd090, /*!< PLL up limiter control in PLL direct bandwidth control mode, pll_bandsel set to 1 */ + TFA9878_BF_PLLSTRTM = 0xd0a2, /*!< PLL startup time selection control */ + TFA9878_BF_SWPROFIL = 0xe00f, /*!< Software profile data */ + TFA9878_BF_SWVSTEP = 0xe10f, /*!< Software vstep information */ + TFA9878_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ + TFA9878_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA9878_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ + TFA9878_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA9878_BF_USERDEF = 0xf042, /*!< Calibration delta current limit DCDC */ + TFA9878_BF_CUSTINFO = 0xf078, /*!< Reserved space for allowing customer to store speaker information */ + TFA9878_BF_R25C = 0xf50f, /*!< Ron resistance of speaker coil */ +} nxpTfa9878BfEnumList_t; +#define TFA9878_NAMETABLE static tfaBfName_t Tfa9878DatasheetNames[] = {\ + { 0x0, "PWDN"}, /* Powerdown selection , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x30, "AMPE"}, /* Activate Amplifier , */\ + { 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0x90, "FSSSEL"}, /* Audio sample reference , */\ + { 0xb0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xc0, "TSTOCP"}, /* OCP testing control , */\ + { 0x101, "AMPINSEL"}, /* Amplifier input selection , */\ + { 0x120, "MANSCONF"}, /* I2C configured , */\ + { 0x131, "DCINSEL"}, /* VAMP_OUT2 input selection , */\ + { 0x160, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x170, "MANROBOD"}, /* Reaction on BOD , */\ + { 0x180, "BODE"}, /* Enable BOD (only in direct control mode) , */\ + { 0x190, "BODHYS"}, /* Enable Hysteresis of BOD , */\ + { 0x1a1, "BODFILT"}, /* BOD filter , */\ + { 0x1c1, "BODTHLVL"}, /* BOD threshold , */\ + { 0x1e0, "OPENMTP"}, /* Control for FAIM protection , */\ + { 0x1f0, "DISFCRBST"}, /* disable boost control with FRCBST , */\ + { 0x203, "AUDFS"}, /* Sample rate (fs) , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ + { 0x2b1, "AMPINPSEL"}, /* amp input selection , */\ + { 0x2d0, "PDMRATE"}, /* Pdm rate , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ + { 0x432, "SWCLKSEL"}, /* Sound Wire clock frequnecy , */\ + { 0x460, "MANAOOSC"}, /* Internal osc off at PWDN , */\ + { 0x480, "FSSYNCEN"}, /* Enable FS synchronisation for clock divider , */\ + { 0x490, "CLKREFSYNCEN"}, /* Enable PLL reference clock synchronisation for clock divider, */\ + { 0x4a0, "AUTOFROSEL"}, /* override automatic OSC selection mechanism , */\ + { 0x4b0, "SWFRSYNC"}, /* Selection SW signal reference for Stream Synchronization , */\ + { 0x500, "CGUSYNCDCG"}, /* Clock gating control for CGU synchronisation module, */\ + { 0x510, "FRCCLKSPKR"}, /* force active the speaker sub-system clock when in idle power, */\ + { 0x5c0, "SSFAIME"}, /* Sub-system FAIM , */\ + { 0x707, "CLKCHKLO"}, /* Clock check Low Threshold , */\ + { 0x787, "CLKCHKHI"}, /* Clock check Higher Threshold , */\ + { 0x802, "AMPOCRT"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "DCOCPOK"}, /* DCDC OCP nmos (sticky register , clear on read) , */\ + { 0x1020, "OTDS"}, /* OTP alarm (sticky register , clear on read) , */\ + { 0x1030, "OCDS"}, /* OCP amplifier (sticky register , clear on read), */\ + { 0x1040, "UVDS"}, /* UVP alarm (sticky register , clear on read) , */\ + { 0x1050, "MANALARM"}, /* Alarm state , */\ + { 0x1060, "CLKS"}, /* Clocks stable , */\ + { 0x1070, "MTPB"}, /* MTP busy , */\ + { 0x1080, "NOCLK"}, /* Lost clock (sticky register , clear on read) , */\ + { 0x1090, "BODNOK"}, /* BOD Flag - VDD NOT OK , */\ + { 0x10a0, "TDMERR"}, /* TDM error , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active (sticky register , clear on read) , */\ + { 0x1120, "DCDCPC"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1130, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1140, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1150, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1160, "PLLS"}, /* PLL lock , */\ + { 0x1180, "TDMLUTER"}, /* TDM LUT error , */\ + { 0x11c0, "CLKOOR"}, /* External clock status , */\ + { 0x11d0, "SWS"}, /* Amplifier engage , */\ + { 0x11e0, "AMPS"}, /* Amplifier enable , */\ + { 0x11f0, "AREFS"}, /* References enable , */\ + { 0x1300, "OCPOAP"}, /* OCPOK pmos B , */\ + { 0x1310, "OCPOAN"}, /* OCPOK pmos A , */\ + { 0x1320, "OCPOBP"}, /* OCPOK nmos B , */\ + { 0x1330, "OCPOBN"}, /* OCPOK nmos A , */\ + { 0x1380, "OVDS"}, /* OVP alarm , */\ + { 0x1390, "CLIPS"}, /* Amplifier clipping , */\ + { 0x13a0, "ADCCR"}, /* Control ADC , */\ + { 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ + { 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x13f0, "MANOPER"}, /* Operating state , */\ + { 0x1402, "TDMSTAT"}, /* TDM status bits , */\ + { 0x1433, "MANSTATE"}, /* Device manager status , */\ + { 0x1473, "AMPSTE"}, /* Amplifier control status , */\ + { 0x14b1, "DCMODE"}, /* DCDC mode status bits , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x1709, "VDDPS"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ + { 0x2000, "TDME"}, /* Enable interface , */\ + { 0x2013, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2073, "TDMFSLN"}, /* FS length , */\ + { 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ + { 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ + { 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x21e0, "TDMDEL"}, /* data delay to FS , */\ + { 0x21f0, "TDMADJ"}, /* data adjustment , */\ + { 0x2201, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2271, "TDMTXDFO"}, /* Format unused bits , */\ + { 0x2291, "TDMTXUS0"}, /* Format unused slots DATAO , */\ + { 0x2300, "TDMSPKE"}, /* Control audio tdm channel in 0 , */\ + { 0x2310, "TDMDCE"}, /* Control audio tdm channel in 1 , */\ + { 0x2330, "TDMCSE"}, /* current sense vbat temperature and vddp feedback , */\ + { 0x2340, "TDMVSE"}, /* Voltage sense vbat temperature and vddp feedback , */\ + { 0x2603, "TDMSPKS"}, /* tdm slot for sink 0 , */\ + { 0x2643, "TDMDCS"}, /* tdm slot for sink 1 , */\ + { 0x26c3, "TDMCSS"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ + { 0x2703, "TDMVSS"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOCPR"}, /* Status ocp alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTMANALARM"}, /* Status nanager Alarm state , */\ + { 0x4060, "ISTTDMER"}, /* Status tdm error , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4080, "ISTBODNOK"}, /* Status BOD event , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOCPR"}, /* Clear ocp alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLMANALARM"}, /* Clear manager Alarm state , */\ + { 0x4460, "ICLTDMER"}, /* Clear tdm error , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4480, "ICLBODNOK"}, /* Clear BOD event , */\ + { 0x4800, "IEVDDS"}, /* Enable por , */\ + { 0x4810, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOCPR"}, /* Enable ocp alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IEMANALARM"}, /* Enable nanager Alarm state , */\ + { 0x4860, "IETDMER"}, /* Enable tdm error , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4880, "IEBODNOK"}, /* Enable BOD trigger , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity por , */\ + { 0x4c10, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOCPR"}, /* Polarity ocp alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOMANALARM"}, /* Polarity nanager Alarm state , */\ + { 0x4c60, "IPOTDMER"}, /* Polarity tdm error , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4c80, "IPOBODNOK"}, /* Polarity BOD trigger , */\ + { 0x5001, "BSSCR"}, /* Battery Safeguard attack time (with K = 1 at sample rate fs of 32kHz, 44,1 kHz or 48kHz ; with K = 2 at sample rate fs 16 kHz . With K =0.5 at sample rate of 96 kHz), */\ + { 0x5023, "BSST"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery Safeguard maximum reduction , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass battery safeguard , */\ + { 0x5100, "BSSS"}, /* Vbat prot steepness , */\ + { 0x5150, "HPFBYP"}, /* Bypass HPF , */\ + { 0x5170, "DPSA"}, /* Enable DPSA , */\ + { 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x52d0, "SLOPEE"}, /* Enables slope control , */\ + { 0x52e0, "SLOPESET"}, /* Slope speed setting (bin. coded) , */\ + { 0x52f0, "BYPDLYLINE"}, /* Bypass the interpolator delay line , */\ + { 0x5f23, "TDMDCG"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5f63, "TDMSPKG"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x60e1, "IPM"}, /* Idle power mode control , */\ + { 0x62e1, "LNMODE"}, /* ctrl select mode , */\ + { 0x64e1, "LPM1MODE"}, /* low power mode control , */\ + { 0x6802, "TDMSRCMAP"}, /* tdm source mapping , */\ + { 0x6831, "TDMSRCAS"}, /* Sensed value A , */\ + { 0x6851, "TDMSRCBS"}, /* Sensed value B , */\ + { 0x6871, "TDMSRCACLIP"}, /* clip information (analog /digital) for source0 , */\ + { 0x6891, "TDMSRCBCLIP"}, /* clip information (analog /digital) for source1 , */\ + { 0x6e00, "LP0"}, /* Idle power mode , */\ + { 0x6e10, "LP1"}, /* low power mode 1 detection , */\ + { 0x6e20, "LA"}, /* low amplitude detection , */\ + { 0x6e30, "VDDPH"}, /* vddp greater than vbat , */\ + { 0x6f02, "DELCURCOMP"}, /* delay to allign compensation signal with current sense signal, */\ + { 0x6f40, "SIGCURCOMP"}, /* polarity of compensation for current sense , */\ + { 0x6f50, "ENCURCOMP"}, /* enable current sense compensation , */\ + { 0x6f72, "LVLCLPPWM"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7003, "DCMCC"}, /* Max coil current , */\ + { 0x7041, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7060, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7070, "DCSR"}, /* Soft ramp up/down , */\ + { 0x7085, "DCOVL"}, /* Threshold level to activate active overshoot control, */\ + { 0x70e0, "DCDIS"}, /* DCDC on/off , */\ + { 0x70f0, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x7430, "DCTRACK"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7444, "DCTRIP"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7494, "DCHOLD"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x74e0, "DCINT"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x7534, "DCTRIP2"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7584, "DCTRIPT"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x75f0, "DCTRIPHYSTE"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7635, "DCVOF"}, /* First boost voltage level , */\ + { 0x7695, "DCVOS"}, /* Second boost voltage level , */\ + { 0xa107, "MTPK"}, /* MTP KEY2 register , */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "MTPADDR"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "MTPWRMSB"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "MTPWRLSB"}, /* LSB word of write data for MTP manual write , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xcd05, "PLLINSI"}, /* PLL INSELI - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcd64, "PLLINSP"}, /* PLL INSELP - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcdb3, "PLLINSR"}, /* PLL INSELR - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcdf0, "PLLBDSEL"}, /* PLL bandwidth selection control, USE WITH CAUTION , */\ + { 0xce09, "PLLNDEC"}, /* PLL NDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcea0, "PLLMDECM"}, /* MSB of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xceb0, "PLLBP"}, /* PLL bypass control during functional mode , */\ + { 0xcec0, "PLLDI"}, /* PLL directi control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xced0, "PLLDO"}, /* PLL directo control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcee0, "PLLCLKSTB"}, /* PLL FRM clock stable control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcef0, "PLLFRM"}, /* PLL free running mode control in functional mode , */\ + { 0xcf0f, "PLLMDECL"}, /* Bits 15..0 of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xd006, "PLLPDEC"}, /* PLL PDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xd070, "PLLDCTRL"}, /* Enabled PLL direct control mode, overrules the PLL LUT with I2C register values, */\ + { 0xd090, "PLLLIMOFF"}, /* PLL up limiter control in PLL direct bandwidth control mode, pll_bandsel set to 1, */\ + { 0xd0a2, "PLLSTRTM"}, /* PLL startup time selection control , */\ + { 0xe00f, "SWPROFIL"}, /* Software profile data , */\ + { 0xe10f, "SWVSTEP"}, /* Software vstep information , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "CUSTINFO"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf50f, "R25C"}, /* Ron resistance of speaker coil , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9878_BITNAMETABLE static tfaBfName_t Tfa9878BitNames[] = {\ + { 0x0, "powerdown"}, /* Powerdown selection , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x30, "enbl_amplifier"}, /* Activate Amplifier , */\ + { 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0x90, "fs_pulse_sel"}, /* Audio sample reference , */\ + { 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xc0, "test_ocp"}, /* OCP testing control , */\ + { 0xd0, "sel_man_wait_time"}, /* Manager wait time selection control , */\ + { 0x101, "vamp_sel1"}, /* Amplifier input selection , */\ + { 0x120, "src_set_configured"}, /* I2C configured , */\ + { 0x131, "vamp_sel2"}, /* VAMP_OUT2 input selection , */\ + { 0x160, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x170, "man_enbl_brown"}, /* Reaction on BOD , */\ + { 0x180, "bod_enbl"}, /* Enable BOD (only in direct control mode) , */\ + { 0x190, "bod_hyst_enbl"}, /* Enable Hysteresis of BOD , */\ + { 0x1a1, "bod_delay_set"}, /* BOD filter , */\ + { 0x1c1, "bod_lvl_set"}, /* BOD threshold , */\ + { 0x1e0, "unprotect_faim"}, /* Control for FAIM protection , */\ + { 0x1f0, "disable_frcbst"}, /* disable boost control with FRCBST , */\ + { 0x203, "audio_fs"}, /* Sample rate (fs) , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ + { 0x2b1, "amp_input_sel"}, /* amp input selection , */\ + { 0x2d0, "pdm_rate"}, /* Pdm rate , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ + { 0x432, "sw_clk_sel"}, /* Sound Wire clock frequnecy , */\ + { 0x460, "enbl_osc_auto_off"}, /* Internal osc off at PWDN , */\ + { 0x480, "enbl_fs_sync"}, /* Enable FS synchronisation for clock divider , */\ + { 0x490, "enbl_clkref_sync"}, /* Enable PLL reference clock synchronisation for clock divider, */\ + { 0x4a0, "override_auto_sel_osc"}, /* override automatic OSC selection mechanism , */\ + { 0x4b0, "sw_sync_sel"}, /* Selection SW signal reference for Stream Synchronization , */\ + { 0x500, "disable_cgu_sync_cgate"}, /* Clock gating control for CGU synchronisation module, */\ + { 0x510, "force_spkr_clk"}, /* force active the speaker sub-system clock when in idle power, */\ + { 0x5c0, "enbl_faim_ss"}, /* Sub-system FAIM , */\ + { 0x707, "clkchk_th_lo"}, /* Clock check Low Threshold , */\ + { 0x787, "clkchk_th_hi"}, /* Clock check Higher Threshold , */\ + { 0x802, "ctrl_on2off_criterion"}, /* Amplifier on-off criteria for shutdown , */\ + { 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ + { 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_bst_ocpok"}, /* DCDC OCP nmos (sticky register , clear on read) , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm (sticky register , clear on read) , */\ + { 0x1030, "flag_ocp_alarm"}, /* OCP amplifier (sticky register , clear on read), */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm (sticky register , clear on read) , */\ + { 0x1050, "flag_man_alarm_state"}, /* Alarm state , */\ + { 0x1060, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1070, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1080, "flag_lost_clk"}, /* Lost clock (sticky register , clear on read) , */\ + { 0x1090, "flag_bod_vddd_nok"}, /* BOD Flag - VDD NOT OK , */\ + { 0x10a0, "flag_tdm_error"}, /* TDM error , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active (sticky register , clear on read) , */\ + { 0x1120, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1130, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1140, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1150, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1160, "flag_pll_lock"}, /* PLL lock , */\ + { 0x1180, "flag_tdm_lut_error"}, /* TDM LUT error , */\ + { 0x11c0, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x11d0, "flag_engage"}, /* Amplifier engage , */\ + { 0x11e0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x11f0, "flag_enbl_ref"}, /* References enable , */\ + { 0x1300, "flag_ocpokbp"}, /* OCPOK pmos B , */\ + { 0x1310, "flag_ocpokap"}, /* OCPOK pmos A , */\ + { 0x1320, "flag_ocpokbn"}, /* OCPOK nmos B , */\ + { 0x1330, "flag_ocpokan"}, /* OCPOK nmos A , */\ + { 0x1380, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1390, "flag_clip"}, /* Amplifier clipping , */\ + { 0x13a0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ + { 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x13f0, "flag_man_operating_state"}, /* Operating state , */\ + { 0x1402, "flag_tdm_status"}, /* TDM status bits , */\ + { 0x1433, "man_state"}, /* Device manager status , */\ + { 0x1473, "amp_ctrl_state"}, /* Amplifier control status , */\ + { 0x14b1, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x1709, "vddp_adc"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ + { 0x2000, "tdm_enable"}, /* Enable interface , */\ + { 0x2013, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2073, "tdm_fs_ws_length"}, /* FS length , */\ + { 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ + { 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ + { 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ + { 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2271, "tdm_txdata_format"}, /* Format unused bits , */\ + { 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots DATAO , */\ + { 0x2300, "tdm_sink0_enable"}, /* Control audio tdm channel in 0 , */\ + { 0x2310, "tdm_sink1_enable"}, /* Control audio tdm channel in 1 , */\ + { 0x2330, "tdm_source0_enable"}, /* current sense vbat temperature and vddp feedback , */\ + { 0x2340, "tdm_source1_enable"}, /* Voltage sense vbat temperature and vddp feedback , */\ + { 0x2603, "tdm_sink0_slot"}, /* tdm slot for sink 0 , */\ + { 0x2643, "tdm_sink1_slot"}, /* tdm slot for sink 1 , */\ + { 0x26c3, "tdm_source0_slot"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ + { 0x2703, "tdm_source1_slot"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ocp_alarm"}, /* Status ocp alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_man_alarm_state"}, /* Status nanager Alarm state , */\ + { 0x4060, "int_out_flag_tdm_error"}, /* Status tdm error , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4080, "int_out_flag_bod_vddd_nok"}, /* Status BOD event , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ocp_alarm"}, /* Clear ocp alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_man_alarm_state"}, /* Clear manager Alarm state , */\ + { 0x4460, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4480, "int_in_flag_bod_vddd_nok"}, /* Clear BOD event , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable por , */\ + { 0x4810, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ocp_alarm"}, /* Enable ocp alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_man_alarm_state"}, /* Enable nanager Alarm state , */\ + { 0x4860, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4880, "int_enable_flag_bod_vddd_nok"}, /* Enable BOD trigger , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ + { 0x4c10, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_man_alarm_state"}, /* Polarity nanager Alarm state , */\ + { 0x4c60, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4c80, "int_polarity_flag_bod_vddd_nok"}, /* Polarity BOD trigger , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery Safeguard attack time (with K = 1 at sample rate fs of 32kHz, 44,1 kHz or 48kHz ; with K = 2 at sample rate fs 16 kHz . With K =0.5 at sample rate of 96 kHz), */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery Safeguard maximum reduction , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass battery safeguard , */\ + { 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ + { 0x5150, "bypass_hp"}, /* Bypass HPF , */\ + { 0x5170, "enbl_dpsa"}, /* Enable DPSA , */\ + { 0x5222, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5257, "gain"}, /* Amplifier gain , */\ + { 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x52e0, "ctrl_slope"}, /* Slope speed setting (bin. coded) , */\ + { 0x52f0, "bypass_dly_line"}, /* Bypass the interpolator delay line , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5350, "bypass_lp"}, /* Bypass the low pass filter inside temperature sensor, */\ + { 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5430, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x5463, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5500, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5513, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5552, "dpsa_drive"}, /* Drive setting (bin. coded) , */\ + { 0x5600, "ref_iref_enbl"}, /* Enable of reference current for OCP , */\ + { 0x5631, "ref_irefdist_set_ctrl"}, /* Scaling of reference current for OCP , */\ + { 0x5652, "ref_irefdist_test_enbl"}, /* Enable of test-function of distribution of reference current, used for OCP. When enabled, the current will to to anamux iso powerstages. Using e.g. 011 it will add the current of powerstage P and N., */\ + { 0x570a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually, */\ + { 0x57b0, "enbl_engage"}, /* Enables/engage power stage and control loop , */\ + { 0x57c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ + { 0x5810, "hard_mute"}, /* Hard mute - PWM , */\ + { 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ + { 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ + { 0x58c0, "enbl_pwm_phase_shift"}, /* Control for pwm phase shift , */\ + { 0x5900, "pwm_clk_sel"}, /* Control for selection for PWM delay line source , */\ + { 0x5910, "sel_pwm_delay_src"}, /* Control for selection for PWM delay line source , */\ + { 0x5f23, "ctrl_attl"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5f63, "ctrl_attr"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x6005, "idle_power_cal_offset"}, /* Idle power mode detector ctrl cal_offset from gain module , */\ + { 0x6065, "idle_power_zero_lvl"}, /* IIdle power mode zero crossing detection level , */\ + { 0x60e1, "idle_power_mode"}, /* Idle power mode control , */\ + { 0x6105, "idle_power_threshold_lvl"}, /* Idle power mode amplitude trigger level , */\ + { 0x6165, "idle_power_hold_time"}, /* Idle power mode detector ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x61c0, "disable_idle_power_mode"}, /* Idle power mode detector control , */\ + { 0x6265, "zero_lvl"}, /* low noise gain switch zero trigger level , */\ + { 0x62c1, "ctrl_fb_resistor"}, /* Select amplifier feedback resistor connection , */\ + { 0x62e1, "lownoisegain_mode"}, /* ctrl select mode , */\ + { 0x6305, "threshold_lvl"}, /* low noise gain switch trigger level , */\ + { 0x6365, "hold_time"}, /* ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x6405, "lpm1_cal_offset"}, /* low power mode1 detector ctrl cal_offset from gain module , */\ + { 0x6465, "lpm1_zero_lvl"}, /* low power mode1 zero crossing detection level , */\ + { 0x64e1, "lpm1_mode"}, /* low power mode control , */\ + { 0x6505, "lpm1_threshold_lvl"}, /* low power mode1 amplitude trigger level , */\ + { 0x6565, "lpm1_hold_time"}, /* low power mode1 detector ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x65c0, "disable_low_power_mode"}, /* low power mode1 detector control , */\ + { 0x6600, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ + { 0x6611, "dcdc_ctrl_maxzercnt"}, /* DCDC. Number of zero current flags to count before going to pfm mode, */\ + { 0x6656, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ + { 0x66c0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x6700, "enbl_minion"}, /* Enables minion (small) power stage , */\ + { 0x6713, "vth_vddpvbat"}, /* select vddp-vbat thres signal , */\ + { 0x6750, "lpen_vddpvbat"}, /* select vddp-vbat filtred vs unfiltered compare , */\ + { 0x6761, "ctrl_rfb"}, /* Feedback resistor selection - I2C direct mode , */\ + { 0x6802, "tdm_source_mapping"}, /* tdm source mapping , */\ + { 0x6831, "tdm_sourcea_frame_sel"}, /* Sensed value A , */\ + { 0x6851, "tdm_sourceb_frame_sel"}, /* Sensed value B , */\ + { 0x6871, "tdm_source0_clip_sel"}, /* clip information (analog /digital) for source0 , */\ + { 0x6891, "tdm_source1_clip_sel"}, /* clip information (analog /digital) for source1 , */\ + { 0x6a02, "rst_min_vbat_delay"}, /* rst_min_vbat delay (nb fs) , */\ + { 0x6b00, "disable_auto_engage"}, /* disable auto engange , */\ + { 0x6b10, "disable_engage"}, /* disable engange , */\ + { 0x6c02, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ + { 0x6c32, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ + { 0x6c69, "spare_out"}, /* spare_out , */\ + { 0x6d0f, "spare_in"}, /* spare_in , */\ + { 0x6e00, "flag_idle_power_mode"}, /* Idle power mode , */\ + { 0x6e10, "flag_lp_detect_mode1"}, /* low power mode 1 detection , */\ + { 0x6e20, "flag_low_amplitude"}, /* low amplitude detection , */\ + { 0x6e30, "flag_vddp_gt_vbat"}, /* vddp greater than vbat , */\ + { 0x6f02, "cursense_comp_delay"}, /* delay to allign compensation signal with current sense signal, */\ + { 0x6f40, "cursense_comp_sign"}, /* polarity of compensation for current sense , */\ + { 0x6f50, "enbl_cursense_comp"}, /* enable current sense compensation , */\ + { 0x6f72, "pwms_clip_lvl"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7003, "boost_cur"}, /* Max coil current , */\ + { 0x7041, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7060, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7070, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x7085, "overshoot_correction_lvl"}, /* Threshold level to activate active overshoot control, */\ + { 0x70e0, "dcdcoff_mode"}, /* DCDC on/off , */\ + { 0x70f0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7174, "bst_slopecur"}, /* For testing direct control slope current , */\ + { 0x71c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ + { 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ + { 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7230, "enbl_bst_peakcur"}, /* Enable peak current , */\ + { 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage , */\ + { 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ + { 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x7290, "enbl_bst_windac"}, /* Enable window dac , */\ + { 0x72a5, "bst_windac"}, /* for testing direct control windac , */\ + { 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7331, "bst_freq"}, /* DCDC boost frequency control , */\ + { 0x7360, "bst_use_new_zercur_detect"}, /* Enable new zero current detection for boost control, */\ + { 0x7430, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7444, "boost_trip_lvl_1st"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7494, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x74e0, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x74f0, "ignore_flag_voutcomp86"}, /* Determines the maximum PWM frequency be the most efficient in relation to the Booster inductor value, */\ + { 0x7534, "boost_trip_lvl_2nd"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7584, "boost_trip_lvl_track"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x75f0, "enbl_trip_hyst"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7635, "frst_boost_voltage"}, /* First boost voltage level , */\ + { 0x7695, "scnd_boost_voltage"}, /* Second boost voltage level , */\ + { 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8210, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ + { 0x8305, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP)*signal, */\ + { 0x8364, "cs_ktemp2"}, /* Second order temperature compensation coefficient , */\ + { 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8440, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ + { 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8700, "enbl_cs_adc"}, /* Enable current sense ADC , */\ + { 0x8710, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 , */\ + { 0x8720, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 , */\ + { 0x8730, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ + { 0x8740, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 , */\ + { 0x8750, "enbl_cs_ldo"}, /* Enable current sense LDO , */\ + { 0x8780, "enbl_cs_vbatldo"}, /* Enable of current sense LDO , */\ + { 0x8790, "enbl_dc_filter"}, /* Control for enabling the DC blocking filter for voltage and current sense, */\ + { 0x8850, "vs_gain_control"}, /* Voltage sense gain control , */\ + { 0x8860, "vs_bypass_gc"}, /* Bypasses the VS gain correction , */\ + { 0x8887, "vs_gain"}, /* voltage sense gain , */\ + { 0x8c00, "vs_adc_bsoinv"}, /* Bitstream inversion for voltage sense ADC , */\ + { 0x8c40, "vs_adc_nortz"}, /* Return to zero for voltage sense ADC , */\ + { 0x8c90, "vs_adc_slowdel"}, /* Select delay for voltage sense ADC (internal decision circuitry), */\ + { 0x8d30, "vs_inn_short"}, /* Short voltage sense negative to common mode , */\ + { 0x8d40, "vs_inp_short"}, /* Short voltage sense positive to common mode , */\ + { 0x8d50, "vs_ldo_bypass"}, /* Bypass voltage sense LDO , */\ + { 0x8d60, "vs_ldo_pulldown"}, /* Pull down voltage sense LDO, only valid if left_enbl_cs_ldo is high, */\ + { 0x8d74, "vs_ldo_voset"}, /* Voltage sense LDO voltage level setting (two's complement), */\ + { 0x8f00, "enbl_vs_adc"}, /* Enable voltage sense ADC (Direct Control only only others done by manager), */\ + { 0x8f10, "enbl_vs_inn1"}, /* Enable connection of voltage sense negative1 , */\ + { 0x8f20, "enbl_vs_inn2"}, /* Enable connection of voltage sense negative2 , */\ + { 0x8f30, "enbl_vs_inp1"}, /* Enable connection of voltage sense positive1 , */\ + { 0x8f40, "enbl_vs_inp2"}, /* Enable connection of voltage sense positive2 , */\ + { 0x8f50, "enbl_vs_ldo"}, /* Enable voltage sense LDO (Direct Control only only others done by manager), */\ + { 0x8f80, "enbl_vs_vbatldo"}, /* Enable of voltage sense LDO (Direct Control only others done by manager), */\ + { 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa400, "faim_set_clkws"}, /* Sets the faim controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the faim are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the faim are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb050, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ + { 0xc0c0, "use_direct_vs_ctrls"}, /* voltage sense Direct control to overrule several functions for testing, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "enbl_pll"}, /* Enables PLL in I2C direct control mode only , */\ + { 0xc0f0, "enbl_fro"}, /* Enables FRO8M in I2C direct control mode only , */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs ), */\ + { 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc580, "test_enbl_vs"}, /* Enable for digimux mode of voltage sense , */\ + { 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to DATAO (see Digimux list for details), */\ + { 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to INT (see Digimux list for details), */\ + { 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to ADS1 (see Digimux list for details), */\ + { 0xc981, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9c0, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xc9d1, "sw_hs_mode"}, /* Speed/load setting for SW IO cell, clk or data mode range (see SWMF IO cell datasheet), */\ + { 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xcac0, "open_frcbst_ensw_switch"}, /* Save test2 configuration before enable anamux2 (open test2 switch and save test2 setting) , */\ + { 0xcb04, "anamux2"}, /* Anamux selection control - anamux on FRCBST/TEST2 , */\ + { 0xcb53, "anamux3"}, /* Anamux selection control - anamux on VSN/TEST3 , */\ + { 0xcba3, "anamux4"}, /* Anamux selection control - anamux on VSP/TEST4 , */\ + { 0xcd05, "pll_inseli"}, /* PLL INSELI - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcd64, "pll_inselp"}, /* PLL INSELP - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcdb3, "pll_inselr"}, /* PLL INSELR - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcdf0, "pll_bandsel"}, /* PLL bandwidth selection control, USE WITH CAUTION , */\ + { 0xce09, "pll_ndec"}, /* PLL NDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcea0, "pll_mdec_msb"}, /* MSB of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xceb0, "pll_bypass"}, /* PLL bypass control during functional mode , */\ + { 0xcec0, "pll_directi"}, /* PLL directi control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xced0, "pll_directo"}, /* PLL directo control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcee0, "pll_frm_clockstable"}, /* PLL FRM clock stable control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcef0, "pll_frm"}, /* PLL free running mode control in functional mode , */\ + { 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xd006, "pll_pdec"}, /* PLL PDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xd070, "use_direct_pll_ctrl"}, /* Enabled PLL direct control mode, overrules the PLL LUT with I2C register values, */\ + { 0xd090, "pll_limup_off"}, /* PLL up limiter control in PLL direct bandwidth control mode, pll_bandsel set to 1, */\ + { 0xd0a2, "sel_pll_startup_time"}, /* PLL startup time selection control , */\ + { 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd283, "tsig_gain"}, /* Test signal gain , */\ + { 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd507, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd580, "enbl_clk_out_of_range"}, /* Clock out of range , */\ + { 0xd721, "datao_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xd740, "bck_ehs"}, /* High-speed and standard/fast mode selection for BCK IO cell (see IIC3V3 IO cell datasheet), */\ + { 0xd750, "datai_ehs"}, /* High-speed and standard/fast mode selection for DATAI IO cell (see IIC3V3 IO cell datasheet), */\ + { 0xd800, "source_in_testmode"}, /* tdm source in test mode (return only current and voltage sense), */\ + { 0xd810, "gainatt_tdm_feedback"}, /* gainatt feedback to tdm , */\ + { 0xd822, "test_parametric_io"}, /* test io parametric , */\ + { 0xd850, "ctrl_bst_clk_lp1"}, /* boost clock control in low power mode1 , */\ + { 0xd861, "test_spare_out1"}, /* test spare out 1 , */\ + { 0xd880, "bst_dcmbst"}, /* dcm boost , */\ + { 0xd890, "gainatt_sw_feedback"}, /* gainatt feedback to sw , */\ + { 0xd8c3, "test_spare_out2"}, /* test spare out 1 , */\ + { 0xd900, "enbl_frocal"}, /* Enable FRO calibration , */\ + { 0xd910, "start_fro_calibration"}, /* Start FRO8 Calibration , */\ + { 0xd920, "enbl_irefcal"}, /* Enable IREF calibration , */\ + { 0xd930, "start_iref_calibration"}, /* Start IREF Calibration , */\ + { 0xda00, "fro_calibration_done"}, /* FRO8 Calibration done - Read Only , */\ + { 0xda15, "fro_auto_trim_val"}, /* Calibration value from Auto Calibration block, to be written into MTP - Read Only, */\ + { 0xda80, "iref_calibration_done"}, /* IREF Calibration done - Read Only , */\ + { 0xda94, "iref_auto_trim_val"}, /* Calibration value from Auto Calibration block, to be written into MTP - Read Only, */\ + { 0xdae0, "iref_calibration_error"}, /* IREF Calibration done - Read Only , */\ + { 0xe00f, "sw_profile"}, /* Software profile data , */\ + { 0xe10f, "sw_vstep"}, /* Software vstep information , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf169, "spare_mtp1_15_6"}, /* SPARE , */\ + { 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ + { 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ + { 0xf2a4, "optimal_pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0xf2f0, "enbl_optimal_pwm_delay"}, /* optimized pwm delay function enabled , */\ + { 0xf307, "calibr_gain_vs1"}, /* Voltage sense gain when external voltage sensing input is selected, */\ + { 0xf387, "calibr_gain_vs2"}, /* Voltage sense gain when internal voltage sensing input is selected, */\ + { 0xf407, "vs_trim1"}, /* VS Trimming when external voltage sensing input is selected, */\ + { 0xf487, "vs_trim2"}, /* VS Trimming when internal voltage sensing input is selected, */\ + { 0xf50f, "calibr_R25C_R"}, /* Ron resistance of speaker coil , */\ + { 0xf607, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ + { 0xf687, "spare_mpt6_15_06"}, /* SPARE , */\ + { 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ + { 0xf770, "spare_mtp7_07"}, /* SPARE , */\ + { 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ + { 0xf7f0, "spare_mtp7_15"}, /* SPARE , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable function dcdcoff_mode , */\ + { 0xf910, "spare_mtp9_1"}, /* SPARE , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Force Boost in follower mode , */\ + { 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf980, "spare_mtp9_8"}, /* SPARE , */\ + { 0xf990, "mtp_enbl_pwm_delay_clock_gating"}, /* pwm delay clock auto gating , */\ + { 0xf9a0, "mtp_enbl_ocp_clock_gating"}, /* ocpclock auto gating , */\ + { 0xf9b0, "mtp_gate_cgu_clock_for_test"}, /* cgu test clock control , */\ + { 0xf9c0, "mtp_tdm_pad_sel"}, /* tdm pad selection , */\ + { 0xf9d2, "spare_mtp9_15_12"}, /* MTP-control FW - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ + { 0xff05, "fro_trim"}, /* 8 MHz oscillator trim code , */\ + { 0xff61, "fro_shortnwell"}, /* Short 4 or 6 n-well resistors , */\ + { 0xff81, "fro_boost"}, /* Self bias current selection , */\ + { 0xffa4, "calibr_iref_trim"}, /* Trimming control of reference current for OCP , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa9878_irq { + tfa9878_irq_stvdds = 0, + tfa9878_irq_stbstoc = 1, + tfa9878_irq_stotds = 2, + tfa9878_irq_stocpr = 3, + tfa9878_irq_stuvds = 4, + tfa9878_irq_stmanalarm = 5, + tfa9878_irq_sttdmer = 6, + tfa9878_irq_stnoclk = 7, + tfa9878_irq_stbodnok = 8, + tfa9878_irq_max = 9, + tfa9878_irq_all = -1 /* all irqs */}; + +#define TFA9878_IRQ_NAMETABLE static tfaIrqName_t Tfa9878IrqNames[] = {\ + { 0, "STVDDS"},\ + { 1, "STBSTOC"},\ + { 2, "STOTDS"},\ + { 3, "STOCPR"},\ + { 4, "STUVDS"},\ + { 5, "STMANALARM"},\ + { 6, "STTDMER"},\ + { 7, "STNOCLK"},\ + { 8, "STBODNOK"},\ + { 9, "9"},\ +}; +#endif /* _TFA9878_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa9887_tfafieldnames.h b/sound/soc/codecs/tfa9887_tfafieldnames.h new file mode 100644 index 000000000000..b85ca5b44a25 --- /dev/null +++ b/sound/soc/codecs/tfa9887_tfafieldnames.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ +#define TFA9887_I2CVERSION 34 +#define TFA9895_I2CVERSION 34 +#define TFA9887_NAMETABLE static tfaBfName_t Tfa9887DatasheetNames[] = {\ + { 0x402, "I2SF"}, /* I2SFormat data 1 input: , */\ + { 0x431, "CHS12"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "CHS3"}, /* ChannelSelection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "CHSA"}, /* Input selection for amplifier , */\ + { 0x4b0, "I2SDOE"}, /* Enable data output , */\ + { 0x4c3, "I2SSR"}, /* sample rate setting , */\ + { 0x500, "BSSBY"}, /* , */\ + { 0x511, "BSSCR"}, /* 00 = 0.56 dB/Sample , */\ + { 0x532, "BSST"}, /* 000 = 2.92V , */\ + { 0x5f0, "I2SDOC"}, /* selection data out , */\ + { 0xa02, "DOLS"}, /* Output selection dataout left channel , */\ + { 0xa32, "DORS"}, /* Output selection dataout right channel , */\ + { 0xa62, "SPKL"}, /* Selection speaker induction , */\ + { 0xa91, "SPKR"}, /* Selection speaker impedance , */\ + { 0xab3, "DCFG"}, /* DCDC speaker current compensation gain , */\ + { 0x4134, "PWMDEL"}, /* PWM DelayBits to set the delay , */\ + { 0x4180, "PWMSH"}, /* PWM Shape , */\ + { 0x4190, "PWMRE"}, /* PWM Bitlength in noise shaper , */\ + { 0x48e1, "TCC"}, /* sample & hold track time: , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9887_BITNAMETABLE static tfaBfName_t Tfa9887BitNames[] = {\ + { 0x402, "i2s_seti"}, /* I2SFormat data 1 input: , */\ + { 0x431, "chan_sel1"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "lr_sw_i2si2"}, /* ChannelSelection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "input_sel"}, /* Input selection for amplifier , */\ + { 0x4b0, "enbl_datao"}, /* Enable data output , */\ + { 0x4c3, "i2s_fs"}, /* sample rate setting , */\ + { 0x500, "bypass_clipper"}, /* , */\ + { 0x511, "vbat_prot_attacktime[1:0]"}, /* 00 = 0.56 dB/Sample , */\ + { 0x532, "vbat_prot_thlevel[2:0]"}, /* 000 = 2.92V , */\ + { 0x5d0, "reset_min_vbat"}, /* to reset the clipper via I2C in case the CF is bypassed, */\ + { 0x5f0, "datao_sel"}, /* selection data out , */\ + { 0xa02, "sel_i2so_l"}, /* Output selection dataout left channel , */\ + { 0xa32, "sel_i2so_r"}, /* Output selection dataout right channel , */\ + { 0xa62, "ctrl_spkr_coil"}, /* Selection speaker induction , */\ + { 0xa91, "ctrl_spr_res"}, /* Selection speaker impedance , */\ + { 0xab3, "ctrl_dcdc_spkr_i_comp_gain"}, /* DCDC speaker current compensation gain , */\ + { 0xaf0, "ctrl_dcdc_spkr_i_comp_sign"}, /* DCDC speaker current compensation sign , */\ + { 0x4100, "bypass_hp"}, /* bypass_hp, to bypass the hp filter byhind the CoolFlux, */\ + { 0x4110, "hard_mute"}, /* hard mute setting in HW , */\ + { 0x4120, "soft_mute"}, /* Soft mute setting in HW , */\ + { 0x4134, "PWM_Delay[4:0]"}, /* PWM DelayBits to set the delay , */\ + { 0x4180, "PWM_Shape"}, /* PWM Shape , */\ + { 0x4190, "PWM_BitLength"}, /* PWM Bitlength in noise shaper , */\ + { 0x4800, "ctrl_negin"}, /* , */\ + { 0x4810, "ctrl_cs_sein"}, /* , */\ + { 0x4820, "ctrl_coincidencecs"}, /* HIGH => Prevent dcdc switching during clk_cs_clksh, */\ + { 0x4876, "delay_se_neg[6:0]"}, /* delayshiftse2 , */\ + { 0x48e1, "ctrl_cs_ttrack[1:0]"}, /* sample & hold track time: , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + diff --git a/sound/soc/codecs/tfa9890_tfafieldnames.h b/sound/soc/codecs/tfa9890_tfafieldnames.h new file mode 100644 index 000000000000..ad043bc83148 --- /dev/null +++ b/sound/soc/codecs/tfa9890_tfafieldnames.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ +#define TFA9890_I2CVERSION 34 +#define TFA9890_NAMETABLE static tfaBfName_t Tfa9890DatasheetNames[] = {\ + { 0x402, "I2SF"}, /* I2SFormat data 1 input: , */\ + { 0x431, "CHS12"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "CHS3"}, /* ChannelSelection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "CHSA"}, /* Input selection for amplifier , */\ + { 0x481, "I2SDOC"}, /* selection data out , */\ + { 0x4a0, "DISP"}, /* idp protection , */\ + { 0x4b0, "I2SDOE"}, /* Enable data output , */\ + { 0x4c3, "I2SSR"}, /* sample rate setting , */\ + { 0x732, "DCMCC"}, /* Max boost coil current - step of 500 mA , */\ + { 0x9c0, "CCFD"}, /* Selection CoolFlux Clock , */\ + { 0x9d0, "ISEL"}, /* selection input 1 or 2 , */\ + { 0xa02, "DOLS"}, /* Output selection dataout left channel , */\ + { 0xa32, "DORS"}, /* Output selection dataout right channel , */\ + { 0xa62, "SPKL"}, /* Selection speaker induction , */\ + { 0xa91, "SPKR"}, /* Selection speaker impedance , */\ + { 0xab3, "DCFG"}, /* DCDC speaker current compensation gain , */\ + { 0xf00, "VDDD"}, /* mask flag_por for interupt generation , */\ + { 0xf10, "OTDD"}, /* mask flag_otpok for interupt generation , */\ + { 0xf20, "OVDD"}, /* mask flag_ovpok for interupt generation , */\ + { 0xf30, "UVDD"}, /* mask flag_uvpok for interupt generation , */\ + { 0xf40, "OCDD"}, /* mask flag_ocp_alarm for interupt generation , */\ + { 0xf50, "CLKD"}, /* mask flag_clocks_stable for interupt generation , */\ + { 0xf60, "DCCD"}, /* mask flag_pwrokbst for interupt generation , */\ + { 0xf70, "SPKD"}, /* mask flag_cf_speakererror for interupt generation , */\ + { 0xf80, "WDD"}, /* mask flag_watchdog_reset for interupt generation , */\ + { 0xf90, "LCLK"}, /* mask flag_lost_clk for interupt generation , */\ + { 0xfe0, "INT"}, /* enabling interrupt , */\ + { 0xff0, "INTP"}, /* Setting polarity interupt , */\ + { 0x8f0f, "VERSION"}, /* (key1 protected) , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9890_BITNAMETABLE static tfaBfName_t Tfa9890BitNames[] = {\ + { 0x402, "i2s_seti"}, /* I2SFormat data 1 input: , */\ + { 0x431, "chan_sel1"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "lr_sw_i2si2"}, /* ChannelSelection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "input_sel"}, /* Input selection for amplifier , */\ + { 0x481, "datao_sel"}, /* selection data out , */\ + { 0x4a0, "disable_idp"}, /* idp protection , */\ + { 0x4b0, "enbl_datao"}, /* Enable data output , */\ + { 0x4c3, "i2s_fs"}, /* sample rate setting , */\ + { 0x732, "ctrl_bstcur"}, /* Max boost coil current - step of 500 mA , */\ + { 0x9c0, "sel_cf_clk"}, /* Selection CoolFlux Clock , */\ + { 0x9d0, "intf_sel"}, /* selection input 1 or 2 , */\ + { 0xa02, "sel_i2so_l"}, /* Output selection dataout left channel , */\ + { 0xa32, "sel_i2so_r"}, /* Output selection dataout right channel , */\ + { 0xa62, "ctrl_spkr_coil"}, /* Selection speaker induction , */\ + { 0xa91, "ctrl_spr_res"}, /* Selection speaker impedance , */\ + { 0xab3, "ctrl_dcdc_spkr_i_comp_gain"}, /* DCDC speaker current compensation gain , */\ + { 0xaf0, "ctrl_dcdc_spkr_i_comp_sign"}, /* DCDC speaker current compensation sign , */\ + { 0xf00, "flag_por_mask"}, /* mask flag_por for interupt generation , */\ + { 0xf10, "flag_otpok_mask"}, /* mask flag_otpok for interupt generation , */\ + { 0xf20, "flag_ovpok_mask"}, /* mask flag_ovpok for interupt generation , */\ + { 0xf30, "flag_uvpok_mask"}, /* mask flag_uvpok for interupt generation , */\ + { 0xf40, "flag_ocp_alarm_mask"}, /* mask flag_ocp_alarm for interupt generation , */\ + { 0xf50, "flag_clocks_stable_mask"}, /* mask flag_clocks_stable for interupt generation , */\ + { 0xf60, "flag_pwrokbst_mask"}, /* mask flag_pwrokbst for interupt generation , */\ + { 0xf70, "flag_cf_speakererror_mask"}, /* mask flag_cf_speakererror for interupt generation , */\ + { 0xf80, "flag_watchdog_reset_mask"}, /* mask flag_watchdog_reset for interupt generation , */\ + { 0xf90, "flag_lost_clk_mask"}, /* mask flag_lost_clk for interupt generation , */\ + { 0xfe0, "enable_interrupt"}, /* enabling interrupt , */\ + { 0xff0, "invert_int_polarity"}, /* Setting polarity interupt , */\ + { 0x4700, "switch_fb"}, /* switch_fb , */\ + { 0x4713, "se_hyst"}, /* se_hyst , */\ + { 0x4754, "se_level"}, /* se_level , */\ + { 0x47a5, "ktemp"}, /* temperature compensation trimming , */\ + { 0x8f0f, "production_data6"}, /* (key1 protected) , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + diff --git a/sound/soc/codecs/tfa9891_tfafieldnames.h b/sound/soc/codecs/tfa9891_tfafieldnames.h new file mode 100644 index 000000000000..8aa691f5bf06 --- /dev/null +++ b/sound/soc/codecs/tfa9891_tfafieldnames.h @@ -0,0 +1,512 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA_INC_TFA9891_TFAFIELDNAMES_H_ +#define TFA_INC_TFA9891_TFAFIELDNAMES_H_ + +#define TFA9891_I2CVERSION 13 + + +#define TFA9891_NAMETABLE static tfaBfName_t Tfa9891DatasheetNames[] = {\ + { 0x0, "VDDS"}, /* POR , */\ + { 0x10, "PLLS"}, /* PLL , */\ + { 0x20, "OTDS"}, /* OTP , */\ + { 0x30, "OVDS"}, /* OVP , */\ + { 0x40, "UVDS"}, /* UVP , */\ + { 0x50, "OCDS"}, /* OCP , */\ + { 0x60, "CLKS"}, /* Clocks , */\ + { 0x70, "CLIPS"}, /* CLIP , */\ + { 0x80, "MTPB"}, /* MTP , */\ + { 0x90, "DCCS"}, /* BOOST , */\ + { 0xa0, "SPKS"}, /* Speaker , */\ + { 0xb0, "ACS"}, /* cold start flag , */\ + { 0xc0, "SWS"}, /* flag engage , */\ + { 0xd0, "WDS"}, /* flag watchdog reset , */\ + { 0xe0, "AMPS"}, /* amplifier is enabled by manager , */\ + { 0xf0, "AREFS"}, /* references are enabled by manager , */\ + { 0x109, "BATS"}, /* Battery voltage readout; 0[V]..5.5[V] , */\ + { 0x208, "TEMPS"}, /* Temperature readout , */\ + { 0x307, "REV"}, /* Device Revision , */\ + { 0x402, "I2SF"}, /* I2SFormat data 1 input , */\ + { 0x431, "CHS12"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "CHS3"}, /* Channel Selection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "CHSA"}, /* Input selection for amplifier , */\ + { 0x481, "I2SDOC"}, /* Selection for I2S data out , */\ + { 0x4a0, "DISP"}, /* idp protection , */\ + { 0x4b0, "I2SDOE"}, /* Enable data output , */\ + { 0x4c3, "I2SSR"}, /* sample rate setting , */\ + { 0x501, "BSSCR"}, /* ProtectionAttackTime , */\ + { 0x523, "BSST"}, /* ProtectionThreshold , */\ + { 0x561, "BSSRL"}, /* ProtectionMaximumReduction , */\ + { 0x582, "BSSRR"}, /* Protection Release Timer , */\ + { 0x5b1, "BSSHY"}, /* ProtectionHysterese , */\ + { 0x5e0, "BSSR"}, /* battery voltage for I2C read out only , */\ + { 0x5f0, "BSSBY"}, /* bypass clipper battery protection , */\ + { 0x600, "DPSA"}, /* Enable dynamic powerstage activation , */\ + { 0x613, "AMPSL"}, /* control slope , */\ + { 0x650, "CFSM"}, /* Soft mute in CoolFlux , */\ + { 0x670, "BSSS"}, /* batsensesteepness , */\ + { 0x687, "VOL"}, /* volume control (in CoolFlux) , */\ + { 0x702, "DCVO"}, /* Boost voltage , */\ + { 0x732, "DCMCC"}, /* Max boost coil current , */\ + { 0x7a0, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7b0, "DCSR"}, /* Soft RampUp/Down mode for DCDC controller , */\ + { 0x800, "TROS"}, /* select external temperature also the ext_temp will be put on the temp read out , */\ + { 0x818, "EXTTS"}, /* external temperature setting to be given by host , */\ + { 0x900, "PWDN"}, /* ON/OFF , */\ + { 0x910, "I2CR"}, /* I2CReset , */\ + { 0x920, "CFE"}, /* EnableCoolFlux , */\ + { 0x930, "AMPE"}, /* EnableAmplifier , */\ + { 0x940, "DCA"}, /* EnableBoost , */\ + { 0x950, "SBSL"}, /* Coolflux configured , */\ + { 0x960, "AMPC"}, /* Selection on how AmplifierEnabling , */\ + { 0x970, "DCDIS"}, /* DCDC not connected , */\ + { 0x980, "PSDR"}, /* Iddq test amplifier , */\ + { 0x991, "DCCV"}, /* Coil Value , */\ + { 0x9b1, "CCFD"}, /* Selection CoolFluxClock , */\ + { 0x9d0, "ISEL"}, /* Interface Selection , */\ + { 0x9e0, "IPLL"}, /* selection input PLL for lock , */\ + { 0xa02, "DOLS"}, /* Output selection dataout left channel , */\ + { 0xa32, "DORS"}, /* Output selection dataout right channel , */\ + { 0xa62, "SPKL"}, /* Selection speaker induction , */\ + { 0xa91, "SPKR"}, /* Selection speaker impedance , */\ + { 0xab3, "DCFG"}, /* DCDC speaker current compensation gain , */\ + { 0xb07, "MTPK"}, /* MTP KEY2 register , */\ + { 0xf00, "VDDD"}, /* mask flag_por for interupt generation , */\ + { 0xf10, "OTDD"}, /* mask flag_otpok for interupt generation , */\ + { 0xf20, "OVDD"}, /* mask flag_ovpok for interupt generation , */\ + { 0xf30, "UVDD"}, /* mask flag_uvpok for interupt generation , */\ + { 0xf40, "OCDD"}, /* mask flag_ocp_alarm for interupt generation , */\ + { 0xf50, "CLKD"}, /* mask flag_clocks_stable for interupt generation , */\ + { 0xf60, "DCCD"}, /* mask flag_pwrokbst for interupt generation , */\ + { 0xf70, "SPKD"}, /* mask flag_cf_speakererror for interupt generation , */\ + { 0xf80, "WDD"}, /* mask flag_watchdog_reset for interupt generation , */\ + { 0xfe0, "INT"}, /* enabling interrupt , */\ + { 0xff0, "INTP"}, /* Setting polarity interupt , */\ + { 0x1000, "PDMSEL"}, /* Audio input interface mode , */\ + { 0x1010, "I2SMOUTEN"}, /* I2S Master enable (CLK and WS pads) , */\ + { 0x1021, "PDMORSEL"}, /* PDM Output right channel source selection , */\ + { 0x1041, "PDMOLSEL"}, /* PDM Output Left/Mono channel source selection , */\ + { 0x1061, "PADSEL"}, /* Output interface mode and ball selection , */\ + { 0x1100, "PDMOSDEN"}, /* Secure delay Cell , */\ + { 0x1110, "PDMOSDCF"}, /* Rising Falling Resync control Mux , */\ + { 0x1140, "SAAMEN"}, /* Speaker As a Mic feature ON/OFF , */\ + { 0x1150, "SAAMLPEN"}, /* speaker_as_mic low power mode (only in PDM_out mode), */\ + { 0x1160, "PDMOINTEN"}, /* PDM output interpolation ratio , */\ + { 0x1203, "PDMORG1"}, /* PDM Interpolator Right Channel DS4 G1 Gain Value , */\ + { 0x1243, "PDMORG2"}, /* PDM Interpolator Right Channel DS4 G2 Gain Value , */\ + { 0x1303, "PDMOLG1"}, /* PDM Interpolator Left Channel DS4 G1 Gain Value , */\ + { 0x1343, "PDMOLG2"}, /* PDM Interpolator Left Channel DS4 G2 Gain Value , */\ + { 0x2202, "SAAMGAIN"}, /* pga gain , */\ + { 0x2250, "SAAMPGACTRL"}, /* 0 = active input common mode voltage source at the attenuator/PGA level, */\ + { 0x2500, "PLLCCOSEL"}, /* pll cco frequency , */\ + { 0x4600, "CSBYPGC"}, /* bypass_gc, bypasses the CS gain correction , */\ + { 0x4900, "CLIP"}, /* Bypass clip control (function depending on digimux clip_x), */\ + { 0x4910, "CLIP2"}, /* Bypass clip control (function depending on digimux clip_x), */\ + { 0x62b0, "CIMTP"}, /* start copying all the data from i2cregs_mtp to mtp [Key 2 protected], */\ + { 0x7000, "RST"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "DMEM"}, /* Target memory for access , */\ + { 0x7030, "AIF"}, /* Autoincrement-flag for memory-address , */\ + { 0x7040, "CFINT"}, /* Interrupt CoolFlux DSP , */\ + { 0x7087, "REQ"}, /* request for access (8 channels) , */\ + { 0x710f, "MADD"}, /* memory-address to be accessed , */\ + { 0x720f, "MEMA"}, /* activate memory access (24- or 32-bits data is written/read to/from memory, */\ + { 0x7307, "ERR"}, /* cf error Flags , */\ + { 0x7387, "ACK"}, /* acknowledge of requests (8 channels")" , */\ + { 0x8000, "MTPOTC"}, /* Calibration schedule (key2 protected) , */\ + { 0x8010, "MTPEX"}, /* (key2 protected) calibration of Ron has been executed, */\ + { 0x8045, "SWPROFIL" },\ + { 0x80a5, "SWVSTEP" },\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9891_BITNAMETABLE static tfaBfName_t Tfa9891BitNames[] = {\ + { 0x0, "POR"}, /* POR , */\ + { 0x10, "PLL_LOCK"}, /* PLL , */\ + { 0x20, "flag_otpok"}, /* OTP , */\ + { 0x30, "flag_ovpok"}, /* OVP , */\ + { 0x40, "flag_uvpok"}, /* UVP , */\ + { 0x50, "flag_OCP_alarm"}, /* OCP , */\ + { 0x60, "flag_clocks_stable"}, /* Clocks , */\ + { 0x70, "CLIP"}, /* CLIP , */\ + { 0x80, "mtp_busy"}, /* MTP , */\ + { 0x90, "flag_pwrokbst"}, /* BOOST , */\ + { 0xa0, "flag_cf_speakererror"}, /* Speaker , */\ + { 0xb0, "flag_cold_started"}, /* cold start flag , */\ + { 0xc0, "flag_engage"}, /* flag engage , */\ + { 0xd0, "flag_watchdog_reset"}, /* flag watchdog reset , */\ + { 0xe0, "flag_enbl_amp"}, /* amplifier is enabled by manager , */\ + { 0xf0, "flag_enbl_ref"}, /* references are enabled by manager , */\ + { 0x109, "bat_adc"}, /* Battery voltage readout; 0[V]..5.5[V] , */\ + { 0x208, "temp_adc"}, /* Temperature readout , */\ + { 0x307, "rev_reg"}, /* Device Revision , */\ + { 0x402, "i2s_seti"}, /* I2SFormat data 1 input , */\ + { 0x431, "chan_sel1"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "lr_sw_i2si2"}, /* Channel Selection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "input_sel"}, /* Input selection for amplifier , */\ + { 0x481, "datao_sel"}, /* Selection for I2S data out , */\ + { 0x4a0, "disable_idp"}, /* idp protection , */\ + { 0x4b0, "enbl_datao"}, /* Enable data output , */\ + { 0x4c3, "i2s_fs"}, /* sample rate setting , */\ + { 0x501, "vbat_prot_attacktime"}, /* ProtectionAttackTime , */\ + { 0x523, "vbat_prot_thlevel"}, /* ProtectionThreshold , */\ + { 0x561, "vbat_prot_max_reduct"}, /* ProtectionMaximumReduction , */\ + { 0x582, "vbat_prot_release_t"}, /* Protection Release Timer , */\ + { 0x5b1, "vbat_prot_hysterese"}, /* ProtectionHysterese , */\ + { 0x5d0, "reset_min_vbat"}, /* reset clipper , */\ + { 0x5e0, "sel_vbat"}, /* battery voltage for I2C read out only , */\ + { 0x5f0, "bypass_clipper"}, /* bypass clipper battery protection , */\ + { 0x600, "dpsa"}, /* Enable dynamic powerstage activation , */\ + { 0x613, "ctrl_slope"}, /* control slope , */\ + { 0x650, "cf_mute"}, /* Soft mute in CoolFlux , */\ + { 0x660, "sel_other_vamp"}, /* Input selection for the second channel of the DCDC inteligent mode detector, */\ + { 0x670, "ctrl_batsensesteepness"}, /* batsensesteepness , */\ + { 0x687, "vol"}, /* volume control (in CoolFlux) , */\ + { 0x702, "ctrl_bstvolt"}, /* Boost voltage , */\ + { 0x732, "ctrl_bstcur"}, /* Max boost coil current , */\ + { 0x761, "ctrl_slopebst_1_0"}, /* Setting for the slope of the boost converter power stage, */\ + { 0x781, "ctrl_slopebst_3_2"}, /* Setting for the part of the power transistor voltage to be used in peak current mode control, */\ + { 0x7a0, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7b0, "boost_speed"}, /* Soft RampUp/Down mode for DCDC controller , */\ + { 0x7c1, "ctrl_delay_comp_dcdc"}, /* delay compensation in current patg compared to delay in the audio path (relative) , */\ + { 0x7e0, "boost_input"}, /* Selection intelligent boost detector input , */\ + { 0x7f0, "ctrl_supplysense"}, /* ADC10 input selection , */\ + { 0x800, "ext_temp_sel"}, /* select external temperature also the ext_temp will be put on the temp read out , */\ + { 0x818, "ext_temp"}, /* external temperature setting to be given by host , */\ + { 0x8a0, "ctrl_spk_coilpvp_bst"}, /* Peak voltage protection boost converter , */\ + { 0x8b2, "ctrl_dcdc_synchronisation"}, /* DCDC synchronisation off + 7 positions , */\ + { 0x8e0, "ctrl_cs_samplevalid"}, /* sample valid moment for CS in single sample moment mode, */\ + { 0x900, "PowerDown"}, /* ON/OFF , */\ + { 0x910, "reset"}, /* I2CReset , */\ + { 0x920, "enbl_coolflux"}, /* EnableCoolFlux , */\ + { 0x930, "enbl_amplifier"}, /* EnableAmplifier , */\ + { 0x940, "enbl_boost"}, /* EnableBoost , */\ + { 0x950, "cf_configured"}, /* Coolflux configured , */\ + { 0x960, "sel_enbl_amplifier"}, /* Selection on how AmplifierEnabling , */\ + { 0x970, "dcdcoff_mode"}, /* DCDC not connected , */\ + { 0x980, "cttr_iddqtest"}, /* Iddq test amplifier , */\ + { 0x991, "ctrl_coil_value"}, /* Coil Value , */\ + { 0x9b1, "ctrl_sel_cf_clock"}, /* Selection CoolFluxClock , */\ + { 0x9d0, "intf_sel"}, /* Interface Selection , */\ + { 0x9e0, "sel_ws_bck"}, /* selection input PLL for lock , */\ + { 0xa02, "sel_i2so_l"}, /* Output selection dataout left channel , */\ + { 0xa32, "sel_i2so_r"}, /* Output selection dataout right channel , */\ + { 0xa62, "ctrl_spkr_coil"}, /* Selection speaker induction , */\ + { 0xa91, "ctrl_spr_res"}, /* Selection speaker impedance , */\ + { 0xab3, "ctrl_dcdc_spkr_i_comp_gain"}, /* DCDC speaker current compensation gain , */\ + { 0xaf0, "ctrl_dcdc_spkr_i_comp_sign"}, /* DCDC speaker current compensation sign , */\ + { 0xb07, "MTP_key2"}, /* MTP KEY2 register , */\ + { 0xc0c, "clk_sync_delay"}, /* Delay count for clock synchronisation , */\ + { 0xcf0, "enbl_clk_sync"}, /* Enable CGU clock synchronisation , */\ + { 0xd0c, "adc_sync_delay"}, /* Delay count for ADC synchronisation , */\ + { 0xdf0, "enable_adc_sync"}, /* Enable ADC synchronisation , */\ + { 0xe00, "bypass_dcdc_curr_prot"}, /* to switch off dcdc reduction with bat prot , */\ + { 0xe24, "ctrl_digtoana6_2"}, /* for extra connections digital to analog , */\ + { 0xe70, "switch_on_icomp"}, /* icomp dem switch , */\ + { 0xe87, "reserve_reg_1_7_0"}, /* reserved , */\ + { 0xf00, "flag_por_mask"}, /* mask flag_por for interupt generation , */\ + { 0xf10, "flag_otpok_mask"}, /* mask flag_otpok for interupt generation , */\ + { 0xf20, "flag_ovpok_mask"}, /* mask flag_ovpok for interupt generation , */\ + { 0xf30, "flag_uvpok_mask"}, /* mask flag_uvpok for interupt generation , */\ + { 0xf40, "flag_ocp_alarm_mask"}, /* mask flag_ocp_alarm for interupt generation , */\ + { 0xf50, "flag_clocks_stable_mask"}, /* mask flag_clocks_stable for interupt generation , */\ + { 0xf60, "flag_pwrokbst_mask"}, /* mask flag_pwrokbst for interupt generation , */\ + { 0xf70, "flag_cf_speakererror_mask"}, /* mask flag_cf_speakererror for interupt generation , */\ + { 0xf80, "flag_watchdog_reset_mask"}, /* mask flag_watchdog_reset for interupt generation , */\ + { 0xf90, "flag_lost_clk_mask"}, /* mask flag_lost_clk for interupt generation , */\ + { 0xfe0, "enable_interrupt"}, /* enabling interrupt , */\ + { 0xff0, "invert_int_polarity"}, /* Setting polarity interupt , */\ + { 0x1000, "pdm_i2s_input"}, /* Audio input interface mode , */\ + { 0x1010, "I2S_master_ena"}, /* I2S Master enable (CLK and WS pads) , */\ + { 0x1021, "pdm_out_sel_r"}, /* PDM Output right channel source selection , */\ + { 0x1041, "pdm_out_sel_l"}, /* PDM Output Left/Mono channel source selection , */\ + { 0x1061, "micdat_out_sel"}, /* Output interface mode and ball selection , */\ + { 0x1100, "secure_dly"}, /* Secure delay Cell , */\ + { 0x1110, "d_out_valid_rf_mux"}, /* Rising Falling Resync control Mux , */\ + { 0x1140, "Speak_As_Mic_en"}, /* Speaker As a Mic feature ON/OFF , */\ + { 0x1150, "speak_as_mic_lp_mode"}, /* speaker_as_mic low power mode (only in PDM_out mode), */\ + { 0x1160, "pdm_out_rate"}, /* PDM output interpolation ratio , */\ + { 0x1203, "ds4_g1_r"}, /* PDM Interpolator Right Channel DS4 G1 Gain Value , */\ + { 0x1243, "ds4_g2_r"}, /* PDM Interpolator Right Channel DS4 G2 Gain Value , */\ + { 0x1303, "ds4_g1_l"}, /* PDM Interpolator Left Channel DS4 G1 Gain Value , */\ + { 0x1343, "ds4_g2_l"}, /* PDM Interpolator Left Channel DS4 G2 Gain Value , */\ + { 0x1400, "clk_secure_dly"}, /* Secure delay Cell on clock path , */\ + { 0x1410, "data_secure_dly"}, /* Secure delay Cell enable on PDM data path , */\ + { 0x2202, "Ctrl_saam_pga_gain"}, /* pga gain , */\ + { 0x2250, "ctrl_saam_pga_src"}, /* 0 = active input common mode voltage source at the attenuator/PGA level, */\ + { 0x2300, "flag_saam_spare"}, /* spare flag , */\ + { 0x2400, "ctrl_saam_pga_tm"}, /* enables PGA test mode , */\ + { 0x2500, "pll_fcco"}, /* pll cco frequency , */\ + { 0x3000, "flag_hi_small"}, /* positive small window dcdc converter , */\ + { 0x3010, "flag_hi_large"}, /* positive large window dcdc converter , */\ + { 0x3020, "flag_lo_small"}, /* negative small window dcdc converter , */\ + { 0x3030, "flag_lo_large"}, /* negative large window dcdc converter , */\ + { 0x3040, "flag_voutcomp"}, /* flag_voutcomp, indication Vset is larger than Vbat, */\ + { 0x3050, "flag_voutcomp93"}, /* flag_voutcomp93, indication Vset is larger than 1.07* Vbat , */\ + { 0x3060, "flag_voutcomp86"}, /* flag_voutcomp86, indication Vset is larger than 1.14* Vbat , */\ + { 0x3070, "flag_hiz"}, /* flag_hiz, indication Vbst is larger than Vbat , */\ + { 0x3080, "flag_hi_peak"}, /* flag_hi_peak, indication hi_peak , */\ + { 0x3090, "flag_ocpokbst"}, /* flag_ocpokbst, indication no over current in boost converter pmos switch, */\ + { 0x30a0, "flag_peakcur"}, /* flag_peakcur, indication current is max in dcdc converter, */\ + { 0x30b0, "flag_ocpokap"}, /* flag_ocpokap, indication no over current in amplifier "a" pmos output stage, */\ + { 0x30c0, "flag_ocpokan"}, /* flag_ocpokan, indication no over current in amplifier "a" nmos output stage, */\ + { 0x30d0, "flag_ocpokbp"}, /* flag_ocpokbp, indication no over current in amplifier "b" pmos output stage, */\ + { 0x30e0, "flag_ocpokbn"}, /* flag_ocpokbn, indication no over current in amplifier"b" nmos output stage, */\ + { 0x30f0, "lost_clk"}, /* lost_clk, lost clock indication CGU , */\ + { 0x310f, "mtp_man_data_out"}, /* single word read from MTP (manual copy) , */\ + { 0x3200, "key01_locked"}, /* key01_locked, indication key 1 is locked , */\ + { 0x3210, "key02_locked"}, /* key02_locked, indication key 2 is locked , */\ + { 0x3225, "mtp_ecc_tcout"}, /* mtp_ecc_tcout , */\ + { 0x3280, "mtpctrl_valid_test_rd"}, /* mtp test readout for read , */\ + { 0x3290, "mtpctrl_valid_test_wr"}, /* mtp test readout for write , */\ + { 0x32a0, "flag_in_alarm_state"}, /* alarm state , */\ + { 0x32b0, "mtp_ecc_err2"}, /* two or more bit errors detected in MTP, can not reconstruct value, */\ + { 0x32c0, "mtp_ecc_err1"}, /* one bit error detected in MTP, reconstructed value, */\ + { 0x32d0, "mtp_mtp_hvf"}, /* high voltage ready flag for MTP , */\ + { 0x32f0, "mtp_zero_check_fail"}, /* zero check failed (tbd) for MTP , */\ + { 0x3300, "flag_adc10_ready"}, /* flag_adc10_ready, indication adc10 is ready , */\ + { 0x3310, "flag_clipa_high"}, /* flag_clipa_high, indication pmos amplifier "a" is clipping, */\ + { 0x3320, "flag_clipa_low"}, /* flag_clipa_low, indication nmos amplifier "a" is clipping, */\ + { 0x3330, "flag_clipb_high"}, /* flag_clipb_high, indication pmos amplifier "b" is clipping, */\ + { 0x3340, "flag_clipb_low"}, /* flag_clipb_low, indication nmos amplifier "b" is clipping, */\ + { 0x3359, "data_adc10_tempbat"}, /* adc 10 data output for testing , */\ + { 0x33f0, "flag_vddd_comp_nok"}, /* power switch flag 2 for testing , */\ + { 0x400f, "hid_code"}, /* hidden code , */\ + { 0x4100, "bypass_hp"}, /* Bypass_High Pass Filter , */\ + { 0x4110, "hard_mute"}, /* Hard Mute , */\ + { 0x4120, "soft_mute"}, /* Soft Mute , */\ + { 0x4134, "PWM_Delay"}, /* PWM DelayBits to set the delay , */\ + { 0x4180, "PWM_Shape"}, /* PWM Shape , */\ + { 0x4190, "PWM_BitLength"}, /* PWM Bitlength in noise shaper , */\ + { 0x4207, "ctrl_drive"}, /* drive bits to select amount of power stages amplifier, */\ + { 0x4281, "dpsalevel"}, /* DPSA Threshold level , */\ + { 0x42a1, "dpsa_release"}, /* DPSA Release time , */\ + { 0x42c0, "ctrl_coincidence"}, /* Prevent simultaneously switching of output stage , */\ + { 0x42d0, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x42e0, "ctrl_test_sdeltaoffset"}, /* ctrl_test_sdeltaoffset , */\ + { 0x42f0, "ctrl_test_sdeltaclk"}, /* ctrl_test_sdeltaclk , */\ + { 0x4309, "ctrl_drivebst"}, /* Drive bits to select the powertransistor sections boost converter, */\ + { 0x43a0, "ctrl_ocptestbst"}, /* Boost OCP. , */\ + { 0x43c0, "enbl_hi_peak"}, /* enable for high peak comparator , */\ + { 0x43d0, "test_abistfft_enbl"}, /* FFT coolflux , */\ + { 0x43e0, "ctrl_sensetest_amp"}, /* sensetest amplifier , */\ + { 0x43f0, "test_bcontrol"}, /* test _bcontrol , */\ + { 0x4400, "ctrl_reversebst"}, /* OverCurrent Protection selection of power stage boost converter, */\ + { 0x4410, "ctrl_sensetest"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0x4420, "enbl_engagebst"}, /* Enable power stage dcdc controller , */\ + { 0x4430, "enbl_hi_small"}, /* Enable bit of hi (small) comparator , */\ + { 0x4440, "enbl_hi_large"}, /* Enable bit of hi (large) comparator , */\ + { 0x4450, "enbl_lo_small"}, /* Enable bit of lo (small) comparator , */\ + { 0x4460, "enbl_lo_large"}, /* Enable bit of lo (large) comparator , */\ + { 0x4470, "enbl_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x4480, "enbl_voutcomp"}, /* Enable vout comparators , */\ + { 0x4490, "enbl_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x44a0, "enbl_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x44b0, "enbl_hizcom"}, /* Enable hiz comparator , */\ + { 0x44c0, "enbl_pcdac"}, /* Enable peak current dac , */\ + { 0x44d0, "enbl_pccomp"}, /* Enable peak current comparator , */\ + { 0x44e0, "enbl_windac"}, /* Enable window dac , */\ + { 0x44f0, "enbl_powerbst"}, /* Enable line of the powerstage , */\ + { 0x4507, "ocp_thr"}, /* ocp_thr threshold level for OCP , */\ + { 0x4580, "bypass_glitchfilter"}, /* Bypass glitchfilter , */\ + { 0x4590, "bypass_ovp"}, /* Bypass OVP , */\ + { 0x45a0, "bypass_uvp"}, /* Bypass UVP , */\ + { 0x45b0, "bypass_otp"}, /* Bypass OTP , */\ + { 0x45c0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0x45d0, "bypass_ocpcounter"}, /* BypassOCPCounter , */\ + { 0x45e0, "bypass_lost_clk"}, /* Bypasslost_clk detector , */\ + { 0x45f0, "vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0x4600, "bypass_gc"}, /* bypass_gc, bypasses the CS gain correction , */\ + { 0x4610, "cs_gain_control"}, /* gain control by means of MTP or i2c , */\ + { 0x4627, "cs_gain"}, /* + / - 128 steps in steps of 1/4 % 2's compliment , */\ + { 0x46a0, "bypass_lp"}, /* bypass Low-Pass filter in temperature sensor , */\ + { 0x46b0, "bypass_pwmcounter"}, /* bypass_pwmcounter , */\ + { 0x46c0, "ctrl_cs_negfixed"}, /* does not switch to neg , */\ + { 0x46d2, "ctrl_cs_neghyst"}, /* switches to neg depending on level , */\ + { 0x4700, "switch_fb"}, /* switch_fb , */\ + { 0x4713, "se_hyst"}, /* se_hyst , */\ + { 0x4754, "se_level"}, /* se_level , */\ + { 0x47a5, "ktemp"}, /* temperature compensation trimming , */\ + { 0x4800, "ctrl_negin"}, /* negin , */\ + { 0x4810, "ctrl_cs_sein"}, /* cs_sein , */\ + { 0x4820, "ctrl_coincidencecs"}, /* Coincidence current sense , */\ + { 0x4830, "ctrl_iddqtestbst"}, /* for iddq testing in powerstage of boost convertor , */\ + { 0x4840, "ctrl_coincidencebst"}, /* Switch protection on to prevent simultaniously switching power stages bst and amp, */\ + { 0x4851, "clock_sh_sel"}, /* Clock SH selection , */\ + { 0x4876, "delay_se_neg"}, /* delay of se and neg , */\ + { 0x48e1, "ctrl_cs_ttrack"}, /* sample & hold track time , */\ + { 0x4900, "ctrl_bypassclip"}, /* Bypass clip control (function depending on digimux clip_x), */\ + { 0x4910, "ctrl_bypassclip2"}, /* Bypass clip control (function depending on digimux clip_x), */\ + { 0x4920, "ctrl_clkgateCFoff"}, /* to disable clock gating in the coolflux , */\ + { 0x4930, "ctrl_testabst"}, /* testabst , */\ + { 0x4940, "ctrl_clipfast"}, /* clock switch for battery protection clipper, it switches back to old frequency, */\ + { 0x4950, "ctrl_cs_8ohm"}, /* 8 ohm mode for current sense (gain mode) , */\ + { 0x4960, "reserved"}, /* reserved , */\ + { 0x4974, "delay_clock_sh"}, /* delay_sh, tunes S7H delay , */\ + { 0x49c0, "inv_clksh"}, /* Invert the sample/hold clock for current sense ADC, */\ + { 0x49d0, "inv_neg"}, /* Invert neg signal , */\ + { 0x49e0, "inv_se"}, /* Invert se signal , */\ + { 0x49f0, "setse"}, /* switches between Single Ende and differentail mode, */\ + { 0x4a12, "ctrl_adc10_sel"}, /* select the input to convert the 10b ADC , */\ + { 0x4a60, "ctrl_adc10_reset"}, /* Global asynchronous reset (active HIGH) 10 bit ADC, */\ + { 0x4a81, "ctrl_adc10_test"}, /* Test mode selection signal 10 bit ADC , */\ + { 0x4aa0, "ctrl_bypass_lp_vbat"}, /* lp filter in batt sensor , */\ + { 0x4ae0, "ctrl_dc_offset"}, /* switch offset control on/off, is decimator offset control, */\ + { 0x4af0, "ctrl_tsense_hibias"}, /* bit to set the biasing in temp sensor to high , */\ + { 0x4b00, "ctrl_adc13_iset"}, /* Micadc Setting of current consumption. Debug use only, */\ + { 0x4b14, "ctrl_adc13_gain"}, /* Micadc gain setting (2-compl) , */\ + { 0x4b61, "ctrl_adc13_slowdel"}, /* Micadc Delay setting for internal clock. Debug use only, */\ + { 0x4b83, "ctrl_adc13_offset"}, /* Micadc ADC offset setting , */\ + { 0x4bc0, "ctrl_adc13_bsoinv"}, /* Micadc bit stream output invert mode for test , */\ + { 0x4bd0, "ctrl_adc13_resonator_enable"}, /* Micadc Give extra SNR with less stability. Debug use only, */\ + { 0x4be0, "ctrl_testmicadc"}, /* Mux at input of MICADC for test purpose , */\ + { 0x4c0f, "ctrl_offset"}, /* offset control for ABIST testing , */\ + { 0x4d05, "ctrl_windac"}, /* for testing direct control windac , */\ + { 0x4d65, "ctrl_peakcur"}, /* Control peakcur , */\ + { 0x4dc3, "pwm_dcc_cnt"}, /* control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0x4e04, "ctrl_slopecur"}, /* for testing direct control slopecur , */\ + { 0x4e53, "ctrl_dem"}, /* dyn element matching control, rest of codes are optional, */\ + { 0x4e93, "ctrl_demmismatch"}, /* dyn element matching add offset , */\ + { 0x4ed0, "enbl_pwm_dcc"}, /* to enable direct control of pwm duty cycle , */\ + { 0x5007, "gain"}, /* gain setting of the gain multiplier gain need to increase with factor 1.41 (3dB), */\ + { 0x5081, "ctrl_sourceb"}, /* Set OUTB to , */\ + { 0x50a1, "ctrl_sourcea"}, /* Set OUTA to , */\ + { 0x50c1, "ctrl_sourcebst"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0x50e1, "ctrl_test_mono"}, /* ABIST mode to add both amplifier halfs as stereo or one amplifier half as mono, */\ + { 0x5104, "pulselengthbst"}, /* pulselength setting test input for boost converter , */\ + { 0x5150, "ctrl_bypasslatchbst"}, /* bypass_latch in boost converter , */\ + { 0x5160, "invertbst"}, /* invert pwmbst test signal , */\ + { 0x5174, "pulselength"}, /* pulselength setting test input for amplifier , */\ + { 0x51c0, "ctrl_bypasslatch"}, /* bypass_latch in boost convert , */\ + { 0x51d0, "invertb"}, /* invert pwmb test signal , */\ + { 0x51e0, "inverta"}, /* invert pwma test signal , */\ + { 0x51f0, "ctrl_bypass_ctrlloop"}, /* bypass_ctrlloop bypasses the control loop of the amplifier, */\ + { 0x5200, "ctrl_test_discrete"}, /* tbd for rdson testing , */\ + { 0x5210, "ctrl_test_rdsona"}, /* tbd for rdson testing , */\ + { 0x5220, "ctrl_test_rdsonb"}, /* tbd for rdson testing , */\ + { 0x5230, "ctrl_test_rdsonbst"}, /* tbd for rdson testing , */\ + { 0x5240, "ctrl_test_cvia"}, /* tbd for rdson testing , */\ + { 0x5250, "ctrl_test_cvib"}, /* tbd for rdson testing , */\ + { 0x5260, "ctrl_test_cvibst"}, /* tbd for rdson testing , */\ + { 0x5290, "test_bypass_pwmdiscretea"}, /* for testing ( ABIST) , */\ + { 0x52a0, "test_bypass_pwmdiscreteb"}, /* for testing ( ABIST) , */\ + { 0x52b0, "ctrl_clipc_forcehigh"}, /* test signal for clipcontrol , */\ + { 0x52c0, "ctrl_clipc_forcelow"}, /* test signal for clipcontrol , */\ + { 0x52d0, "ctrl_test_sdelta"}, /* for testing ( ABIST) , */\ + { 0x52e0, "ctrl_test_swhvp"}, /* for testing ( ABIST) , */\ + { 0x52f0, "test_gain_reduction"}, /* test gain reduction , */\ + { 0x5303, "ctrl_digimux_out_test1"}, /* Digimux TEST1 out , */\ + { 0x5343, "ctrl_digimux_out_test2"}, /* Digimux TEST2 out. output flag_clipa_low depending on cntr_bypassclip setting, */\ + { 0x5383, "ctrl_digimux_out_data1"}, /* Digimux DATA1 out (output flag_clipb_high depending on cntr_bypassclip setting), */\ + { 0x53c3, "ctrl_digimux_out_data3"}, /* Digimux DATA3 out (output flag_clipx_x depending on cntr_bypassclip setting), */\ + { 0x5400, "hs_mode"}, /* hs_mode, high speed mode I2C bus , */\ + { 0x5412, "test_parametric_io"}, /* test_parametric_io for testing pads , */\ + { 0x5440, "enbl_ringo"}, /* enbl_ringo, for test purpose to check with ringo , */\ + { 0x5480, "ctrl_cliplevel"}, /* Clip level , */\ + { 0x5491, "ctrl_anamux_sel"}, /* anamux selection , */\ + { 0x54b0, "test_vdddsw_dio"}, /* to overrule the power switches for memory , */\ + { 0x54c0, "ctrl_bypass_diosw_ovp"}, /* To disable the overvoltage protection of vddd_dio_sw, */\ + { 0x54d0, "test_vddd_sw"}, /* test vdd sw , */\ + { 0x54e0, "test_vddd_sw_comp"}, /* test vdd sw comp , */\ + { 0x550e, "enbl_amp"}, /* enbl_amp for testing to enable all analoge blocks in amplifier, */\ + { 0x55f0, "fr_fsp"}, /* extr free running clock mode for testing , */\ + { 0x5600, "use_direct_ctrls"}, /* use_direct_ctrls, to overrule several functions direct for testing, */\ + { 0x5610, "rst_datapath"}, /* rst_datapath, datapath reset , */\ + { 0x5620, "rst_cgu"}, /* rst_cgu, cgu reset , */\ + { 0x5637, "enbl_ref"}, /* for testing to enable all analoge blocks in references, */\ + { 0x56b0, "enbl_engage"}, /* Enable output stage amplifier , */\ + { 0x56c0, "use_direct_clk_ctrl"}, /* use_direct_clk_ctrl, to overrule several functions direct for testing, */\ + { 0x56d0, "use_direct_pll_ctrl"}, /* use_direct_pll_ctrl, to overrule several functions direct for test, */\ + { 0x56e0, "use_direct_ctrls_2"}, /* use_direct_sourseamp_ctrls, to overrule several functions direct for testing, */\ + { 0x5707, "ctrl_anamux_out_test1"}, /* Anamux control , */\ + { 0x5782, "ctrl_zero"}, /* Bandwith control feedbackloop , */\ + { 0x57b0, "enbl_ldo_stress"}, /* LDO stress function frinch capacitors , */\ + { 0x57c0, "ctrl_ocptest"}, /* ctrl_ocptest, deactivates the over current protection in the power stages of the amplifier. The ocp flag signals stay active., */\ + { 0x57e0, "ctrl_otptest"}, /* otptest, test mode otp amplifier , */\ + { 0x57f0, "ctrl_reverse"}, /* CTRL revers , */\ + { 0x5802, "pll_mdec_msb"}, /* most significant bits pll_mdec , */\ + { 0x5833, "pll_selr"}, /* pll_selr , */\ + { 0x5874, "pll_selp"}, /* pll_selp , */\ + { 0x58c3, "pll_seli"}, /* pll_seli , */\ + { 0x5900, "pll_psel"}, /* pll_psel , */\ + { 0x5910, "use_direct_pll_psel"}, /* use_direct_pll_psel , */\ + { 0x5923, "nbck"}, /* NBCK , */\ + { 0x5960, "auto_nbck"}, /* AUTO_NBCK , */\ + { 0x5970, "pll_frm"}, /* pll_frm , */\ + { 0x5980, "pll_directi"}, /* pll_directi , */\ + { 0x5990, "pll_directo"}, /* pll_directo , */\ + { 0x59a0, "enbl_PLL"}, /* enbl_PLL , */\ + { 0x59b0, "sel_clkout"}, /* SEL_CLKOUT , */\ + { 0x59e0, "fr_lost_clk"}, /* fr_lost_clk , */\ + { 0x59f0, "pll_bypass"}, /* pll_bypass , */\ + { 0x5a0f, "tsig_freq"}, /* tsig_freq, internal sinus test generator, frequency control, */\ + { 0x5b02, "tsig_freq_msb"}, /* select internal sinus test generator, frequency control msb bits, */\ + { 0x5b30, "inject_tsig"}, /* inject_tsig, control bit to switch to internal sinus test generator, */\ + { 0x5b44, "ctrl_adc10_prog_sample"}, /* control ADC10 , */\ + { 0x5c01, "pll_ndec_msb"}, /* most significant bits of pll_ndec , */\ + { 0x5c2d, "pll_mdec"}, /* bits 13..0 of pll_mdec , */\ + { 0x5d06, "pll_pdec"}, /* pll_pdec , */\ + { 0x5d87, "pll_ndec"}, /* bits 7..0 of pll_ndec , */\ + { 0x5e00, "pdm_ch_sel_reg"}, /* PDM channel selection , */\ + { 0x5e10, "pdm_iis_rst_reg"}, /* PDM Interface reset , */\ + { 0x5e20, "clk_src_sel_reg"}, /* WS Source Selection , */\ + { 0x5e70, "pdm_resync_bypass"}, /* PDM resynchronization bypass , */\ + { 0x6007, "MTP_key1"}, /* MTP Key1 , */\ + { 0x6185, "mtp_ecc_tcin"}, /* Mtp_ecc_tcin , */\ + { 0x6203, "mtp_man_address_in"}, /* address from i2cregs for writing one word single mtp, */\ + { 0x6260, "mtp_ecc_eeb"}, /* enable code bit generation (active low!) , */\ + { 0x6270, "mtp_ecc_ecb"}, /* enable correction signal (active low!) , */\ + { 0x6280, "man_copy_mtp_to_iic"}, /* start copying single word from mtp to i2cregs_mtp , */\ + { 0x6290, "man_copy_iic_to_mtp"}, /* start copying single word from i2cregs_mtp to mtp [Key 1 protected], */\ + { 0x62a0, "auto_copy_mtp_to_iic"}, /* start copying all the data from mtp to i2cregs_mtp, */\ + { 0x62b0, "auto_copy_iic_to_mtp"}, /* start copying all the data from i2cregs_mtp to mtp [Key 2 protected], */\ + { 0x62d2, "mtp_speed_mode"}, /* Speed mode , */\ + { 0x6340, "mtp_dircet_enable"}, /* mtp_direct_enable (key1 protected) , */\ + { 0x6350, "mtp_direct_wr"}, /* mtp_direct_wr (key1 protected) direct value for mtp pin wr. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x6360, "mtp_direct_rd"}, /* mtp_direct_rd (key1 protected) direct value for mtp pin rd. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x6370, "mtp_direct_rst"}, /* mtp_direct_rst (key1 protected) direct value for mtp pin rst. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x6380, "mtp_direct_ers"}, /* mtp_direct_ers (key1 protected) direct value for mtp pin ers. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x6390, "mtp_direct_prg"}, /* mtp_direct_prg (key1 protected) direct value for mtp pin prg. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x63a0, "mtp_direct_epp"}, /* mtp_direct_epp (key1 protected) direct value for mtp pin epp. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x63b4, "mtp_direct_test"}, /* mtp_direct_test (key1 protected) , */\ + { 0x640f, "mtp_man_data_in"}, /* single wordt be written to MTP (manual copy) , */\ + { 0x7000, "cf_rst_dsp"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "cf_dmem"}, /* Target memory for access , */\ + { 0x7030, "cf_aif"}, /* Autoincrement-flag for memory-address , */\ + { 0x7040, "cf_int"}, /* Interrupt CoolFlux DSP , */\ + { 0x7087, "cf_req"}, /* request for access (8 channels) , */\ + { 0x710f, "cf_madd"}, /* memory-address to be accessed , */\ + { 0x720f, "cf_mema"}, /* activate memory access (24- or 32-bits data is written/read to/from memory, */\ + { 0x7307, "cf_err"}, /* cf error Flags , */\ + { 0x7387, "cf_ack"}, /* acknowledge of requests (8 channels")" , */\ + { 0x8000, "calibration_onetime"}, /* Calibration schedule (key2 protected) , */\ + { 0x8010, "calibr_ron_done"}, /* (key2 protected) calibration of Ron has been executed, */\ + { 0x8105, "calibr_vout_offset"}, /* calibr_vout_offset (DCDCoffset) 2's compliment (key1 protected), */\ + { 0x8163, "calibr_delta_gain"}, /* delta gain for vamp (alpha) 2's compliment (key1 protected), */\ + { 0x81a5, "calibr_offs_amp"}, /* offset for vamp (Ampoffset) 2's compliment (key1 protected), */\ + { 0x8207, "calibr_gain_cs"}, /* gain current sense (Imeasalpha) 2's compliment (key1 protected), */\ + { 0x8284, "calibr_temp_offset"}, /* temperature offset 2's compliment (key1 protected), */\ + { 0x82d2, "calibr_temp_gain"}, /* temperature gain 2's compliment (key1 protected) , */\ + { 0x830f, "calibr_ron"}, /* Ron resistance of coil (key1 protected) , */\ + { 0x8406, "ctrl_offset_a"}, /* Offset of amplifier level shifter , */\ + { 0x8486, "ctrl_offset_b"}, /* Offset of amplifier level shifter , */\ + { 0x850f, "type_bits_HW"}, /* HW Bits , */\ + { 0x860f, "type_bits1_SW"}, /* MTP-control SW1 , */\ + { 0x870f, "type_bits2_SW"}, /* MTP-control SW2 , */\ + { 0x8a0f, "production_data1"}, /* (key1 protected) , */\ + { 0x8b0f, "production_data2"}, /* (key1 protected) , */\ + { 0x8c0f, "production_data3"}, /* (key1 protected) , */\ + { 0x8d0f, "production_data4"}, /* (key1 protected) , */\ + { 0x8e0f, "production_data5"}, /* (key1 protected) , */\ + { 0x8f0f, "production_data6"}, /* (key1 protected) , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + + +#endif /* TFA_INC_TFA9891_TFAFIELDNAMES_H_ */ diff --git a/sound/soc/codecs/tfa9894_tfafieldnames.h b/sound/soc/codecs/tfa9894_tfafieldnames.h new file mode 100644 index 000000000000..327c15eef5bf --- /dev/null +++ b/sound/soc/codecs/tfa9894_tfafieldnames.h @@ -0,0 +1,1072 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9894_TFAFIELDNAMES_H +#define _TFA9894_TFAFIELDNAMES_H + + +#define TFA9894_I2CVERSION 17.0 + +typedef enum nxpTfa9894BfEnumList { + TFA9894_BF_PWDN = 0x0000, /*!< Powerdown control */ + TFA9894_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA9894_BF_CFE = 0x0020, /*!< Enable CoolFlux DSP */ + TFA9894_BF_AMPE = 0x0030, /*!< Enable Amplifier */ + TFA9894_BF_DCA = 0x0040, /*!< Enable DCDC Boost converter */ + TFA9894_BF_SBSL = 0x0050, /*!< Coolflux configured */ + TFA9894_BF_AMPC = 0x0060, /*!< CoolFlux control over amplifier */ + TFA9894_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA9894_BF_FSSSEL = 0x0090, /*!< Audio sample reference */ + TFA9894_BF_BYPOCP = 0x00a0, /*!< Bypass OCP */ + TFA9894_BF_TSTOCP = 0x00b0, /*!< OCP testing control */ + TFA9894_BF_BSSS = 0x00c0, /*!< Vbat protection steepness */ + TFA9894_BF_HPFBYP = 0x00d0, /*!< Bypass High Pass Filter */ + TFA9894_BF_DPSA = 0x00e0, /*!< Enable DPSA */ + TFA9894_BF_AMPINSEL = 0x0101, /*!< Amplifier input selection */ + TFA9894_BF_MANSCONF = 0x0120, /*!< Device I2C settings configured */ + TFA9894_BF_MANCOLD = 0x0130, /*!< Execute cold start */ + TFA9894_BF_MANROBOD = 0x0140, /*!< Reaction on BOD */ + TFA9894_BF_BODE = 0x0150, /*!< Enable BOD (only in direct control mode) */ + TFA9894_BF_BODHYS = 0x0160, /*!< Enable Hysteresis of BOD */ + TFA9894_BF_BODFILT = 0x0171, /*!< BOD filter */ + TFA9894_BF_BODTHLVL = 0x0191, /*!< BOD threshold */ + TFA9894_BF_MUTETO = 0x01b0, /*!< Time out SB mute sequence */ + TFA9894_BF_MANWDE = 0x01c0, /*!< Watchdog enable */ + TFA9894_BF_OPENMTP = 0x01e0, /*!< Control for FAIM protection */ + TFA9894_BF_FAIMVBGOVRRL = 0x01f0, /*!< Overrule the enabling of VBG for faim erase/write access */ + TFA9894_BF_AUDFS = 0x0203, /*!< Audio sample rate Fs */ + TFA9894_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ + TFA9894_BF_FRACTDEL = 0x0255, /*!< Current sense fractional delay */ + TFA9894_BF_TDMPRES = 0x02b1, /*!< Control for HW manager */ + TFA9894_BF_AMPOCRT = 0x02d2, /*!< Amplifier on-off criteria for shutdown */ + TFA9894_BF_REV = 0x030f, /*!< Revision info */ + TFA9894_BF_REFCKEXT = 0x0401, /*!< PLL external reference clock */ + TFA9894_BF_REFCKSEL = 0x0420, /*!< PLL internal reference clock */ + TFA9894_BF_MCLKSEL = 0x0432, /*!< Master Clock Selection */ + TFA9894_BF_MANAOOSC = 0x0460, /*!< Internal OSC1M off at PWDN */ + TFA9894_BF_ACKCLDDIS = 0x0470, /*!< Automatic PLL reference clock selection for cold start */ + TFA9894_BF_SPKSSEN = 0x0510, /*!< Enable speaker sub-system */ + TFA9894_BF_MTPSSEN = 0x0520, /*!< Enable FAIM sub-system */ + TFA9894_BF_WDTCLKEN = 0x0530, /*!< Enable Coolflux watchdog clock */ + TFA9894_BF_VDDS = 0x1000, /*!< POR */ + TFA9894_BF_PLLS = 0x1010, /*!< PLL Lock */ + TFA9894_BF_OTDS = 0x1020, /*!< OTP alarm */ + TFA9894_BF_OVDS = 0x1030, /*!< OVP alarm */ + TFA9894_BF_UVDS = 0x1040, /*!< UVP alarm */ + TFA9894_BF_OCDS = 0x1050, /*!< OCP amplifier (sticky register, clear on read) */ + TFA9894_BF_CLKS = 0x1060, /*!< Clocks stable */ + TFA9894_BF_MTPB = 0x1070, /*!< MTP busy */ + TFA9894_BF_NOCLK = 0x1080, /*!< Lost clock */ + TFA9894_BF_ACS = 0x1090, /*!< Cold Start */ + TFA9894_BF_WDS = 0x10a0, /*!< Watchdog */ + TFA9894_BF_SWS = 0x10b0, /*!< Amplifier engage */ + TFA9894_BF_AMPS = 0x10c0, /*!< Amplifier enable */ + TFA9894_BF_AREFS = 0x10d0, /*!< References enable */ + TFA9894_BF_ADCCR = 0x10e0, /*!< Control ADC */ + TFA9894_BF_BODNOK = 0x10f0, /*!< BOD Flag - VDD NOT OK */ + TFA9894_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA9894_BF_DCDCA = 0x1110, /*!< DCDC active (sticky register, clear on read) */ + TFA9894_BF_DCOCPOK = 0x1120, /*!< DCDC OCP nmos (sticky register, clear on read) */ + TFA9894_BF_DCHVBAT = 0x1140, /*!< DCDC level 1x */ + TFA9894_BF_DCH114 = 0x1150, /*!< DCDC level 1.14x */ + TFA9894_BF_DCH107 = 0x1160, /*!< DCDC level 1.07x */ + TFA9894_BF_SPKS = 0x1170, /*!< Speaker status */ + TFA9894_BF_CLKOOR = 0x1180, /*!< External clock status */ + TFA9894_BF_MANALARM = 0x1190, /*!< Alarm state */ + TFA9894_BF_TDMERR = 0x11a0, /*!< TDM error */ + TFA9894_BF_TDMLUTER = 0x11b0, /*!< TDM lookup table error */ + TFA9894_BF_OCPOAP = 0x1200, /*!< OCPOK pmos A */ + TFA9894_BF_OCPOAN = 0x1210, /*!< OCPOK nmos A */ + TFA9894_BF_OCPOBP = 0x1220, /*!< OCPOK pmos B */ + TFA9894_BF_OCPOBN = 0x1230, /*!< OCPOK nmos B */ + TFA9894_BF_CLIPS = 0x1240, /*!< Amplifier clipping */ + TFA9894_BF_MANMUTE = 0x1250, /*!< Audio mute sequence */ + TFA9894_BF_MANOPER = 0x1260, /*!< Device in Operating state */ + TFA9894_BF_LP1 = 0x1270, /*!< Low power MODE1 detection */ + TFA9894_BF_LA = 0x1280, /*!< Low amplitude detection */ + TFA9894_BF_VDDPH = 0x1290, /*!< VDDP greater than VBAT flag */ + TFA9894_BF_TDMSTAT = 0x1402, /*!< TDM Status bits */ + TFA9894_BF_MANSTATE = 0x1433, /*!< Device Manager status */ + TFA9894_BF_DCMODE = 0x14b1, /*!< DCDC mode status bits */ + TFA9894_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA9894_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA9894_BF_VDDPS = 0x1709, /*!< IC VDDP voltage (1023*VDDP/13V) */ + TFA9894_BF_TDME = 0x2000, /*!< Enable interface */ + TFA9894_BF_TDMSPKE = 0x2010, /*!< Control audio tdm channel in sink0 */ + TFA9894_BF_TDMDCE = 0x2020, /*!< Control audio tdm channel in sink1 */ + TFA9894_BF_TDMCSE = 0x2030, /*!< Source 0 enable */ + TFA9894_BF_TDMVSE = 0x2040, /*!< Source 1 enable */ + TFA9894_BF_TDMCFE = 0x2050, /*!< Source 2 enable */ + TFA9894_BF_TDMCF2E = 0x2060, /*!< Source 3 enable */ + TFA9894_BF_TDMCLINV = 0x2070, /*!< Reception data to BCK clock */ + TFA9894_BF_TDMFSPOL = 0x2080, /*!< FS polarity */ + TFA9894_BF_TDMDEL = 0x2090, /*!< Data delay to FS */ + TFA9894_BF_TDMADJ = 0x20a0, /*!< Data adjustment */ + TFA9894_BF_TDMOOMP = 0x20b1, /*!< Received audio compression */ + TFA9894_BF_TDMNBCK = 0x2103, /*!< TDM NBCK - Bit clock to FS ratio */ + TFA9894_BF_TDMFSLN = 0x2143, /*!< FS length (master mode only) */ + TFA9894_BF_TDMSLOTS = 0x2183, /*!< N-slots in Frame */ + TFA9894_BF_TDMTXDFO = 0x21c1, /*!< Format unused bits */ + TFA9894_BF_TDMTXUS = 0x21e1, /*!< Format unused slots DATAO */ + TFA9894_BF_TDMSLLN = 0x2204, /*!< N-bits in slot */ + TFA9894_BF_TDMBRMG = 0x2254, /*!< N-bits remaining */ + TFA9894_BF_TDMSSIZE = 0x22a4, /*!< Sample size per slot */ + TFA9894_BF_TDMSPKS = 0x2303, /*!< TDM slot for sink 0 */ + TFA9894_BF_TDMDCS = 0x2343, /*!< TDM slot for sink 1 */ + TFA9894_BF_TDMCFSEL = 0x2381, /*!< TDM Source 2 data selection */ + TFA9894_BF_TDMCF2SEL = 0x23a1, /*!< TDM Source 3 data selection */ + TFA9894_BF_TDMCSS = 0x2403, /*!< Slot Position of source 0 data */ + TFA9894_BF_TDMVSS = 0x2443, /*!< Slot Position of source 1 data */ + TFA9894_BF_TDMCFS = 0x2483, /*!< Slot Position of source 2 data */ + TFA9894_BF_TDMCF2S = 0x24c3, /*!< Slot Position of source 3 data */ + TFA9894_BF_ISTVDDS = 0x4000, /*!< Status POR */ + TFA9894_BF_ISTBSTOC = 0x4010, /*!< Status DCDC OCP */ + TFA9894_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ + TFA9894_BF_ISTOCPR = 0x4030, /*!< Status OCP alarm */ + TFA9894_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ + TFA9894_BF_ISTMANALARM = 0x4050, /*!< Status manager alarm state */ + TFA9894_BF_ISTTDMER = 0x4060, /*!< Status TDM error */ + TFA9894_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ + TFA9894_BF_ISTCFMER = 0x4080, /*!< Status cfma error */ + TFA9894_BF_ISTCFMAC = 0x4090, /*!< Status cfma ack */ + TFA9894_BF_ISTSPKS = 0x40a0, /*!< Status coolflux speaker error */ + TFA9894_BF_ISTACS = 0x40b0, /*!< Status cold started */ + TFA9894_BF_ISTWDS = 0x40c0, /*!< Status watchdog reset */ + TFA9894_BF_ISTBODNOK = 0x40d0, /*!< Status brown out detect */ + TFA9894_BF_ISTLP1 = 0x40e0, /*!< Status low power mode1 detect */ + TFA9894_BF_ISTCLKOOR = 0x40f0, /*!< Status clock out of range */ + TFA9894_BF_ICLVDDS = 0x4400, /*!< Clear POR */ + TFA9894_BF_ICLBSTOC = 0x4410, /*!< Clear DCDC OCP */ + TFA9894_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ + TFA9894_BF_ICLOCPR = 0x4430, /*!< Clear OCP alarm */ + TFA9894_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ + TFA9894_BF_ICLMANALARM = 0x4450, /*!< Clear manager alarm state */ + TFA9894_BF_ICLTDMER = 0x4460, /*!< Clear TDM error */ + TFA9894_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ + TFA9894_BF_ICLCFMER = 0x4480, /*!< Clear cfma err */ + TFA9894_BF_ICLCFMAC = 0x4490, /*!< Clear cfma ack */ + TFA9894_BF_ICLSPKS = 0x44a0, /*!< Clear coolflux speaker error */ + TFA9894_BF_ICLACS = 0x44b0, /*!< Clear cold started */ + TFA9894_BF_ICLWDS = 0x44c0, /*!< Clear watchdog reset */ + TFA9894_BF_ICLBODNOK = 0x44d0, /*!< Clear brown out detect */ + TFA9894_BF_ICLLP1 = 0x44e0, /*!< Clear low power mode1 detect */ + TFA9894_BF_ICLCLKOOR = 0x44f0, /*!< Clear clock out of range */ + TFA9894_BF_IEVDDS = 0x4800, /*!< Enable POR */ + TFA9894_BF_IEBSTOC = 0x4810, /*!< Enable DCDC OCP */ + TFA9894_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ + TFA9894_BF_IEOCPR = 0x4830, /*!< Enable OCP alarm */ + TFA9894_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ + TFA9894_BF_IEMANALARM = 0x4850, /*!< Enable Manager Alarm state */ + TFA9894_BF_IETDMER = 0x4860, /*!< Enable TDM error */ + TFA9894_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ + TFA9894_BF_IECFMER = 0x4880, /*!< Enable cfma err */ + TFA9894_BF_IECFMAC = 0x4890, /*!< Enable cfma ack */ + TFA9894_BF_IESPKS = 0x48a0, /*!< Enable coolflux speaker error */ + TFA9894_BF_IEACS = 0x48b0, /*!< Enable cold started */ + TFA9894_BF_IEWDS = 0x48c0, /*!< Enable watchdog reset */ + TFA9894_BF_IEBODNOK = 0x48d0, /*!< Enable brown out detect */ + TFA9894_BF_IELP1 = 0x48e0, /*!< Enable low power mode1 detect */ + TFA9894_BF_IECLKOOR = 0x48f0, /*!< Enable clock out of range */ + TFA9894_BF_IPOVDDS = 0x4c00, /*!< Polarity POR */ + TFA9894_BF_IPOBSTOC = 0x4c10, /*!< Polarity DCDC OCP */ + TFA9894_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ + TFA9894_BF_IPOOCPR = 0x4c30, /*!< Polarity ocp alarm */ + TFA9894_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ + TFA9894_BF_IPOMANALARM = 0x4c50, /*!< Polarity manager alarm state */ + TFA9894_BF_IPOTDMER = 0x4c60, /*!< Polarity TDM error */ + TFA9894_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ + TFA9894_BF_IPOCFMER = 0x4c80, /*!< Polarity cfma err */ + TFA9894_BF_IPOCFMAC = 0x4c90, /*!< Polarity cfma ack */ + TFA9894_BF_IPOSPKS = 0x4ca0, /*!< Polarity coolflux speaker error */ + TFA9894_BF_IPOACS = 0x4cb0, /*!< Polarity cold started */ + TFA9894_BF_IPOWDS = 0x4cc0, /*!< Polarity watchdog reset */ + TFA9894_BF_IPOBODNOK = 0x4cd0, /*!< Polarity brown out detect */ + TFA9894_BF_IPOLP1 = 0x4ce0, /*!< Polarity low power mode1 detect */ + TFA9894_BF_IPOCLKOOR = 0x4cf0, /*!< Polarity clock out of range */ + TFA9894_BF_BSSCR = 0x5001, /*!< Battery safeguard attack time */ + TFA9894_BF_BSST = 0x5023, /*!< Battery safeguard threshold voltage level */ + TFA9894_BF_BSSRL = 0x5061, /*!< Battery safeguard maximum reduction */ + TFA9894_BF_BSSRR = 0x5082, /*!< Battery safeguard release time */ + TFA9894_BF_BSSHY = 0x50b1, /*!< Battery Safeguard hysteresis */ + TFA9894_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA9894_BF_BSSBY = 0x50f0, /*!< Bypass HW clipper */ + TFA9894_BF_CFSM = 0x5130, /*!< Coolflux firmware soft mute control */ + TFA9894_BF_VOL = 0x5187, /*!< CF firmware volume control */ + TFA9894_BF_CLIPCTRL = 0x5202, /*!< Clip control setting */ + TFA9894_BF_SLOPEE = 0x5230, /*!< Enables slope control */ + TFA9894_BF_SLOPESET = 0x5240, /*!< Slope speed setting (binary coded) */ + TFA9894_BF_AMPGAIN = 0x5287, /*!< Amplifier gain */ + TFA9894_BF_TDMDCG = 0x5703, /*!< Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE) */ + TFA9894_BF_TDMSPKG = 0x5743, /*!< Total gain depending on INPLEV setting (channel 0) */ + TFA9894_BF_DCINSEL = 0x5781, /*!< VAMP_OUT2 input selection */ + TFA9894_BF_LNMODE = 0x5881, /*!< Low noise gain mode control */ + TFA9894_BF_LPM1MODE = 0x5ac1, /*!< Low power mode control */ + TFA9894_BF_TDMSRCMAP = 0x5d02, /*!< TDM source mapping */ + TFA9894_BF_TDMSRCAS = 0x5d31, /*!< Sensed value A */ + TFA9894_BF_TDMSRCBS = 0x5d51, /*!< Sensed value B */ + TFA9894_BF_TDMSRCACLIP = 0x5d71, /*!< Clip information (analog /digital) for source0 */ + TFA9894_BF_TDMSRCBCLIP = 0x5d91, /*!< Clip information (analog /digital) for source1 */ + TFA9894_BF_DELCURCOMP = 0x6102, /*!< Delay to allign compensation signal with current sense signal */ + TFA9894_BF_SIGCURCOMP = 0x6130, /*!< Polarity of compensation for current sense */ + TFA9894_BF_ENCURCOMP = 0x6140, /*!< Enable current sense compensation */ + TFA9894_BF_LVLCLPPWM = 0x6152, /*!< Set the amount of pwm pulse that may be skipped before clip-flag is triggered */ + TFA9894_BF_DCVOF = 0x7005, /*!< First Boost Voltage Level */ + TFA9894_BF_DCVOS = 0x7065, /*!< Second Boost Voltage Level */ + TFA9894_BF_DCMCC = 0x70c3, /*!< Max Coil Current */ + TFA9894_BF_DCCV = 0x7101, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ + TFA9894_BF_DCIE = 0x7120, /*!< Adaptive boost mode */ + TFA9894_BF_DCSR = 0x7130, /*!< Soft ramp up/down */ + TFA9894_BF_DCDIS = 0x7140, /*!< DCDC on/off */ + TFA9894_BF_DCPWM = 0x7150, /*!< DCDC PWM only mode */ + TFA9894_BF_DCTRACK = 0x7160, /*!< Boost algorithm selection, effective only when boost_intelligent is set to 1 */ + TFA9894_BF_DCENVSEL = 0x7170, /*!< Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1 */ + TFA9894_BF_DCTRIP = 0x7204, /*!< 1st adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9894_BF_DCTRIP2 = 0x7254, /*!< 2nd adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9894_BF_DCTRIPT = 0x72a4, /*!< Track adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ + TFA9894_BF_DCTRIPHYSTE = 0x72f0, /*!< Enable hysteresis on booster trip levels */ + TFA9894_BF_DCHOLD = 0x7304, /*!< Hold time for DCDC booster, effective only when boost_intelligent is set to 1 */ + TFA9894_BF_RST = 0x9000, /*!< Reset for Coolflux DSP */ + TFA9894_BF_DMEM = 0x9011, /*!< Target memory for CFMA using I2C interface */ + TFA9894_BF_AIF = 0x9030, /*!< Auto increment */ + TFA9894_BF_CFINT = 0x9040, /*!< Coolflux Interrupt - auto clear */ + TFA9894_BF_CFCGATE = 0x9050, /*!< Coolflux clock gating disabling control */ + TFA9894_BF_REQCMD = 0x9080, /*!< Firmware event request rpc command */ + TFA9894_BF_REQRST = 0x9090, /*!< Firmware event request reset restart */ + TFA9894_BF_REQMIPS = 0x90a0, /*!< Firmware event request short on mips */ + TFA9894_BF_REQMUTED = 0x90b0, /*!< Firmware event request mute sequence ready */ + TFA9894_BF_REQVOL = 0x90c0, /*!< Firmware event request volume ready */ + TFA9894_BF_REQDMG = 0x90d0, /*!< Firmware event request speaker damage detected */ + TFA9894_BF_REQCAL = 0x90e0, /*!< Firmware event request calibration completed */ + TFA9894_BF_REQRSV = 0x90f0, /*!< Firmware event request reserved */ + TFA9894_BF_MADD = 0x910f, /*!< CF memory address */ + TFA9894_BF_MEMA = 0x920f, /*!< Activate memory access */ + TFA9894_BF_ERR = 0x9307, /*!< CF error flags */ + TFA9894_BF_ACKCMD = 0x9380, /*!< Firmware event acknowledge rpc command */ + TFA9894_BF_ACKRST = 0x9390, /*!< Firmware event acknowledge reset restart */ + TFA9894_BF_ACKMIPS = 0x93a0, /*!< Firmware event acknowledge short on mips */ + TFA9894_BF_ACKMUTED = 0x93b0, /*!< Firmware event acknowledge mute sequence ready */ + TFA9894_BF_ACKVOL = 0x93c0, /*!< Firmware event acknowledge volume ready */ + TFA9894_BF_ACKDMG = 0x93d0, /*!< Firmware event acknowledge speaker damage detected */ + TFA9894_BF_ACKCAL = 0x93e0, /*!< Firmware event acknowledge calibration completed */ + TFA9894_BF_ACKRSV = 0x93f0, /*!< Firmware event acknowledge reserved */ + TFA9894_BF_MTPK = 0xa107, /*!< KEY2 to access KEY2 protected registers, customer key */ + TFA9894_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ + TFA9894_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ + TFA9894_BF_CMTPI = 0xa350, /*!< Start copying all the data from mtp to I2C mtp registers - auto clear */ + TFA9894_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp - auto clear */ + TFA9894_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ + TFA9894_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ + TFA9894_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA9894_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA9894_BF_SWPROFIL = 0xe00f, /*!< Software profile data */ + TFA9894_BF_SWVSTEP = 0xe10f, /*!< Software vstep information */ + TFA9894_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ + TFA9894_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA9894_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ + TFA9894_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA9894_BF_USERDEF = 0xf042, /*!< Calibration delta current limit DCDC */ + TFA9894_BF_CUSTINFO = 0xf078, /*!< Reserved space for allowing customer to store speaker information */ + TFA9894_BF_R25C = 0xf50f, /*!< Ron resistance of speaker coil */ +} nxpTfa9894BfEnumList_t; +#define TFA9894_NAMETABLE static tfaBfName_t Tfa9894DatasheetNames[] = {\ + { 0x0, "PWDN"}, /* Powerdown control , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x20, "CFE"}, /* Enable CoolFlux DSP , */\ + { 0x30, "AMPE"}, /* Enable Amplifier , */\ + { 0x40, "DCA"}, /* Enable DCDC Boost converter , */\ + { 0x50, "SBSL"}, /* Coolflux configured , */\ + { 0x60, "AMPC"}, /* CoolFlux control over amplifier , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0x90, "FSSSEL"}, /* Audio sample reference , */\ + { 0xa0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xb0, "TSTOCP"}, /* OCP testing control , */\ + { 0xc0, "BSSS"}, /* Vbat protection steepness , */\ + { 0xd0, "HPFBYP"}, /* Bypass High Pass Filter , */\ + { 0xe0, "DPSA"}, /* Enable DPSA , */\ + { 0x101, "AMPINSEL"}, /* Amplifier input selection , */\ + { 0x120, "MANSCONF"}, /* Device I2C settings configured , */\ + { 0x130, "MANCOLD"}, /* Execute cold start , */\ + { 0x140, "MANROBOD"}, /* Reaction on BOD , */\ + { 0x150, "BODE"}, /* Enable BOD (only in direct control mode) , */\ + { 0x160, "BODHYS"}, /* Enable Hysteresis of BOD , */\ + { 0x171, "BODFILT"}, /* BOD filter , */\ + { 0x191, "BODTHLVL"}, /* BOD threshold , */\ + { 0x1b0, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x1c0, "MANWDE"}, /* Watchdog enable , */\ + { 0x1e0, "OPENMTP"}, /* Control for FAIM protection , */\ + { 0x1f0, "FAIMVBGOVRRL"}, /* Overrule the enabling of VBG for faim erase/write access, */\ + { 0x203, "AUDFS"}, /* Audio sample rate Fs , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* Current sense fractional delay , */\ + { 0x2b1, "TDMPRES"}, /* Control for HW manager , */\ + { 0x2d2, "AMPOCRT"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external reference clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal reference clock , */\ + { 0x432, "MCLKSEL"}, /* Master Clock Selection , */\ + { 0x460, "MANAOOSC"}, /* Internal OSC1M off at PWDN , */\ + { 0x470, "ACKCLDDIS"}, /* Automatic PLL reference clock selection for cold start, */\ + { 0x510, "SPKSSEN"}, /* Enable speaker sub-system , */\ + { 0x520, "MTPSSEN"}, /* Enable FAIM sub-system , */\ + { 0x530, "WDTCLKEN"}, /* Enable Coolflux watchdog clock , */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "PLLS"}, /* PLL Lock , */\ + { 0x1020, "OTDS"}, /* OTP alarm , */\ + { 0x1030, "OVDS"}, /* OVP alarm , */\ + { 0x1040, "UVDS"}, /* UVP alarm , */\ + { 0x1050, "OCDS"}, /* OCP amplifier (sticky register, clear on read) , */\ + { 0x1060, "CLKS"}, /* Clocks stable , */\ + { 0x1070, "MTPB"}, /* MTP busy , */\ + { 0x1080, "NOCLK"}, /* Lost clock , */\ + { 0x1090, "ACS"}, /* Cold Start , */\ + { 0x10a0, "WDS"}, /* Watchdog , */\ + { 0x10b0, "SWS"}, /* Amplifier engage , */\ + { 0x10c0, "AMPS"}, /* Amplifier enable , */\ + { 0x10d0, "AREFS"}, /* References enable , */\ + { 0x10e0, "ADCCR"}, /* Control ADC , */\ + { 0x10f0, "BODNOK"}, /* BOD Flag - VDD NOT OK , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active (sticky register, clear on read) , */\ + { 0x1120, "DCOCPOK"}, /* DCDC OCP nmos (sticky register, clear on read) , */\ + { 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1170, "SPKS"}, /* Speaker status , */\ + { 0x1180, "CLKOOR"}, /* External clock status , */\ + { 0x1190, "MANALARM"}, /* Alarm state , */\ + { 0x11a0, "TDMERR"}, /* TDM error , */\ + { 0x11b0, "TDMLUTER"}, /* TDM lookup table error , */\ + { 0x1200, "OCPOAP"}, /* OCPOK pmos A , */\ + { 0x1210, "OCPOAN"}, /* OCPOK nmos A , */\ + { 0x1220, "OCPOBP"}, /* OCPOK pmos B , */\ + { 0x1230, "OCPOBN"}, /* OCPOK nmos B , */\ + { 0x1240, "CLIPS"}, /* Amplifier clipping , */\ + { 0x1250, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x1260, "MANOPER"}, /* Device in Operating state , */\ + { 0x1270, "LP1"}, /* Low power MODE1 detection , */\ + { 0x1280, "LA"}, /* Low amplitude detection , */\ + { 0x1290, "VDDPH"}, /* VDDP greater than VBAT flag , */\ + { 0x1402, "TDMSTAT"}, /* TDM Status bits , */\ + { 0x1433, "MANSTATE"}, /* Device Manager status , */\ + { 0x14b1, "DCMODE"}, /* DCDC mode status bits , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x1709, "VDDPS"}, /* IC VDDP voltage (1023*VDDP/13V) , */\ + { 0x2000, "TDME"}, /* Enable interface , */\ + { 0x2010, "TDMSPKE"}, /* Control audio tdm channel in sink0 , */\ + { 0x2020, "TDMDCE"}, /* Control audio tdm channel in sink1 , */\ + { 0x2030, "TDMCSE"}, /* Source 0 enable , */\ + { 0x2040, "TDMVSE"}, /* Source 1 enable , */\ + { 0x2050, "TDMCFE"}, /* Source 2 enable , */\ + { 0x2060, "TDMCF2E"}, /* Source 3 enable , */\ + { 0x2070, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2080, "TDMFSPOL"}, /* FS polarity , */\ + { 0x2090, "TDMDEL"}, /* Data delay to FS , */\ + { 0x20a0, "TDMADJ"}, /* Data adjustment , */\ + { 0x20b1, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2103, "TDMNBCK"}, /* TDM NBCK - Bit clock to FS ratio , */\ + { 0x2143, "TDMFSLN"}, /* FS length (master mode only) , */\ + { 0x2183, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x21c1, "TDMTXDFO"}, /* Format unused bits , */\ + { 0x21e1, "TDMTXUS0"}, /* Format unused slots DATAO , */\ + { 0x2204, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2254, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x22a4, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2303, "TDMSPKS"}, /* TDM slot for sink 0 , */\ + { 0x2343, "TDMDCS"}, /* TDM slot for sink 1 , */\ + { 0x2381, "TDMCFSEL"}, /* TDM Source 2 data selection , */\ + { 0x23a1, "TDMCF2SEL"}, /* TDM Source 3 data selection , */\ + { 0x2403, "TDMCSS"}, /* Slot Position of source 0 data , */\ + { 0x2443, "TDMVSS"}, /* Slot Position of source 1 data , */\ + { 0x2483, "TDMCFS"}, /* Slot Position of source 2 data , */\ + { 0x24c3, "TDMCF2S"}, /* Slot Position of source 3 data , */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOCPR"}, /* Status OCP alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTMANALARM"}, /* Status manager alarm state , */\ + { 0x4060, "ISTTDMER"}, /* Status TDM error , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4080, "ISTCFMER"}, /* Status cfma error , */\ + { 0x4090, "ISTCFMAC"}, /* Status cfma ack , */\ + { 0x40a0, "ISTSPKS"}, /* Status coolflux speaker error , */\ + { 0x40b0, "ISTACS"}, /* Status cold started , */\ + { 0x40c0, "ISTWDS"}, /* Status watchdog reset , */\ + { 0x40d0, "ISTBODNOK"}, /* Status brown out detect , */\ + { 0x40e0, "ISTLP1"}, /* Status low power mode1 detect , */\ + { 0x40f0, "ISTCLKOOR"}, /* Status clock out of range , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOCPR"}, /* Clear OCP alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLMANALARM"}, /* Clear manager alarm state , */\ + { 0x4460, "ICLTDMER"}, /* Clear TDM error , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4480, "ICLCFMER"}, /* Clear cfma err , */\ + { 0x4490, "ICLCFMAC"}, /* Clear cfma ack , */\ + { 0x44a0, "ICLSPKS"}, /* Clear coolflux speaker error , */\ + { 0x44b0, "ICLACS"}, /* Clear cold started , */\ + { 0x44c0, "ICLWDS"}, /* Clear watchdog reset , */\ + { 0x44d0, "ICLBODNOK"}, /* Clear brown out detect , */\ + { 0x44e0, "ICLLP1"}, /* Clear low power mode1 detect , */\ + { 0x44f0, "ICLCLKOOR"}, /* Clear clock out of range , */\ + { 0x4800, "IEVDDS"}, /* Enable POR , */\ + { 0x4810, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOCPR"}, /* Enable OCP alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IEMANALARM"}, /* Enable Manager Alarm state , */\ + { 0x4860, "IETDMER"}, /* Enable TDM error , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4880, "IECFMER"}, /* Enable cfma err , */\ + { 0x4890, "IECFMAC"}, /* Enable cfma ack , */\ + { 0x48a0, "IESPKS"}, /* Enable coolflux speaker error , */\ + { 0x48b0, "IEACS"}, /* Enable cold started , */\ + { 0x48c0, "IEWDS"}, /* Enable watchdog reset , */\ + { 0x48d0, "IEBODNOK"}, /* Enable brown out detect , */\ + { 0x48e0, "IELP1"}, /* Enable low power mode1 detect , */\ + { 0x48f0, "IECLKOOR"}, /* Enable clock out of range , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity POR , */\ + { 0x4c10, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOCPR"}, /* Polarity ocp alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOMANALARM"}, /* Polarity manager alarm state , */\ + { 0x4c60, "IPOTDMER"}, /* Polarity TDM error , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4c80, "IPOCFMER"}, /* Polarity cfma err , */\ + { 0x4c90, "IPOCFMAC"}, /* Polarity cfma ack , */\ + { 0x4ca0, "IPOSPKS"}, /* Polarity coolflux speaker error , */\ + { 0x4cb0, "IPOACS"}, /* Polarity cold started , */\ + { 0x4cc0, "IPOWDS"}, /* Polarity watchdog reset , */\ + { 0x4cd0, "IPOBODNOK"}, /* Polarity brown out detect , */\ + { 0x4ce0, "IPOLP1"}, /* Polarity low power mode1 detect , */\ + { 0x4cf0, "IPOCLKOOR"}, /* Polarity clock out of range , */\ + { 0x5001, "BSSCR"}, /* Battery safeguard attack time , */\ + { 0x5023, "BSST"}, /* Battery safeguard threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery safeguard maximum reduction , */\ + { 0x5082, "BSSRR"}, /* Battery safeguard release time , */\ + { 0x50b1, "BSSHY"}, /* Battery Safeguard hysteresis , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass HW clipper , */\ + { 0x5130, "CFSM"}, /* Coolflux firmware soft mute control , */\ + { 0x5187, "VOL"}, /* CF firmware volume control , */\ + { 0x5202, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5230, "SLOPEE"}, /* Enables slope control , */\ + { 0x5240, "SLOPESET"}, /* Slope speed setting (binary coded) , */\ + { 0x5287, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x5703, "TDMDCG"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5743, "TDMSPKG"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x5781, "DCINSEL"}, /* VAMP_OUT2 input selection , */\ + { 0x5881, "LNMODE"}, /* Low noise gain mode control , */\ + { 0x5ac1, "LPM1MODE"}, /* Low power mode control , */\ + { 0x5d02, "TDMSRCMAP"}, /* TDM source mapping , */\ + { 0x5d31, "TDMSRCAS"}, /* Sensed value A , */\ + { 0x5d51, "TDMSRCBS"}, /* Sensed value B , */\ + { 0x5d71, "TDMSRCACLIP"}, /* Clip information (analog /digital) for source0 , */\ + { 0x5d91, "TDMSRCBCLIP"}, /* Clip information (analog /digital) for source1 , */\ + { 0x6102, "DELCURCOMP"}, /* Delay to allign compensation signal with current sense signal, */\ + { 0x6130, "SIGCURCOMP"}, /* Polarity of compensation for current sense , */\ + { 0x6140, "ENCURCOMP"}, /* Enable current sense compensation , */\ + { 0x6152, "LVLCLPPWM"}, /* Set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7005, "DCVOF"}, /* First Boost Voltage Level , */\ + { 0x7065, "DCVOS"}, /* Second Boost Voltage Level , */\ + { 0x70c3, "DCMCC"}, /* Max Coil Current , */\ + { 0x7101, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7120, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7130, "DCSR"}, /* Soft ramp up/down , */\ + { 0x7140, "DCDIS"}, /* DCDC on/off , */\ + { 0x7150, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x7160, "DCTRACK"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7170, "DCENVSEL"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x7204, "DCTRIP"}, /* 1st adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7254, "DCTRIP2"}, /* 2nd adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x72a4, "DCTRIPT"}, /* Track adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x72f0, "DCTRIPHYSTE"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7304, "DCHOLD"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x9000, "RST"}, /* Reset for Coolflux DSP , */\ + { 0x9011, "DMEM"}, /* Target memory for CFMA using I2C interface , */\ + { 0x9030, "AIF"}, /* Auto increment , */\ + { 0x9040, "CFINT"}, /* Coolflux Interrupt - auto clear , */\ + { 0x9050, "CFCGATE"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "REQCMD"}, /* Firmware event request rpc command , */\ + { 0x9090, "REQRST"}, /* Firmware event request reset restart , */\ + { 0x90a0, "REQMIPS"}, /* Firmware event request short on mips , */\ + { 0x90b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "REQVOL"}, /* Firmware event request volume ready , */\ + { 0x90d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "REQCAL"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "REQRSV"}, /* Firmware event request reserved , */\ + { 0x910f, "MADD"}, /* CF memory address , */\ + { 0x920f, "MEMA"}, /* Activate memory access , */\ + { 0x9307, "ERR"}, /* CF error flags , */\ + { 0x9380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "ACKVOL"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "ACKDMG"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "ACKRSV"}, /* Firmware event acknowledge reserved , */\ + { 0xa107, "MTPK"}, /* KEY2 to access KEY2 protected registers, customer key, */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa350, "CMTPI"}, /* Start copying all the data from mtp to I2C mtp registers - auto clear, */\ + { 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp - auto clear, */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xe00f, "SWPROFIL"}, /* Software profile data , */\ + { 0xe10f, "SWVSTEP"}, /* Software vstep information , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "CUSTINFO"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf50f, "R25C"}, /* Ron resistance of speaker coil , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9894_BITNAMETABLE static tfaBfName_t Tfa9894BitNames[] = {\ + { 0x0, "powerdown"}, /* Powerdown control , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x20, "enbl_coolflux"}, /* Enable CoolFlux DSP , */\ + { 0x30, "enbl_amplifier"}, /* Enable Amplifier , */\ + { 0x40, "enbl_boost"}, /* Enable DCDC Boost converter , */\ + { 0x50, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x60, "sel_enbl_amplifier"}, /* CoolFlux control over amplifier , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0x90, "fs_pulse_sel"}, /* Audio sample reference , */\ + { 0xa0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xb0, "test_ocp"}, /* OCP testing control , */\ + { 0xc0, "batsense_steepness"}, /* Vbat protection steepness , */\ + { 0xd0, "bypass_hp"}, /* Bypass High Pass Filter , */\ + { 0xe0, "enbl_dpsa"}, /* Enable DPSA , */\ + { 0xf0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ + { 0x101, "vamp_sel1"}, /* Amplifier input selection , */\ + { 0x120, "src_set_configured"}, /* Device I2C settings configured , */\ + { 0x130, "execute_cold_start"}, /* Execute cold start , */\ + { 0x140, "man_enbl_brown_out"}, /* Reaction on BOD , */\ + { 0x150, "bod_enbl"}, /* Enable BOD (only in direct control mode) , */\ + { 0x160, "bod_hyst_enbl"}, /* Enable Hysteresis of BOD , */\ + { 0x171, "bod_delay_set"}, /* BOD filter , */\ + { 0x191, "bod_lvl_set"}, /* BOD threshold , */\ + { 0x1b0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x1c0, "man_enbl_watchdog"}, /* Watchdog enable , */\ + { 0x1d0, "disable_engage"}, /* Disable Engage , */\ + { 0x1e0, "unprotect_faim"}, /* Control for FAIM protection , */\ + { 0x1f0, "faim_enable_vbg"}, /* Overrule the enabling of VBG for faim erase/write access, */\ + { 0x203, "audio_fs"}, /* Audio sample rate Fs , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* Current sense fractional delay , */\ + { 0x2b1, "use_tdm_presence"}, /* Control for HW manager , */\ + { 0x2d2, "ctrl_on2off_criterion"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external reference clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal reference clock , */\ + { 0x432, "mclk_sel"}, /* Master Clock Selection , */\ + { 0x460, "enbl_osc1m_auto_off"}, /* Internal OSC1M off at PWDN , */\ + { 0x470, "disable_auto_sel_refclk"}, /* Automatic PLL reference clock selection for cold start, */\ + { 0x510, "enbl_spkr_ss"}, /* Enable speaker sub-system , */\ + { 0x520, "enbl_faim_ss"}, /* Enable FAIM sub-system , */\ + { 0x530, "enbl_wdt_clk"}, /* Enable Coolflux watchdog clock , */\ + { 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ + { 0xf0f, "hidden_code"}, /* Hidden code to enable access to hidden register. (0x5A6B/23147 default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_pll_lock"}, /* PLL Lock , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm , */\ + { 0x1030, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm , */\ + { 0x1050, "flag_ocp_alarm"}, /* OCP amplifier (sticky register, clear on read) , */\ + { 0x1060, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1070, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1080, "flag_lost_clk"}, /* Lost clock , */\ + { 0x1090, "flag_cold_started"}, /* Cold Start , */\ + { 0x10a0, "flag_watchdog_reset"}, /* Watchdog , */\ + { 0x10b0, "flag_engage"}, /* Amplifier engage , */\ + { 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x10d0, "flag_enbl_ref"}, /* References enable , */\ + { 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x10f0, "flag_bod_vddd_nok"}, /* BOD Flag - VDD NOT OK , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active (sticky register, clear on read) , */\ + { 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos (sticky register, clear on read) , */\ + { 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1170, "flag_cf_speakererror"}, /* Speaker status , */\ + { 0x1180, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x1190, "flag_man_alarm_state"}, /* Alarm state , */\ + { 0x11a0, "flag_tdm_error"}, /* TDM error , */\ + { 0x11b0, "flag_tdm_lut_error"}, /* TDM lookup table error , */\ + { 0x1200, "flag_ocpokap"}, /* OCPOK pmos A , */\ + { 0x1210, "flag_ocpokan"}, /* OCPOK nmos A , */\ + { 0x1220, "flag_ocpokbp"}, /* OCPOK pmos B , */\ + { 0x1230, "flag_ocpokbn"}, /* OCPOK nmos B , */\ + { 0x1240, "flag_clip"}, /* Amplifier clipping , */\ + { 0x1250, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x1260, "flag_man_operating_state"}, /* Device in Operating state , */\ + { 0x1270, "flag_lp_detect_mode1"}, /* Low power MODE1 detection , */\ + { 0x1280, "flag_low_amplitude"}, /* Low amplitude detection , */\ + { 0x1290, "flag_vddp_gt_vbat"}, /* VDDP greater than VBAT flag , */\ + { 0x1402, "tdm_status"}, /* TDM Status bits , */\ + { 0x1433, "man_state"}, /* Device Manager status , */\ + { 0x1473, "amp_ctrl_state"}, /* Amplifier control status , */\ + { 0x14b1, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x1709, "vddp_adc"}, /* IC VDDP voltage (1023*VDDP/13V) , */\ + { 0x2000, "tdm_enable"}, /* Enable interface , */\ + { 0x2010, "tdm_sink0_enable"}, /* Control audio tdm channel in sink0 , */\ + { 0x2020, "tdm_sink1_enable"}, /* Control audio tdm channel in sink1 , */\ + { 0x2030, "tdm_source0_enable"}, /* Source 0 enable , */\ + { 0x2040, "tdm_source1_enable"}, /* Source 1 enable , */\ + { 0x2050, "tdm_source2_enable"}, /* Source 2 enable , */\ + { 0x2060, "tdm_source3_enable"}, /* Source 3 enable , */\ + { 0x2070, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2080, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x2090, "tdm_data_delay"}, /* Data delay to FS , */\ + { 0x20a0, "tdm_data_adjustment"}, /* Data adjustment , */\ + { 0x20b1, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2103, "tdm_nbck"}, /* TDM NBCK - Bit clock to FS ratio , */\ + { 0x2143, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ + { 0x2183, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x21c1, "tdm_txdata_format"}, /* Format unused bits , */\ + { 0x21e1, "tdm_txdata_format_unused_slot"}, /* Format unused slots DATAO , */\ + { 0x2204, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2254, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x22a4, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2303, "tdm_sink0_slot"}, /* TDM slot for sink 0 , */\ + { 0x2343, "tdm_sink1_slot"}, /* TDM slot for sink 1 , */\ + { 0x2381, "tdm_source2_sel"}, /* TDM Source 2 data selection , */\ + { 0x23a1, "tdm_source3_sel"}, /* TDM Source 3 data selection , */\ + { 0x2403, "tdm_source0_slot"}, /* Slot Position of source 0 data , */\ + { 0x2443, "tdm_source1_slot"}, /* Slot Position of source 1 data , */\ + { 0x2483, "tdm_source2_slot"}, /* Slot Position of source 2 data , */\ + { 0x24c3, "tdm_source3_slot"}, /* Slot Position of source 3 data , */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ocp_alarm"}, /* Status OCP alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_man_alarm_state"}, /* Status manager alarm state , */\ + { 0x4060, "int_out_flag_tdm_error"}, /* Status TDM error , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4080, "int_out_flag_cfma_err"}, /* Status cfma error , */\ + { 0x4090, "int_out_flag_cfma_ack"}, /* Status cfma ack , */\ + { 0x40a0, "int_out_flag_cf_speakererror"}, /* Status coolflux speaker error , */\ + { 0x40b0, "int_out_flag_cold_started"}, /* Status cold started , */\ + { 0x40c0, "int_out_flag_watchdog_reset"}, /* Status watchdog reset , */\ + { 0x40d0, "int_out_flag_bod_vddd_nok"}, /* Status brown out detect , */\ + { 0x40e0, "int_out_flag_lp_detect_mode1"}, /* Status low power mode1 detect , */\ + { 0x40f0, "int_out_flag_clk_out_of_range"}, /* Status clock out of range , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ocp_alarm"}, /* Clear OCP alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_man_alarm_state"}, /* Clear manager alarm state , */\ + { 0x4460, "int_in_flag_tdm_error"}, /* Clear TDM error , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4480, "int_in_flag_cfma_err"}, /* Clear cfma err , */\ + { 0x4490, "int_in_flag_cfma_ack"}, /* Clear cfma ack , */\ + { 0x44a0, "int_in_flag_cf_speakererror"}, /* Clear coolflux speaker error , */\ + { 0x44b0, "int_in_flag_cold_started"}, /* Clear cold started , */\ + { 0x44c0, "int_in_flag_watchdog_reset"}, /* Clear watchdog reset , */\ + { 0x44d0, "int_in_flag_bod_vddd_nok"}, /* Clear brown out detect , */\ + { 0x44e0, "int_in_flag_lp_detect_mode1"}, /* Clear low power mode1 detect , */\ + { 0x44f0, "int_in_flag_clk_out_of_range"}, /* Clear clock out of range , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable POR , */\ + { 0x4810, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ocp_alarm"}, /* Enable OCP alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_man_alarm_state"}, /* Enable Manager Alarm state , */\ + { 0x4860, "int_enable_flag_tdm_error"}, /* Enable TDM error , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4880, "int_enable_flag_cfma_err"}, /* Enable cfma err , */\ + { 0x4890, "int_enable_flag_cfma_ack"}, /* Enable cfma ack , */\ + { 0x48a0, "int_enable_flag_cf_speakererror"}, /* Enable coolflux speaker error , */\ + { 0x48b0, "int_enable_flag_cold_started"}, /* Enable cold started , */\ + { 0x48c0, "int_enable_flag_watchdog_reset"}, /* Enable watchdog reset , */\ + { 0x48d0, "int_enable_flag_bod_vddd_nok"}, /* Enable brown out detect , */\ + { 0x48e0, "int_enable_flag_lp_detect_mode1"}, /* Enable low power mode1 detect , */\ + { 0x48f0, "int_enable_flag_clk_out_of_range"}, /* Enable clock out of range , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity POR , */\ + { 0x4c10, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_man_alarm_state"}, /* Polarity manager alarm state , */\ + { 0x4c60, "int_polarity_flag_tdm_error"}, /* Polarity TDM error , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4c80, "int_polarity_flag_cfma_err"}, /* Polarity cfma err , */\ + { 0x4c90, "int_polarity_flag_cfma_ack"}, /* Polarity cfma ack , */\ + { 0x4ca0, "int_polarity_flag_cf_speakererror"}, /* Polarity coolflux speaker error , */\ + { 0x4cb0, "int_polarity_flag_cold_started"}, /* Polarity cold started , */\ + { 0x4cc0, "int_polarity_flag_watchdog_reset"}, /* Polarity watchdog reset , */\ + { 0x4cd0, "int_polarity_flag_bod_vddd_nok"}, /* Polarity brown out detect , */\ + { 0x4ce0, "int_polarity_flag_lp_detect_mode1"}, /* Polarity low power mode1 detect , */\ + { 0x4cf0, "int_polarity_flag_clk_out_of_range"}, /* Polarity clock out of range , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery safeguard attack time , */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery safeguard threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery safeguard maximum reduction , */\ + { 0x5082, "vbat_prot_release_time"}, /* Battery safeguard release time , */\ + { 0x50b1, "vbat_prot_hysterese"}, /* Battery Safeguard hysteresis , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass HW clipper , */\ + { 0x5130, "cf_mute"}, /* Coolflux firmware soft mute control , */\ + { 0x5187, "cf_volume"}, /* CF firmware volume control , */\ + { 0x5202, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5230, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x5240, "ctrl_slope"}, /* Slope speed setting (binary coded) , */\ + { 0x5287, "gain"}, /* Amplifier gain , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5340, "clipfast"}, /* Clock selection for HW clipper for battery safeguard, */\ + { 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x5360, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5370, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5380, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5390, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x53a3, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5400, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5413, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5452, "dpsa_drive"}, /* Drive setting (binary coded) , */\ + { 0x550a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually, */\ + { 0x55b0, "enbl_engage"}, /* Enables/engage power stage and control loop , */\ + { 0x55c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ + { 0x5600, "pwm_shape"}, /* PWM shape , */\ + { 0x5614, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0x5660, "reclock_pwm"}, /* Reclock the PWM signal inside analog , */\ + { 0x5670, "reclock_voltsense"}, /* Reclock the voltage sense PWM signal , */\ + { 0x5680, "enbl_pwm_phase_shift"}, /* Control for PWM phase shift , */\ + { 0x5690, "sel_pwm_delay_src"}, /* Control for selection for PWM delay line source , */\ + { 0x56a1, "enbl_odd_up_even_down"}, /* Control for PWM reference sawtooth generartion , */\ + { 0x5703, "ctrl_att_dcdc"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5743, "ctrl_att_spkr"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x5781, "vamp_sel2"}, /* VAMP_OUT2 input selection , */\ + { 0x5805, "zero_lvl"}, /* Low noise gain switch zero trigger level , */\ + { 0x5861, "ctrl_fb_resistor"}, /* Select amplifier feedback resistor connection , */\ + { 0x5881, "lownoisegain_mode"}, /* Low noise gain mode control , */\ + { 0x5905, "threshold_lvl"}, /* Low noise gain switch trigger level , */\ + { 0x5965, "hold_time"}, /* Low noise mode hold time before entering into low noise mode, */\ + { 0x5a05, "lpm1_cal_offset"}, /* Low power mode1 detector ctrl cal_offset from gain module , */\ + { 0x5a65, "lpm1_zero_lvl"}, /* Low power mode1 zero crossing detection level , */\ + { 0x5ac1, "lpm1_mode"}, /* Low power mode control , */\ + { 0x5b05, "lpm1_threshold_lvl"}, /* Low power mode1 amplitude trigger level , */\ + { 0x5b65, "lpm1_hold_time"}, /* Low power mode hold time before entering into low power mode, */\ + { 0x5bc0, "disable_low_power_mode"}, /* Low power mode1 detector control , */\ + { 0x5c00, "enbl_minion"}, /* Enables minion (small) power stage , */\ + { 0x5c13, "vth_vddpvbat"}, /* Select vddp-vbat threshold signal , */\ + { 0x5c50, "lpen_vddpvbat"}, /* Select vddp-vbat filtred vs unfiltered compare , */\ + { 0x5c61, "ctrl_rfb"}, /* Feedback resistor selection - I2C direct mode , */\ + { 0x5d02, "tdm_source_mapping"}, /* TDM source mapping , */\ + { 0x5d31, "tdm_sourcea_frame_sel"}, /* Sensed value A , */\ + { 0x5d51, "tdm_sourceb_frame_sel"}, /* Sensed value B , */\ + { 0x5d71, "tdm_source0_clip_sel"}, /* Clip information (analog /digital) for source0 , */\ + { 0x5d91, "tdm_source1_clip_sel"}, /* Clip information (analog /digital) for source1 , */\ + { 0x5e02, "rst_min_vbat_delay"}, /* Delay for reseting the min_vbat value inside HW Clipper (number of Fs pulses), */\ + { 0x5e30, "rst_min_vbat_sel"}, /* Control for selecting reset signal for min_bat , */\ + { 0x5f00, "hard_mute"}, /* Hard mute - PWM , */\ + { 0x5f12, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ + { 0x5f42, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ + { 0x5f78, "spare_out"}, /* Spare out register , */\ + { 0x600f, "spare_in"}, /* Spare IN , */\ + { 0x6102, "cursense_comp_delay"}, /* Delay to allign compensation signal with current sense signal, */\ + { 0x6130, "cursense_comp_sign"}, /* Polarity of compensation for current sense , */\ + { 0x6140, "enbl_cursense_comp"}, /* Enable current sense compensation , */\ + { 0x6152, "pwms_clip_lvl"}, /* Set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7005, "frst_boost_voltage"}, /* First Boost Voltage Level , */\ + { 0x7065, "scnd_boost_voltage"}, /* Second Boost Voltage Level , */\ + { 0x70c3, "boost_cur"}, /* Max Coil Current , */\ + { 0x7101, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7120, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7130, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x7140, "dcdcoff_mode"}, /* DCDC on/off , */\ + { 0x7150, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7160, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7170, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x7180, "ignore_flag_voutcomp86"}, /* Determines the maximum PWM frequency be the most efficient in relation to the Booster inductor value, */\ + { 0x7204, "boost_trip_lvl_1st"}, /* 1st adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7254, "boost_trip_lvl_2nd"}, /* 2nd adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x72a4, "boost_trip_lvl_track"}, /* Track adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x72f0, "enbl_trip_hyst"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7304, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x7350, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ + { 0x7361, "dcdc_ctrl_maxzercnt"}, /* Number of zero current flags to count before going to pfm mode, */\ + { 0x7386, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ + { 0x73f0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x7404, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7451, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7474, "bst_slopecur"}, /* For testing direct control slope current , */\ + { 0x74c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x74e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x74f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7500, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ + { 0x7510, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ + { 0x7520, "enbl_bst_peakcur"}, /* Enable peak current , */\ + { 0x7530, "enbl_bst_power"}, /* Enable line of the powerstage , */\ + { 0x7540, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x7550, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ + { 0x7560, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x7570, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x7580, "enbl_bst_windac"}, /* Enable window dac , */\ + { 0x7595, "bst_windac"}, /* For testing direct control windac , */\ + { 0x7600, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7611, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7631, "bst_freq"}, /* DCDC boost frequency control , */\ + { 0x7650, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7660, "bst_use_new_zercur_detect"}, /* Enable new zero current detection for boost control, */\ + { 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ + { 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ + { 0x8040, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8050, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8060, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8105, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP) * signal, */\ + { 0x8164, "cs_ktemp2"}, /* Second order temperature compensation coefficient , */\ + { 0x81b0, "enbl_cs_adc"}, /* Enable current sense ADC , */\ + { 0x81c0, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 , */\ + { 0x81d0, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 , */\ + { 0x81e0, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ + { 0x81f0, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 , */\ + { 0x8200, "enbl_cs_ldo"}, /* Enable current sense LDO , */\ + { 0x8210, "enbl_cs_vbatldo"}, /* Enable of current sense LDO , */\ + { 0x8220, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8231, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ + { 0x8250, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x8263, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ + { 0x82a0, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x82b4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ + { 0x8300, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ + { 0x8310, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8320, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8330, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8340, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8350, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if enbl_cs_ldo is high, */\ + { 0x8364, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8800, "ctrl_vs_igen_supply"}, /* Control for selecting supply for VS current generator, */\ + { 0x8810, "ctrl_vs_force_div2"}, /* Select input resistive divider gain , */\ + { 0x8820, "enbl_dc_filter"}, /* Control for enabling the DC blocking filter for voltage and current sense, */\ + { 0x8901, "volsense_pwm_sel"}, /* Voltage sense source selection control , */\ + { 0x8920, "vs_gain_control"}, /* Voltage sense gain control , */\ + { 0x8930, "vs_bypass_gc"}, /* Bypasses the VS gain correction , */\ + { 0x8940, "vs_adc_bsoinv"}, /* Bitstream inversion for voltage sense ADC , */\ + { 0x8950, "vs_adc_nortz"}, /* Return to zero for voltage sense ADC , */\ + { 0x8960, "vs_adc_slowdel"}, /* Select delay for voltage sense ADC (internal decision circuitry), */\ + { 0x8970, "vs_classd_tran_skip"}, /* Skip voltage sense connection during a classD amplifier transition, */\ + { 0x8987, "vs_gain"}, /* Voltage sense gain , */\ + { 0x8a00, "vs_inn_short"}, /* Short voltage sense negative to common mode , */\ + { 0x8a10, "vs_inp_short"}, /* Short voltage sense positive to common mode , */\ + { 0x8a20, "vs_ldo_bypass"}, /* Bypass voltage sense LDO , */\ + { 0x8a30, "vs_ldo_pulldown"}, /* Pull down voltage sense LDO, only valid if enbl_cs_ldo is high, */\ + { 0x8a44, "vs_ldo_voset"}, /* Voltage sense LDO voltage level setting (two's complement), */\ + { 0x8a90, "enbl_vs_adc"}, /* Enable voltage sense ADC , */\ + { 0x8aa0, "enbl_vs_inn1"}, /* Enable connection of voltage sense negative1 , */\ + { 0x8ab0, "enbl_vs_inn2"}, /* Enable connection of voltage sense negative2 , */\ + { 0x8ac0, "enbl_vs_inp1"}, /* Enable connection of voltage sense positive1 , */\ + { 0x8ad0, "enbl_vs_inp2"}, /* Enable connection of voltage sense positive2 , */\ + { 0x8ae0, "enbl_vs_ldo"}, /* Enable voltage sense LDO , */\ + { 0x8af0, "enbl_vs_vbatldo"}, /* Enable of voltage sense LDO , */\ + { 0x9000, "cf_rst_dsp"}, /* Reset for Coolflux DSP , */\ + { 0x9011, "cf_dmem"}, /* Target memory for CFMA using I2C interface , */\ + { 0x9030, "cf_aif"}, /* Auto increment , */\ + { 0x9040, "cf_int"}, /* Coolflux Interrupt - auto clear , */\ + { 0x9050, "cf_cgate_off"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "cf_req_cmd"}, /* Firmware event request rpc command , */\ + { 0x9090, "cf_req_reset"}, /* Firmware event request reset restart , */\ + { 0x90a0, "cf_req_mips"}, /* Firmware event request short on mips , */\ + { 0x90b0, "cf_req_mute_ready"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "cf_req_volume_ready"}, /* Firmware event request volume ready , */\ + { 0x90d0, "cf_req_damage"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "cf_req_calibrate_ready"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "cf_req_reserved"}, /* Firmware event request reserved , */\ + { 0x910f, "cf_madd"}, /* CF memory address , */\ + { 0x920f, "cf_mema"}, /* Activate memory access , */\ + { 0x9307, "cf_err"}, /* CF error flags , */\ + { 0x9380, "cf_ack_cmd"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "cf_ack_reset"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "cf_ack_mips"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "cf_ack_mute_ready"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "cf_ack_volume_ready"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "cf_ack_damage"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "cf_ack_calibrate_ready"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "cf_ack_reserved"}, /* Firmware event acknowledge reserved , */\ + { 0xa007, "mtpkey1"}, /* KEY1 To access KEY1 protected registers 0x5A/90d (default for engineering), */\ + { 0xa107, "mtpkey2"}, /* KEY2 to access KEY2 protected registers, customer key, */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from MTP to I2C mtp register - auto clear, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp - auto clear, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers - auto clear, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp - auto clear, */\ + { 0xa400, "faim_set_clkws"}, /* Sets the FaIM controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the FaIM are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the FaIM are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb000, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb010, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb020, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb030, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb040, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb050, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb060, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb070, "disable_main_ctrl_change_prot"}, /* Disable main control change protection , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ + { 0xc0c0, "use_direct_vs_ctrls"}, /* Voltage sense direct control to overrule several functions for testing, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ + { 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ + { 0xc3d0, "test_abistfft_enbl"}, /* Enable ABIST with FFT on Coolflux DSP , */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc530, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc540, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc550, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc560, "test_enbl_vs"}, /* Enable for digimux mode of voltage sense , */\ + { 0xc570, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc583, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc5c0, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc607, "digimuxa_sel"}, /* DigimuxA input selection control routed to DATAO , */\ + { 0xc687, "digimuxb_sel"}, /* DigimuxB input selection control routed to INT , */\ + { 0xc707, "digimuxc_sel"}, /* DigimuxC input selection control routed to ADS1 , */\ + { 0xc800, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xc810, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xc820, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xc830, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xc844, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xc894, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ + { 0xc903, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ + { 0xc943, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ + { 0xca05, "pll_seli"}, /* PLL SELI - I2C direct PLL control mode only , */\ + { 0xca64, "pll_selp"}, /* PLL SELP - I2C direct PLL control mode only , */\ + { 0xcab3, "pll_selr"}, /* PLL SELR - I2C direct PLL control mode only , */\ + { 0xcaf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ + { 0xcb09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0xcba0, "pll_mdec_msb"}, /* MSB of PLL_mdec - I2C direct PLL control mode only, */\ + { 0xcbb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ + { 0xcbc0, "enbl_osc"}, /* Enables OSC1M in I2C direct control mode only , */\ + { 0xcbd0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ + { 0xcbe0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ + { 0xcbf0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ + { 0xcc0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ + { 0xcd06, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0xce0f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xcf02, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xcf33, "tsig_gain"}, /* Test signal gain , */\ + { 0xd000, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd011, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd032, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd064, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd0b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd0c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd109, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd201, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ + { 0xd221, "clkdiv_muxa_sel"}, /* DCDC MUXA clock divider selection in direct clock control mode, */\ + { 0xd241, "clkdiv_muxb_sel"}, /* DCDC MUXB clock divider selection in direct clock control mode, */\ + { 0xd301, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO datasheet), */\ + { 0xd321, "datao_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO datasheet), */\ + { 0xd340, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xd407, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd480, "enbl_clk_out_of_range"}, /* Clock out of range , */\ + { 0xd491, "sel_wdt_clk"}, /* Watch dog clock divider settings , */\ + { 0xd4b0, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd500, "source_in_testmode"}, /* TDM source in test mode (return only current and voltage sense), */\ + { 0xd510, "gainatt_feedback"}, /* Gainatt feedback to tdm , */\ + { 0xd522, "test_parametric_io"}, /* Test IO parametric , */\ + { 0xd550, "ctrl_bst_clk_lp1"}, /* Boost clock control in low power mode1 , */\ + { 0xd561, "test_spare_out1"}, /* Test spare out 1 , */\ + { 0xd580, "bst_dcmbst"}, /* DCM boost , */\ + { 0xd593, "test_spare_out2"}, /* Test spare out 2 , */\ + { 0xe00f, "sw_profile"}, /* Software profile data , */\ + { 0xe10f, "sw_vstep"}, /* Software vstep information , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf163, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ + { 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ + { 0xf307, "calibr_gain_vs"}, /* Voltage sense gain , */\ + { 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ + { 0xf40f, "mtpdata4"}, /* MTP4 data , */\ + { 0xf50f, "calibr_R25C"}, /* Ron resistance of speaker coil , */\ + { 0xf60f, "mtpdata6"}, /* MTP6 data , */\ + { 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ + { 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable functionality of dcdcoff_mode bit , */\ + { 0xf910, "mtp_lock_enbl_coolflux"}, /* Disable functionality of enbl_coolflux bit , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_enbl_pwm_delay_clock_gating"}, /* PWM delay clock auto gating , */\ + { 0xf940, "mtp_enbl_ocp_clock_gating"}, /* OCP clock auto gating , */\ + { 0xf950, "mtp_gate_cgu_clock_for_test"}, /* CGU test clock control , */\ + { 0xf987, "type_bits_fw"}, /* MTP control for firmware features - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE , */\ + { 0xff07, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa9894_irq { + tfa9894_irq_max = -1, + tfa9894_irq_all = -1 /* all irqs */}; + +#define TFA9894_IRQ_NAMETABLE static tfaIrqName_t Tfa9894IrqNames[] = {\ +}; +#endif /* _TFA9894_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa9894_tfafieldnames_N2.h b/sound/soc/codecs/tfa9894_tfafieldnames_N2.h new file mode 100644 index 000000000000..22ac3ae26c4f --- /dev/null +++ b/sound/soc/codecs/tfa9894_tfafieldnames_N2.h @@ -0,0 +1,1123 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9894_TFAFIELDNAMES_N2_H +#define _TFA9894_TFAFIELDNAMES_N2_H + + +#define TFA9894N2_I2CVERSION 25.0 + +typedef enum nxpTfa9894N2BfEnumList { + TFA9894N2_BF_PWDN = 0x0000, /*!< Powerdown control */ + TFA9894N2_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA9894N2_BF_CFE = 0x0020, /*!< Enable CoolFlux DSP */ + TFA9894N2_BF_AMPE = 0x0030, /*!< Enable Amplifier */ + TFA9894N2_BF_DCA = 0x0040, /*!< Enable DCDC Boost converter */ + TFA9894N2_BF_SBSL = 0x0050, /*!< Coolflux configured */ + TFA9894N2_BF_AMPC = 0x0060, /*!< CoolFlux control over amplifier */ + TFA9894N2_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA9894N2_BF_FSSSEL = 0x0090, /*!< Audio sample reference */ + TFA9894N2_BF_BYPOCP = 0x00a0, /*!< Bypass OCP */ + TFA9894N2_BF_TSTOCP = 0x00b0, /*!< OCP testing control */ + TFA9894N2_BF_BSSS = 0x00c0, /*!< Vbat protection steepness */ + TFA9894N2_BF_HPFBYP = 0x00d0, /*!< Bypass High Pass Filter */ + TFA9894N2_BF_DPSA = 0x00e0, /*!< Enable DPSA */ + TFA9894N2_BF_AMPINSEL = 0x0101, /*!< Amplifier input selection */ + TFA9894N2_BF_MANSCONF = 0x0120, /*!< Device I2C settings configured */ + TFA9894N2_BF_MANCOLD = 0x0130, /*!< Execute cold start */ + TFA9894N2_BF_MANROBOD = 0x0140, /*!< Reaction on BOD */ + TFA9894N2_BF_BODE = 0x0150, /*!< Enable BOD (only in direct control mode) */ + TFA9894N2_BF_BODHYS = 0x0160, /*!< Enable Hysteresis of BOD */ + TFA9894N2_BF_BODFILT = 0x0171, /*!< BOD filter */ + TFA9894N2_BF_BODTHLVL = 0x0191, /*!< BOD threshold */ + TFA9894N2_BF_MUTETO = 0x01b0, /*!< Time out SB mute sequence */ + TFA9894N2_BF_MANWDE = 0x01c0, /*!< Watchdog enable */ + TFA9894N2_BF_OPENMTP = 0x01e0, /*!< Control for FAIM protection */ + TFA9894N2_BF_FAIMVBGOVRRL = 0x01f0, /*!< Overrule the enabling of VBG for faim erase/write access */ + TFA9894N2_BF_AUDFS = 0x0203, /*!< Audio sample rate Fs */ + TFA9894N2_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ + TFA9894N2_BF_FRACTDEL = 0x0255, /*!< Current sense fractional delay */ + TFA9894N2_BF_TDMPRES = 0x02b1, /*!< Control for HW manager */ + TFA9894N2_BF_AMPOCRT = 0x02d2, /*!< Amplifier on-off criteria for shutdown */ + TFA9894N2_BF_REV = 0x030f, /*!< Revision info */ + TFA9894N2_BF_REFCKEXT = 0x0401, /*!< PLL external reference clock */ + TFA9894N2_BF_REFCKSEL = 0x0420, /*!< PLL internal reference clock */ + TFA9894N2_BF_MCLKSEL = 0x0432, /*!< Master Clock Selection */ + TFA9894N2_BF_MANAOOSC = 0x0460, /*!< Internal OSC1M off at PWDN */ + TFA9894N2_BF_ACKCLDDIS = 0x0470, /*!< Automatic PLL reference clock selection for cold start */ + TFA9894N2_BF_FSSYNCEN = 0x0480, /*!< Enable FS synchronisation for clock divider */ + TFA9894N2_BF_CLKREFSYNCEN = 0x0490, /*!< Enable PLL reference clock synchronisation for clock divider */ + TFA9894N2_BF_PLLSTUP = 0x04a0, /*!< PLL startup time configuration */ + TFA9894N2_BF_CGUSYNCDCG = 0x0500, /*!< Clock gating control for CGU synchronisation module */ + TFA9894N2_BF_SPKSSEN = 0x0510, /*!< Enable speaker sub-system */ + TFA9894N2_BF_MTPSSEN = 0x0520, /*!< Enable FAIM sub-system */ + TFA9894N2_BF_WDTCLKEN = 0x0530, /*!< Enable Coolflux watchdog clock */ + TFA9894N2_BF_VDDS = 0x1000, /*!< POR */ + TFA9894N2_BF_PLLS = 0x1010, /*!< PLL Lock */ + TFA9894N2_BF_OTDS = 0x1020, /*!< OTP alarm */ + TFA9894N2_BF_OVDS = 0x1030, /*!< OVP alarm */ + TFA9894N2_BF_UVDS = 0x1040, /*!< UVP alarm */ + TFA9894N2_BF_OCDS = 0x1050, /*!< OCP amplifier (sticky register, clear on read) */ + TFA9894N2_BF_CLKS = 0x1060, /*!< Clocks stable */ + TFA9894N2_BF_MTPB = 0x1070, /*!< MTP busy */ + TFA9894N2_BF_NOCLK = 0x1080, /*!< Lost clock */ + TFA9894N2_BF_ACS = 0x1090, /*!< Cold Start */ + TFA9894N2_BF_WDS = 0x10a0, /*!< Watchdog */ + TFA9894N2_BF_SWS = 0x10b0, /*!< Amplifier engage */ + TFA9894N2_BF_AMPS = 0x10c0, /*!< Amplifier enable */ + TFA9894N2_BF_AREFS = 0x10d0, /*!< References enable */ + TFA9894N2_BF_ADCCR = 0x10e0, /*!< Control ADC */ + TFA9894N2_BF_BODNOK = 0x10f0, /*!< BOD Flag - VDD NOT OK */ + TFA9894N2_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA9894N2_BF_DCDCA = 0x1110, /*!< DCDC active (sticky register, clear on read) */ + TFA9894N2_BF_DCOCPOK = 0x1120, /*!< DCDC OCP nmos (sticky register, clear on read) */ + TFA9894N2_BF_DCHVBAT = 0x1140, /*!< DCDC level 1x */ + TFA9894N2_BF_DCH114 = 0x1150, /*!< DCDC level 1.14x */ + TFA9894N2_BF_DCH107 = 0x1160, /*!< DCDC level 1.07x */ + TFA9894N2_BF_SPKS = 0x1170, /*!< Speaker status */ + TFA9894N2_BF_CLKOOR = 0x1180, /*!< External clock status */ + TFA9894N2_BF_MANALARM = 0x1190, /*!< Alarm state */ + TFA9894N2_BF_TDMERR = 0x11a0, /*!< TDM error */ + TFA9894N2_BF_TDMLUTER = 0x11b0, /*!< TDM lookup table error */ + TFA9894N2_BF_NOAUDCLK = 0x11c0, /*!< Lost Audio clock */ + TFA9894N2_BF_OCPOAP = 0x1200, /*!< OCPOK pmos A */ + TFA9894N2_BF_OCPOAN = 0x1210, /*!< OCPOK nmos A */ + TFA9894N2_BF_OCPOBP = 0x1220, /*!< OCPOK pmos B */ + TFA9894N2_BF_OCPOBN = 0x1230, /*!< OCPOK nmos B */ + TFA9894N2_BF_CLIPS = 0x1240, /*!< Amplifier clipping */ + TFA9894N2_BF_MANMUTE = 0x1250, /*!< Audio mute sequence */ + TFA9894N2_BF_MANOPER = 0x1260, /*!< Device in Operating state */ + TFA9894N2_BF_LP1 = 0x1270, /*!< Low power MODE1 detection */ + TFA9894N2_BF_LA = 0x1280, /*!< Low amplitude detection */ + TFA9894N2_BF_VDDPH = 0x1290, /*!< VDDP greater than VBAT flag */ + TFA9894N2_BF_TDMSTAT = 0x1302, /*!< TDM Status bits */ + TFA9894N2_BF_MANSTATE = 0x1333, /*!< Device Manager status */ + TFA9894N2_BF_DCMODE = 0x13b1, /*!< DCDC mode status bits */ + TFA9894N2_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA9894N2_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA9894N2_BF_VDDPS = 0x1709, /*!< IC VDDP voltage (1023*VDDP/13V) */ + TFA9894N2_BF_TDME = 0x2000, /*!< Enable interface */ + TFA9894N2_BF_TDMSPKE = 0x2010, /*!< Control audio tdm channel in sink0 */ + TFA9894N2_BF_TDMDCE = 0x2020, /*!< Control audio tdm channel in sink1 */ + TFA9894N2_BF_TDMCSE = 0x2030, /*!< Source 0 enable */ + TFA9894N2_BF_TDMVSE = 0x2040, /*!< Source 1 enable */ + TFA9894N2_BF_TDMCFE = 0x2050, /*!< Source 2 enable */ + TFA9894N2_BF_TDMCF2E = 0x2060, /*!< Source 3 enable */ + TFA9894N2_BF_TDMCLINV = 0x2070, /*!< Reception data to BCK clock */ + TFA9894N2_BF_TDMFSPOL = 0x2080, /*!< FS polarity */ + TFA9894N2_BF_TDMDEL = 0x2090, /*!< Data delay to FS */ + TFA9894N2_BF_TDMADJ = 0x20a0, /*!< Data adjustment */ + TFA9894N2_BF_TDMOOMP = 0x20b1, /*!< Received audio compression */ + TFA9894N2_BF_TDMNBCK = 0x2103, /*!< TDM NBCK - Bit clock to FS ratio */ + TFA9894N2_BF_TDMFSLN = 0x2143, /*!< FS length (master mode only) */ + TFA9894N2_BF_TDMSLOTS = 0x2183, /*!< N-slots in Frame */ + TFA9894N2_BF_TDMTXDFO = 0x21c1, /*!< Format unused bits */ + TFA9894N2_BF_TDMTXUS0 = 0x21e1, /*!< Format unused slots DATAO */ + TFA9894N2_BF_TDMSLLN = 0x2204, /*!< N-bits in slot */ + TFA9894N2_BF_TDMBRMG = 0x2254, /*!< N-bits remaining */ + TFA9894N2_BF_TDMSSIZE = 0x22a4, /*!< Sample size per slot */ + TFA9894N2_BF_TDMSPKS = 0x2303, /*!< TDM slot for sink 0 */ + TFA9894N2_BF_TDMDCS = 0x2343, /*!< TDM slot for sink 1 */ + TFA9894N2_BF_TDMCFSEL = 0x2381, /*!< TDM Source 2 data selection */ + TFA9894N2_BF_TDMCF2SEL = 0x23a1, /*!< TDM Source 3 data selection */ + TFA9894N2_BF_TDMCSS = 0x2403, /*!< Slot position of source 0 data */ + TFA9894N2_BF_TDMVSS = 0x2443, /*!< Slot position of source 1 data */ + TFA9894N2_BF_TDMCFS = 0x2483, /*!< Slot position of source 2 data */ + TFA9894N2_BF_TDMCF2S = 0x24c3, /*!< Slot position of source 3 data */ + TFA9894N2_BF_ISTVDDS = 0x4000, /*!< Status POR */ + TFA9894N2_BF_ISTBSTOC = 0x4010, /*!< Status DCDC OCP */ + TFA9894N2_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ + TFA9894N2_BF_ISTOCPR = 0x4030, /*!< Status OCP alarm */ + TFA9894N2_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ + TFA9894N2_BF_ISTMANALARM = 0x4050, /*!< Status manager alarm state */ + TFA9894N2_BF_ISTTDMER = 0x4060, /*!< Status TDM error */ + TFA9894N2_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ + TFA9894N2_BF_ISTCFMER = 0x4080, /*!< Status cfma error */ + TFA9894N2_BF_ISTCFMAC = 0x4090, /*!< Status cfma ack */ + TFA9894N2_BF_ISTSPKS = 0x40a0, /*!< Status coolflux speaker error */ + TFA9894N2_BF_ISTACS = 0x40b0, /*!< Status cold started */ + TFA9894N2_BF_ISTWDS = 0x40c0, /*!< Status watchdog reset */ + TFA9894N2_BF_ISTBODNOK = 0x40d0, /*!< Status brown out detect */ + TFA9894N2_BF_ISTLP1 = 0x40e0, /*!< Status low power mode1 detect */ + TFA9894N2_BF_ISTCLKOOR = 0x40f0, /*!< Status clock out of range */ + TFA9894N2_BF_ICLVDDS = 0x4400, /*!< Clear POR */ + TFA9894N2_BF_ICLBSTOC = 0x4410, /*!< Clear DCDC OCP */ + TFA9894N2_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ + TFA9894N2_BF_ICLOCPR = 0x4430, /*!< Clear OCP alarm */ + TFA9894N2_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ + TFA9894N2_BF_ICLMANALARM = 0x4450, /*!< Clear manager alarm state */ + TFA9894N2_BF_ICLTDMER = 0x4460, /*!< Clear TDM error */ + TFA9894N2_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ + TFA9894N2_BF_ICLCFMER = 0x4480, /*!< Clear cfma err */ + TFA9894N2_BF_ICLCFMAC = 0x4490, /*!< Clear cfma ack */ + TFA9894N2_BF_ICLSPKS = 0x44a0, /*!< Clear coolflux speaker error */ + TFA9894N2_BF_ICLACS = 0x44b0, /*!< Clear cold started */ + TFA9894N2_BF_ICLWDS = 0x44c0, /*!< Clear watchdog reset */ + TFA9894N2_BF_ICLBODNOK = 0x44d0, /*!< Clear brown out detect */ + TFA9894N2_BF_ICLLP1 = 0x44e0, /*!< Clear low power mode1 detect */ + TFA9894N2_BF_ICLCLKOOR = 0x44f0, /*!< Clear clock out of range */ + TFA9894N2_BF_IEVDDS = 0x4800, /*!< Enable POR */ + TFA9894N2_BF_IEBSTOC = 0x4810, /*!< Enable DCDC OCP */ + TFA9894N2_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ + TFA9894N2_BF_IEOCPR = 0x4830, /*!< Enable OCP alarm */ + TFA9894N2_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ + TFA9894N2_BF_IEMANALARM = 0x4850, /*!< Enable Manager Alarm state */ + TFA9894N2_BF_IETDMER = 0x4860, /*!< Enable TDM error */ + TFA9894N2_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ + TFA9894N2_BF_IECFMER = 0x4880, /*!< Enable cfma err */ + TFA9894N2_BF_IECFMAC = 0x4890, /*!< Enable cfma ack */ + TFA9894N2_BF_IESPKS = 0x48a0, /*!< Enable coolflux speaker error */ + TFA9894N2_BF_IEACS = 0x48b0, /*!< Enable cold started */ + TFA9894N2_BF_IEWDS = 0x48c0, /*!< Enable watchdog reset */ + TFA9894N2_BF_IEBODNOK = 0x48d0, /*!< Enable brown out detect */ + TFA9894N2_BF_IELP1 = 0x48e0, /*!< Enable low power mode1 detect */ + TFA9894N2_BF_IECLKOOR = 0x48f0, /*!< Enable clock out of range */ + TFA9894N2_BF_IPOVDDS = 0x4c00, /*!< Polarity POR */ + TFA9894N2_BF_IPOBSTOC = 0x4c10, /*!< Polarity DCDC OCP */ + TFA9894N2_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ + TFA9894N2_BF_IPOOCPR = 0x4c30, /*!< Polarity ocp alarm */ + TFA9894N2_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ + TFA9894N2_BF_IPOMANALARM = 0x4c50, /*!< Polarity manager alarm state */ + TFA9894N2_BF_IPOTDMER = 0x4c60, /*!< Polarity TDM error */ + TFA9894N2_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ + TFA9894N2_BF_IPOCFMER = 0x4c80, /*!< Polarity cfma err */ + TFA9894N2_BF_IPOCFMAC = 0x4c90, /*!< Polarity cfma ack */ + TFA9894N2_BF_IPOSPKS = 0x4ca0, /*!< Polarity coolflux speaker error */ + TFA9894N2_BF_IPOACS = 0x4cb0, /*!< Polarity cold started */ + TFA9894N2_BF_IPOWDS = 0x4cc0, /*!< Polarity watchdog reset */ + TFA9894N2_BF_IPOBODNOK = 0x4cd0, /*!< Polarity brown out detect */ + TFA9894N2_BF_IPOLP1 = 0x4ce0, /*!< Polarity low power mode1 detect */ + TFA9894N2_BF_IPOCLKOOR = 0x4cf0, /*!< Polarity clock out of range */ + TFA9894N2_BF_BSSCR = 0x5001, /*!< Battery safeguard attack time */ + TFA9894N2_BF_BSST = 0x5023, /*!< Battery safeguard threshold voltage level */ + TFA9894N2_BF_BSSRL = 0x5061, /*!< Battery safeguard maximum reduction */ + TFA9894N2_BF_BSSRR = 0x5082, /*!< Battery safeguard release time */ + TFA9894N2_BF_BSSHY = 0x50b1, /*!< Battery Safeguard hysteresis */ + TFA9894N2_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA9894N2_BF_BSSBY = 0x50f0, /*!< Bypass HW clipper */ + TFA9894N2_BF_CFSM = 0x5130, /*!< Coolflux firmware soft mute control */ + TFA9894N2_BF_VOL = 0x5187, /*!< CF firmware volume control */ + TFA9894N2_BF_CLIPCTRL = 0x5202, /*!< Clip control setting */ + TFA9894N2_BF_SLOPEE = 0x5230, /*!< Enables slope control */ + TFA9894N2_BF_SLOPESET = 0x5240, /*!< Slope speed setting (binary coded) */ + TFA9894N2_BF_BYPDLYLINE = 0x5250, /*!< Bypass the interpolator delay line */ + TFA9894N2_BF_AMPGAIN = 0x5287, /*!< Amplifier gain */ + TFA9894N2_BF_TDMDCG = 0x5703, /*!< Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE) */ + TFA9894N2_BF_TDMSPKG = 0x5743, /*!< Total gain depending on INPLEV setting (channel 0) */ + TFA9894N2_BF_DCINSEL = 0x5781, /*!< VAMP_OUT2 input selection */ + TFA9894N2_BF_LNMODE = 0x5881, /*!< Low noise gain mode control */ + TFA9894N2_BF_LPM1MODE = 0x5ac1, /*!< Low power mode control */ + TFA9894N2_BF_TDMSRCMAP = 0x5d02, /*!< TDM source mapping */ + TFA9894N2_BF_TDMSRCAS = 0x5d31, /*!< Sensed value A */ + TFA9894N2_BF_TDMSRCBS = 0x5d51, /*!< Sensed value B */ + TFA9894N2_BF_TDMSRCACLIP = 0x5d71, /*!< Clip information (analog /digital) for source0 */ + TFA9894N2_BF_TDMSRCBCLIP = 0x5d91, /*!< Clip information (analog /digital) for source1 */ + TFA9894N2_BF_DELCURCOMP = 0x6102, /*!< Delay to allign compensation signal with current sense signal */ + TFA9894N2_BF_SIGCURCOMP = 0x6130, /*!< Polarity of compensation for current sense */ + TFA9894N2_BF_ENCURCOMP = 0x6140, /*!< Enable current sense compensation */ + TFA9894N2_BF_LVLCLPPWM = 0x6152, /*!< Set the amount of pwm pulse that may be skipped before clip-flag is triggered */ + TFA9894N2_BF_DCVOF = 0x7005, /*!< First Boost Voltage Level */ + TFA9894N2_BF_DCVOS = 0x7065, /*!< Second Boost Voltage Level */ + TFA9894N2_BF_DCMCC = 0x70c3, /*!< Max Coil Current */ + TFA9894N2_BF_DCCV = 0x7101, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ + TFA9894N2_BF_DCIE = 0x7120, /*!< Adaptive boost mode */ + TFA9894N2_BF_DCSR = 0x7130, /*!< Soft ramp up/down */ + TFA9894N2_BF_DCDIS = 0x7140, /*!< DCDC on/off */ + TFA9894N2_BF_DCPWM = 0x7150, /*!< DCDC PWM only mode */ + TFA9894N2_BF_DCTRACK = 0x7160, /*!< Boost algorithm selection, effective only when boost_intelligent is set to 1 */ + TFA9894N2_BF_DCENVSEL = 0x7170, /*!< Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1 */ + TFA9894N2_BF_OVSCTLVL = 0x7195, /*!< Threshold level to activate active overshoot control */ + TFA9894N2_BF_DCTRIP = 0x7204, /*!< 1st adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9894N2_BF_DCTRIP2 = 0x7254, /*!< 2nd adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9894N2_BF_DCTRIPT = 0x72a4, /*!< Track adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ + TFA9894N2_BF_DCTRIPHYSTE = 0x72f0, /*!< Enable hysteresis on booster trip levels */ + TFA9894N2_BF_DCHOLD = 0x7304, /*!< Hold time / Hysteresis for DCDC booster, effective only when boost_intelligent is set to 1 */ + TFA9894N2_BF_RST = 0x9000, /*!< Reset for Coolflux DSP */ + TFA9894N2_BF_DMEM = 0x9011, /*!< Target memory for CFMA using I2C interface */ + TFA9894N2_BF_AIF = 0x9030, /*!< Auto increment */ + TFA9894N2_BF_CFINT = 0x9040, /*!< Coolflux Interrupt - auto clear */ + TFA9894N2_BF_CFCGATE = 0x9050, /*!< Coolflux clock gating disabling control */ + TFA9894N2_BF_REQCMD = 0x9080, /*!< Firmware event request rpc command */ + TFA9894N2_BF_REQRST = 0x9090, /*!< Firmware event request reset restart */ + TFA9894N2_BF_REQMIPS = 0x90a0, /*!< Firmware event request short on mips */ + TFA9894N2_BF_REQMUTED = 0x90b0, /*!< Firmware event request mute sequence ready */ + TFA9894N2_BF_REQVOL = 0x90c0, /*!< Firmware event request volume ready */ + TFA9894N2_BF_REQDMG = 0x90d0, /*!< Firmware event request speaker damage detected */ + TFA9894N2_BF_REQCAL = 0x90e0, /*!< Firmware event request calibration completed */ + TFA9894N2_BF_REQRSV = 0x90f0, /*!< Firmware event request reserved */ + TFA9894N2_BF_MADD = 0x910f, /*!< CF memory address */ + TFA9894N2_BF_MEMA = 0x920f, /*!< Activate memory access */ + TFA9894N2_BF_ERR = 0x9307, /*!< CF error flags */ + TFA9894N2_BF_ACKCMD = 0x9380, /*!< Firmware event acknowledge rpc command */ + TFA9894N2_BF_ACKRST = 0x9390, /*!< Firmware event acknowledge reset restart */ + TFA9894N2_BF_ACKMIPS = 0x93a0, /*!< Firmware event acknowledge short on mips */ + TFA9894N2_BF_ACKMUTED = 0x93b0, /*!< Firmware event acknowledge mute sequence ready */ + TFA9894N2_BF_ACKVOL = 0x93c0, /*!< Firmware event acknowledge volume ready */ + TFA9894N2_BF_ACKDMG = 0x93d0, /*!< Firmware event acknowledge speaker damage detected */ + TFA9894N2_BF_ACKCAL = 0x93e0, /*!< Firmware event acknowledge calibration completed */ + TFA9894N2_BF_ACKRSV = 0x93f0, /*!< Firmware event acknowledge reserved */ + TFA9894N2_BF_MTPK = 0xa107, /*!< KEY2 to access KEY2 protected registers, customer key */ + TFA9894N2_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ + TFA9894N2_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ + TFA9894N2_BF_CMTPI = 0xa350, /*!< Start copying all the data from mtp to I2C mtp registers - auto clear */ + TFA9894N2_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp - auto clear */ + TFA9894N2_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ + TFA9894N2_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ + TFA9894N2_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA9894N2_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA9894N2_BF_PLLINSELI = 0xca05, /*!< PLL INSELI - PLL direct bandwidth control mode only with pll_bandsel set to 1 */ + TFA9894N2_BF_PLLINSELP = 0xca64, /*!< PLL INSELP - PLL direct bandwidth control mode only with pll_bandsel set to 1 */ + TFA9894N2_BF_PLLINSELR = 0xcab3, /*!< PLL INSELR - PLL direct bandwidth control mode only with pll_bandsel set to 1 */ + TFA9894N2_BF_PLLNDEC = 0xcb09, /*!< PLL NDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_PLLMDECMSB = 0xcba0, /*!< MSB of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_PLLBYPASS = 0xcbb0, /*!< PLL bypass control during functional mode */ + TFA9894N2_BF_PLLDIRECTI = 0xcbc0, /*!< PLL directi control in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_PLLDIRECTO = 0xcbd0, /*!< PLL directo control in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_PLLFRMSTBL = 0xcbe0, /*!< PLL FRM clock stable control in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_PLLFRM = 0xcbf0, /*!< PLL free running mode control in functional mode */ + TFA9894N2_BF_PLLMDECLSB = 0xcc0f, /*!< Bits 15..0 of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_PLLPDEC = 0xcd06, /*!< PLL PDEC in direct control mode only, use_direct_pll_ctrl set to 1 */ + TFA9894N2_BF_DIRECTPLL = 0xcd70, /*!< Enabled PLL direct control mode, overrules the PLL LUT with I2C register values */ + TFA9894N2_BF_DIRECTCLK = 0xcd80, /*!< Enabled CGU clock divider direct control mode */ + TFA9894N2_BF_PLLLIM = 0xcd90, /*!< PLL up limiter control in PLL direct bandwidth control mode, pll_bandsel set to 1 */ + TFA9894N2_BF_SWPROFIL = 0xe00f, /*!< Software profile data */ + TFA9894N2_BF_SWVSTEP = 0xe10f, /*!< Software vstep information */ + TFA9894N2_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ + TFA9894N2_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA9894N2_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ + TFA9894N2_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA9894N2_BF_USERDEF = 0xf042, /*!< Calibration delta current limit DCDC */ + TFA9894N2_BF_CUSTINFO = 0xf078, /*!< Reserved space for allowing customer to store speaker information */ + TFA9894N2_BF_R25C = 0xf50f, /*!< Ron resistance of speaker coil */ +} nxpTfa9894N2BfEnumList_t; +#define TFA9894N2_NAMETABLE static tfaBfName_t Tfa9894N2DatasheetNames[] = {\ + { 0x0, "PWDN"}, /* Powerdown control , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x20, "CFE"}, /* Enable CoolFlux DSP , */\ + { 0x30, "AMPE"}, /* Enable Amplifier , */\ + { 0x40, "DCA"}, /* Enable DCDC Boost converter , */\ + { 0x50, "SBSL"}, /* Coolflux configured , */\ + { 0x60, "AMPC"}, /* CoolFlux control over amplifier , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0x90, "FSSSEL"}, /* Audio sample reference , */\ + { 0xa0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xb0, "TSTOCP"}, /* OCP testing control , */\ + { 0xc0, "BSSS"}, /* Vbat protection steepness , */\ + { 0xd0, "HPFBYP"}, /* Bypass High Pass Filter , */\ + { 0xe0, "DPSA"}, /* Enable DPSA , */\ + { 0x101, "AMPINSEL"}, /* Amplifier input selection , */\ + { 0x120, "MANSCONF"}, /* Device I2C settings configured , */\ + { 0x130, "MANCOLD"}, /* Execute cold start , */\ + { 0x140, "MANROBOD"}, /* Reaction on BOD , */\ + { 0x150, "BODE"}, /* Enable BOD (only in direct control mode) , */\ + { 0x160, "BODHYS"}, /* Enable Hysteresis of BOD , */\ + { 0x171, "BODFILT"}, /* BOD filter , */\ + { 0x191, "BODTHLVL"}, /* BOD threshold , */\ + { 0x1b0, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x1c0, "MANWDE"}, /* Watchdog enable , */\ + { 0x1e0, "OPENMTP"}, /* Control for FAIM protection , */\ + { 0x1f0, "FAIMVBGOVRRL"}, /* Overrule the enabling of VBG for faim erase/write access, */\ + { 0x203, "AUDFS"}, /* Audio sample rate Fs , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* Current sense fractional delay , */\ + { 0x2b1, "TDMPRES"}, /* Control for HW manager , */\ + { 0x2d2, "AMPOCRT"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external reference clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal reference clock , */\ + { 0x432, "MCLKSEL"}, /* Master Clock Selection , */\ + { 0x460, "MANAOOSC"}, /* Internal OSC1M off at PWDN , */\ + { 0x470, "ACKCLDDIS"}, /* Automatic PLL reference clock selection for cold start, */\ + { 0x480, "FSSYNCEN"}, /* Enable FS synchronisation for clock divider , */\ + { 0x490, "CLKREFSYNCEN"}, /* Enable PLL reference clock synchronisation for clock divider, */\ + { 0x4a0, "PLLSTUP"}, /* PLL startup time configuration , */\ + { 0x500, "CGUSYNCDCG"}, /* Clock gating control for CGU synchronisation module, */\ + { 0x510, "SPKSSEN"}, /* Enable speaker sub-system , */\ + { 0x520, "MTPSSEN"}, /* Enable FAIM sub-system , */\ + { 0x530, "WDTCLKEN"}, /* Enable Coolflux watchdog clock , */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "PLLS"}, /* PLL Lock , */\ + { 0x1020, "OTDS"}, /* OTP alarm , */\ + { 0x1030, "OVDS"}, /* OVP alarm , */\ + { 0x1040, "UVDS"}, /* UVP alarm , */\ + { 0x1050, "OCDS"}, /* OCP amplifier (sticky register, clear on read) , */\ + { 0x1060, "CLKS"}, /* Clocks stable , */\ + { 0x1070, "MTPB"}, /* MTP busy , */\ + { 0x1080, "NOCLK"}, /* Lost clock , */\ + { 0x1090, "ACS"}, /* Cold Start , */\ + { 0x10a0, "WDS"}, /* Watchdog , */\ + { 0x10b0, "SWS"}, /* Amplifier engage , */\ + { 0x10c0, "AMPS"}, /* Amplifier enable , */\ + { 0x10d0, "AREFS"}, /* References enable , */\ + { 0x10e0, "ADCCR"}, /* Control ADC , */\ + { 0x10f0, "BODNOK"}, /* BOD Flag - VDD NOT OK , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active (sticky register, clear on read) , */\ + { 0x1120, "DCOCPOK"}, /* DCDC OCP nmos (sticky register, clear on read) , */\ + { 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1170, "SPKS"}, /* Speaker status , */\ + { 0x1180, "CLKOOR"}, /* External clock status , */\ + { 0x1190, "MANALARM"}, /* Alarm state , */\ + { 0x11a0, "TDMERR"}, /* TDM error , */\ + { 0x11b0, "TDMLUTER"}, /* TDM lookup table error , */\ + { 0x11c0, "NOAUDCLK"}, /* Lost Audio clock , */\ + { 0x1200, "OCPOAP"}, /* OCPOK pmos A , */\ + { 0x1210, "OCPOAN"}, /* OCPOK nmos A , */\ + { 0x1220, "OCPOBP"}, /* OCPOK pmos B , */\ + { 0x1230, "OCPOBN"}, /* OCPOK nmos B , */\ + { 0x1240, "CLIPS"}, /* Amplifier clipping , */\ + { 0x1250, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x1260, "MANOPER"}, /* Device in Operating state , */\ + { 0x1270, "LP1"}, /* Low power MODE1 detection , */\ + { 0x1280, "LA"}, /* Low amplitude detection , */\ + { 0x1290, "VDDPH"}, /* VDDP greater than VBAT flag , */\ + { 0x1302, "TDMSTAT"}, /* TDM Status bits , */\ + { 0x1333, "MANSTATE"}, /* Device Manager status , */\ + { 0x13b1, "DCMODE"}, /* DCDC mode status bits , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x1709, "VDDPS"}, /* IC VDDP voltage (1023*VDDP/13V) , */\ + { 0x2000, "TDME"}, /* Enable interface , */\ + { 0x2010, "TDMSPKE"}, /* Control audio tdm channel in sink0 , */\ + { 0x2020, "TDMDCE"}, /* Control audio tdm channel in sink1 , */\ + { 0x2030, "TDMCSE"}, /* Source 0 enable , */\ + { 0x2040, "TDMVSE"}, /* Source 1 enable , */\ + { 0x2050, "TDMCFE"}, /* Source 2 enable , */\ + { 0x2060, "TDMCF2E"}, /* Source 3 enable , */\ + { 0x2070, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2080, "TDMFSPOL"}, /* FS polarity , */\ + { 0x2090, "TDMDEL"}, /* Data delay to FS , */\ + { 0x20a0, "TDMADJ"}, /* Data adjustment , */\ + { 0x20b1, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2103, "TDMNBCK"}, /* TDM NBCK - Bit clock to FS ratio , */\ + { 0x2143, "TDMFSLN"}, /* FS length (master mode only) , */\ + { 0x2183, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x21c1, "TDMTXDFO"}, /* Format unused bits , */\ + { 0x21e1, "TDMTXUS0"}, /* Format unused slots DATAO , */\ + { 0x2204, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2254, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x22a4, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2303, "TDMSPKS"}, /* TDM slot for sink 0 , */\ + { 0x2343, "TDMDCS"}, /* TDM slot for sink 1 , */\ + { 0x2381, "TDMCFSEL"}, /* TDM Source 2 data selection , */\ + { 0x23a1, "TDMCF2SEL"}, /* TDM Source 3 data selection , */\ + { 0x2403, "TDMCSS"}, /* Slot position of source 0 data , */\ + { 0x2443, "TDMVSS"}, /* Slot position of source 1 data , */\ + { 0x2483, "TDMCFS"}, /* Slot position of source 2 data , */\ + { 0x24c3, "TDMCF2S"}, /* Slot position of source 3 data , */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOCPR"}, /* Status OCP alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTMANALARM"}, /* Status manager alarm state , */\ + { 0x4060, "ISTTDMER"}, /* Status TDM error , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4080, "ISTCFMER"}, /* Status cfma error , */\ + { 0x4090, "ISTCFMAC"}, /* Status cfma ack , */\ + { 0x40a0, "ISTSPKS"}, /* Status coolflux speaker error , */\ + { 0x40b0, "ISTACS"}, /* Status cold started , */\ + { 0x40c0, "ISTWDS"}, /* Status watchdog reset , */\ + { 0x40d0, "ISTBODNOK"}, /* Status brown out detect , */\ + { 0x40e0, "ISTLP1"}, /* Status low power mode1 detect , */\ + { 0x40f0, "ISTCLKOOR"}, /* Status clock out of range , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOCPR"}, /* Clear OCP alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLMANALARM"}, /* Clear manager alarm state , */\ + { 0x4460, "ICLTDMER"}, /* Clear TDM error , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4480, "ICLCFMER"}, /* Clear cfma err , */\ + { 0x4490, "ICLCFMAC"}, /* Clear cfma ack , */\ + { 0x44a0, "ICLSPKS"}, /* Clear coolflux speaker error , */\ + { 0x44b0, "ICLACS"}, /* Clear cold started , */\ + { 0x44c0, "ICLWDS"}, /* Clear watchdog reset , */\ + { 0x44d0, "ICLBODNOK"}, /* Clear brown out detect , */\ + { 0x44e0, "ICLLP1"}, /* Clear low power mode1 detect , */\ + { 0x44f0, "ICLCLKOOR"}, /* Clear clock out of range , */\ + { 0x4800, "IEVDDS"}, /* Enable POR , */\ + { 0x4810, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOCPR"}, /* Enable OCP alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IEMANALARM"}, /* Enable Manager Alarm state , */\ + { 0x4860, "IETDMER"}, /* Enable TDM error , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4880, "IECFMER"}, /* Enable cfma err , */\ + { 0x4890, "IECFMAC"}, /* Enable cfma ack , */\ + { 0x48a0, "IESPKS"}, /* Enable coolflux speaker error , */\ + { 0x48b0, "IEACS"}, /* Enable cold started , */\ + { 0x48c0, "IEWDS"}, /* Enable watchdog reset , */\ + { 0x48d0, "IEBODNOK"}, /* Enable brown out detect , */\ + { 0x48e0, "IELP1"}, /* Enable low power mode1 detect , */\ + { 0x48f0, "IECLKOOR"}, /* Enable clock out of range , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity POR , */\ + { 0x4c10, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOCPR"}, /* Polarity ocp alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOMANALARM"}, /* Polarity manager alarm state , */\ + { 0x4c60, "IPOTDMER"}, /* Polarity TDM error , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4c80, "IPOCFMER"}, /* Polarity cfma err , */\ + { 0x4c90, "IPOCFMAC"}, /* Polarity cfma ack , */\ + { 0x4ca0, "IPOSPKS"}, /* Polarity coolflux speaker error , */\ + { 0x4cb0, "IPOACS"}, /* Polarity cold started , */\ + { 0x4cc0, "IPOWDS"}, /* Polarity watchdog reset , */\ + { 0x4cd0, "IPOBODNOK"}, /* Polarity brown out detect , */\ + { 0x4ce0, "IPOLP1"}, /* Polarity low power mode1 detect , */\ + { 0x4cf0, "IPOCLKOOR"}, /* Polarity clock out of range , */\ + { 0x5001, "BSSCR"}, /* Battery safeguard attack time , */\ + { 0x5023, "BSST"}, /* Battery safeguard threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery safeguard maximum reduction , */\ + { 0x5082, "BSSRR"}, /* Battery safeguard release time , */\ + { 0x50b1, "BSSHY"}, /* Battery Safeguard hysteresis , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass HW clipper , */\ + { 0x5130, "CFSM"}, /* Coolflux firmware soft mute control , */\ + { 0x5187, "VOL"}, /* CF firmware volume control , */\ + { 0x5202, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5230, "SLOPEE"}, /* Enables slope control , */\ + { 0x5240, "SLOPESET"}, /* Slope speed setting (binary coded) , */\ + { 0x5250, "BYPDLYLINE"}, /* Bypass the interpolator delay line , */\ + { 0x5287, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x5703, "TDMDCG"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5743, "TDMSPKG"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x5781, "DCINSEL"}, /* VAMP_OUT2 input selection , */\ + { 0x5881, "LNMODE"}, /* Low noise gain mode control , */\ + { 0x5ac1, "LPM1MODE"}, /* Low power mode control , */\ + { 0x5d02, "TDMSRCMAP"}, /* TDM source mapping , */\ + { 0x5d31, "TDMSRCAS"}, /* Sensed value A , */\ + { 0x5d51, "TDMSRCBS"}, /* Sensed value B , */\ + { 0x5d71, "TDMSRCACLIP"}, /* Clip information (analog /digital) for source0 , */\ + { 0x5d91, "TDMSRCBCLIP"}, /* Clip information (analog /digital) for source1 , */\ + { 0x6102, "DELCURCOMP"}, /* Delay to allign compensation signal with current sense signal, */\ + { 0x6130, "SIGCURCOMP"}, /* Polarity of compensation for current sense , */\ + { 0x6140, "ENCURCOMP"}, /* Enable current sense compensation , */\ + { 0x6152, "LVLCLPPWM"}, /* Set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7005, "DCVOF"}, /* First Boost Voltage Level , */\ + { 0x7065, "DCVOS"}, /* Second Boost Voltage Level , */\ + { 0x70c3, "DCMCC"}, /* Max Coil Current , */\ + { 0x7101, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7120, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7130, "DCSR"}, /* Soft ramp up/down , */\ + { 0x7140, "DCDIS"}, /* DCDC on/off , */\ + { 0x7150, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x7160, "DCTRACK"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7170, "DCENVSEL"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x7195, "OVSCTLVL"}, /* Threshold level to activate active overshoot control, */\ + { 0x7204, "DCTRIP"}, /* 1st adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7254, "DCTRIP2"}, /* 2nd adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x72a4, "DCTRIPT"}, /* Track adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x72f0, "DCTRIPHYSTE"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7304, "DCHOLD"}, /* Hold time / Hysteresis for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x9000, "RST"}, /* Reset for Coolflux DSP , */\ + { 0x9011, "DMEM"}, /* Target memory for CFMA using I2C interface , */\ + { 0x9030, "AIF"}, /* Auto increment , */\ + { 0x9040, "CFINT"}, /* Coolflux Interrupt - auto clear , */\ + { 0x9050, "CFCGATE"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "REQCMD"}, /* Firmware event request rpc command , */\ + { 0x9090, "REQRST"}, /* Firmware event request reset restart , */\ + { 0x90a0, "REQMIPS"}, /* Firmware event request short on mips , */\ + { 0x90b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "REQVOL"}, /* Firmware event request volume ready , */\ + { 0x90d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "REQCAL"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "REQRSV"}, /* Firmware event request reserved , */\ + { 0x910f, "MADD"}, /* CF memory address , */\ + { 0x920f, "MEMA"}, /* Activate memory access , */\ + { 0x9307, "ERR"}, /* CF error flags , */\ + { 0x9380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "ACKVOL"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "ACKDMG"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "ACKRSV"}, /* Firmware event acknowledge reserved , */\ + { 0xa107, "MTPK"}, /* KEY2 to access KEY2 protected registers, customer key, */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa350, "CMTPI"}, /* Start copying all the data from mtp to I2C mtp registers - auto clear, */\ + { 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp - auto clear, */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xca05, "PLLINSELI"}, /* PLL INSELI - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xca64, "PLLINSELP"}, /* PLL INSELP - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcab3, "PLLINSELR"}, /* PLL INSELR - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcb09, "PLLNDEC"}, /* PLL NDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcba0, "PLLMDECMSB"}, /* MSB of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbb0, "PLLBYPASS"}, /* PLL bypass control during functional mode , */\ + { 0xcbc0, "PLLDIRECTI"}, /* PLL directi control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbd0, "PLLDIRECTO"}, /* PLL directo control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbe0, "PLLFRMSTBL"}, /* PLL FRM clock stable control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbf0, "PLLFRM"}, /* PLL free running mode control in functional mode , */\ + { 0xcc0f, "PLLMDECLSB"}, /* Bits 15..0 of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcd06, "PLLPDEC"}, /* PLL PDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcd70, "DIRECTPLL"}, /* Enabled PLL direct control mode, overrules the PLL LUT with I2C register values, */\ + { 0xcd80, "DIRECTCLK"}, /* Enabled CGU clock divider direct control mode , */\ + { 0xcd90, "PLLLIM"}, /* PLL up limiter control in PLL direct bandwidth control mode, pll_bandsel set to 1, */\ + { 0xe00f, "SWPROFIL"}, /* Software profile data , */\ + { 0xe10f, "SWVSTEP"}, /* Software vstep information , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "CUSTINFO"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf50f, "R25C"}, /* Ron resistance of speaker coil , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9894N2_BITNAMETABLE static tfaBfName_t Tfa9894N2BitNames[] = {\ + { 0x0, "powerdown"}, /* Powerdown control , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x20, "enbl_coolflux"}, /* Enable CoolFlux DSP , */\ + { 0x30, "enbl_amplifier"}, /* Enable Amplifier , */\ + { 0x40, "enbl_boost"}, /* Enable DCDC Boost converter , */\ + { 0x50, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x60, "sel_enbl_amplifier"}, /* CoolFlux control over amplifier , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0x90, "fs_pulse_sel"}, /* Audio sample reference , */\ + { 0xa0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xb0, "test_ocp"}, /* OCP testing control , */\ + { 0xc0, "batsense_steepness"}, /* Vbat protection steepness , */\ + { 0xd0, "bypass_hp"}, /* Bypass High Pass Filter , */\ + { 0xe0, "enbl_dpsa"}, /* Enable DPSA , */\ + { 0xf0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ + { 0x101, "vamp_sel1"}, /* Amplifier input selection , */\ + { 0x120, "src_set_configured"}, /* Device I2C settings configured , */\ + { 0x130, "execute_cold_start"}, /* Execute cold start , */\ + { 0x140, "man_enbl_brown_out"}, /* Reaction on BOD , */\ + { 0x150, "bod_enbl"}, /* Enable BOD (only in direct control mode) , */\ + { 0x160, "bod_hyst_enbl"}, /* Enable Hysteresis of BOD , */\ + { 0x171, "bod_delay_set"}, /* BOD filter , */\ + { 0x191, "bod_lvl_set"}, /* BOD threshold , */\ + { 0x1b0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x1c0, "man_enbl_watchdog"}, /* Watchdog enable , */\ + { 0x1d0, "disable_engage"}, /* Disable Engage , */\ + { 0x1e0, "unprotect_faim"}, /* Control for FAIM protection , */\ + { 0x1f0, "faim_enable_vbg"}, /* Overrule the enabling of VBG for faim erase/write access, */\ + { 0x203, "audio_fs"}, /* Audio sample rate Fs , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* Current sense fractional delay , */\ + { 0x2b1, "use_tdm_presence"}, /* Control for HW manager , */\ + { 0x2d2, "ctrl_on2off_criterion"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external reference clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal reference clock , */\ + { 0x432, "mclk_sel"}, /* Master Clock Selection , */\ + { 0x460, "enbl_osc1m_auto_off"}, /* Internal OSC1M off at PWDN , */\ + { 0x470, "disable_auto_sel_refclk"}, /* Automatic PLL reference clock selection for cold start, */\ + { 0x480, "enbl_fs_sync"}, /* Enable FS synchronisation for clock divider , */\ + { 0x490, "enbl_clkref_sync"}, /* Enable PLL reference clock synchronisation for clock divider, */\ + { 0x4a0, "pll_slow_startup"}, /* PLL startup time configuration , */\ + { 0x500, "disable_cgu_sync_cgate"}, /* Clock gating control for CGU synchronisation module, */\ + { 0x510, "enbl_spkr_ss"}, /* Enable speaker sub-system , */\ + { 0x520, "enbl_faim_ss"}, /* Enable FAIM sub-system , */\ + { 0x530, "enbl_wdt_clk"}, /* Enable Coolflux watchdog clock , */\ + { 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ + { 0xf0f, "hidden_code"}, /* Hidden code to enable access to hidden register. (0x5A6B/23147 default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_pll_lock"}, /* PLL Lock , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm , */\ + { 0x1030, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm , */\ + { 0x1050, "flag_ocp_alarm"}, /* OCP amplifier (sticky register, clear on read) , */\ + { 0x1060, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1070, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1080, "flag_lost_clk"}, /* Lost clock , */\ + { 0x1090, "flag_cold_started"}, /* Cold Start , */\ + { 0x10a0, "flag_watchdog_reset"}, /* Watchdog , */\ + { 0x10b0, "flag_engage"}, /* Amplifier engage , */\ + { 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x10d0, "flag_enbl_ref"}, /* References enable , */\ + { 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x10f0, "flag_bod_vddd_nok"}, /* BOD Flag - VDD NOT OK , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active (sticky register, clear on read) , */\ + { 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos (sticky register, clear on read) , */\ + { 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1170, "flag_cf_speakererror"}, /* Speaker status , */\ + { 0x1180, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x1190, "flag_man_alarm_state"}, /* Alarm state , */\ + { 0x11a0, "flag_tdm_error"}, /* TDM error , */\ + { 0x11b0, "flag_tdm_lut_error"}, /* TDM lookup table error , */\ + { 0x11c0, "flag_lost_audio_clk"}, /* Lost Audio clock , */\ + { 0x1200, "flag_ocpokap"}, /* OCPOK pmos A , */\ + { 0x1210, "flag_ocpokan"}, /* OCPOK nmos A , */\ + { 0x1220, "flag_ocpokbp"}, /* OCPOK pmos B , */\ + { 0x1230, "flag_ocpokbn"}, /* OCPOK nmos B , */\ + { 0x1240, "flag_clip"}, /* Amplifier clipping , */\ + { 0x1250, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x1260, "flag_man_operating_state"}, /* Device in Operating state , */\ + { 0x1270, "flag_lp_detect_mode1"}, /* Low power MODE1 detection , */\ + { 0x1280, "flag_low_amplitude"}, /* Low amplitude detection , */\ + { 0x1290, "flag_vddp_gt_vbat"}, /* VDDP greater than VBAT flag , */\ + { 0x1302, "tdm_status"}, /* TDM Status bits , */\ + { 0x1333, "man_state"}, /* Device Manager status , */\ + { 0x1373, "amp_ctrl_state"}, /* Amplifier control status , */\ + { 0x13b1, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x1709, "vddp_adc"}, /* IC VDDP voltage (1023*VDDP/13V) , */\ + { 0x2000, "tdm_enable"}, /* Enable interface , */\ + { 0x2010, "tdm_sink0_enable"}, /* Control audio tdm channel in sink0 , */\ + { 0x2020, "tdm_sink1_enable"}, /* Control audio tdm channel in sink1 , */\ + { 0x2030, "tdm_source0_enable"}, /* Source 0 enable , */\ + { 0x2040, "tdm_source1_enable"}, /* Source 1 enable , */\ + { 0x2050, "tdm_source2_enable"}, /* Source 2 enable , */\ + { 0x2060, "tdm_source3_enable"}, /* Source 3 enable , */\ + { 0x2070, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2080, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x2090, "tdm_data_delay"}, /* Data delay to FS , */\ + { 0x20a0, "tdm_data_adjustment"}, /* Data adjustment , */\ + { 0x20b1, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2103, "tdm_nbck"}, /* TDM NBCK - Bit clock to FS ratio , */\ + { 0x2143, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ + { 0x2183, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x21c1, "tdm_txdata_format"}, /* Format unused bits , */\ + { 0x21e1, "tdm_txdata_format_unused_slot"}, /* Format unused slots DATAO , */\ + { 0x2204, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2254, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x22a4, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2303, "tdm_sink0_slot"}, /* TDM slot for sink 0 , */\ + { 0x2343, "tdm_sink1_slot"}, /* TDM slot for sink 1 , */\ + { 0x2381, "tdm_source2_sel"}, /* TDM Source 2 data selection , */\ + { 0x23a1, "tdm_source3_sel"}, /* TDM Source 3 data selection , */\ + { 0x2403, "tdm_source0_slot"}, /* Slot position of source 0 data , */\ + { 0x2443, "tdm_source1_slot"}, /* Slot position of source 1 data , */\ + { 0x2483, "tdm_source2_slot"}, /* Slot position of source 2 data , */\ + { 0x24c3, "tdm_source3_slot"}, /* Slot position of source 3 data , */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ocp_alarm"}, /* Status OCP alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_man_alarm_state"}, /* Status manager alarm state , */\ + { 0x4060, "int_out_flag_tdm_error"}, /* Status TDM error , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4080, "int_out_flag_cfma_err"}, /* Status cfma error , */\ + { 0x4090, "int_out_flag_cfma_ack"}, /* Status cfma ack , */\ + { 0x40a0, "int_out_flag_cf_speakererror"}, /* Status coolflux speaker error , */\ + { 0x40b0, "int_out_flag_cold_started"}, /* Status cold started , */\ + { 0x40c0, "int_out_flag_watchdog_reset"}, /* Status watchdog reset , */\ + { 0x40d0, "int_out_flag_bod_vddd_nok"}, /* Status brown out detect , */\ + { 0x40e0, "int_out_flag_lp_detect_mode1"}, /* Status low power mode1 detect , */\ + { 0x40f0, "int_out_flag_clk_out_of_range"}, /* Status clock out of range , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ocp_alarm"}, /* Clear OCP alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_man_alarm_state"}, /* Clear manager alarm state , */\ + { 0x4460, "int_in_flag_tdm_error"}, /* Clear TDM error , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4480, "int_in_flag_cfma_err"}, /* Clear cfma err , */\ + { 0x4490, "int_in_flag_cfma_ack"}, /* Clear cfma ack , */\ + { 0x44a0, "int_in_flag_cf_speakererror"}, /* Clear coolflux speaker error , */\ + { 0x44b0, "int_in_flag_cold_started"}, /* Clear cold started , */\ + { 0x44c0, "int_in_flag_watchdog_reset"}, /* Clear watchdog reset , */\ + { 0x44d0, "int_in_flag_bod_vddd_nok"}, /* Clear brown out detect , */\ + { 0x44e0, "int_in_flag_lp_detect_mode1"}, /* Clear low power mode1 detect , */\ + { 0x44f0, "int_in_flag_clk_out_of_range"}, /* Clear clock out of range , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable POR , */\ + { 0x4810, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ocp_alarm"}, /* Enable OCP alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_man_alarm_state"}, /* Enable Manager Alarm state , */\ + { 0x4860, "int_enable_flag_tdm_error"}, /* Enable TDM error , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4880, "int_enable_flag_cfma_err"}, /* Enable cfma err , */\ + { 0x4890, "int_enable_flag_cfma_ack"}, /* Enable cfma ack , */\ + { 0x48a0, "int_enable_flag_cf_speakererror"}, /* Enable coolflux speaker error , */\ + { 0x48b0, "int_enable_flag_cold_started"}, /* Enable cold started , */\ + { 0x48c0, "int_enable_flag_watchdog_reset"}, /* Enable watchdog reset , */\ + { 0x48d0, "int_enable_flag_bod_vddd_nok"}, /* Enable brown out detect , */\ + { 0x48e0, "int_enable_flag_lp_detect_mode1"}, /* Enable low power mode1 detect , */\ + { 0x48f0, "int_enable_flag_clk_out_of_range"}, /* Enable clock out of range , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity POR , */\ + { 0x4c10, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_man_alarm_state"}, /* Polarity manager alarm state , */\ + { 0x4c60, "int_polarity_flag_tdm_error"}, /* Polarity TDM error , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4c80, "int_polarity_flag_cfma_err"}, /* Polarity cfma err , */\ + { 0x4c90, "int_polarity_flag_cfma_ack"}, /* Polarity cfma ack , */\ + { 0x4ca0, "int_polarity_flag_cf_speakererror"}, /* Polarity coolflux speaker error , */\ + { 0x4cb0, "int_polarity_flag_cold_started"}, /* Polarity cold started , */\ + { 0x4cc0, "int_polarity_flag_watchdog_reset"}, /* Polarity watchdog reset , */\ + { 0x4cd0, "int_polarity_flag_bod_vddd_nok"}, /* Polarity brown out detect , */\ + { 0x4ce0, "int_polarity_flag_lp_detect_mode1"}, /* Polarity low power mode1 detect , */\ + { 0x4cf0, "int_polarity_flag_clk_out_of_range"}, /* Polarity clock out of range , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery safeguard attack time , */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery safeguard threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery safeguard maximum reduction , */\ + { 0x5082, "vbat_prot_release_time"}, /* Battery safeguard release time , */\ + { 0x50b1, "vbat_prot_hysterese"}, /* Battery Safeguard hysteresis , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass HW clipper , */\ + { 0x5130, "cf_mute"}, /* Coolflux firmware soft mute control , */\ + { 0x5187, "cf_volume"}, /* CF firmware volume control , */\ + { 0x5202, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5230, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x5240, "ctrl_slope"}, /* Slope speed setting (binary coded) , */\ + { 0x5250, "bypass_dly_line"}, /* Bypass the interpolator delay line , */\ + { 0x5287, "gain"}, /* Amplifier gain , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5340, "clipfast"}, /* Clock selection for HW clipper for battery safeguard, */\ + { 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x5360, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5370, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5380, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5390, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x53a3, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5400, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5413, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5452, "dpsa_drive"}, /* Drive setting (binary coded) , */\ + { 0x550a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually, */\ + { 0x55b0, "enbl_engage"}, /* Enables/engage power stage and control loop , */\ + { 0x55c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ + { 0x5600, "pwm_shape"}, /* PWM shape , */\ + { 0x5614, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0x5660, "reclock_pwm"}, /* Reclock the PWM signal inside analog , */\ + { 0x5670, "reclock_voltsense"}, /* Reclock the voltage sense PWM signal , */\ + { 0x5680, "enbl_pwm_phase_shift"}, /* Control for PWM phase shift , */\ + { 0x5690, "sel_pwm_delay_src"}, /* Control for selection for PWM delay line source , */\ + { 0x56a1, "enbl_odd_up_even_down"}, /* Control for PWM reference sawtooth generartion , */\ + { 0x5703, "ctrl_att_dcdc"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5743, "ctrl_att_spkr"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x5781, "vamp_sel2"}, /* VAMP_OUT2 input selection , */\ + { 0x5805, "zero_lvl"}, /* Low noise gain switch zero trigger level , */\ + { 0x5861, "ctrl_fb_resistor"}, /* Select amplifier feedback resistor connection , */\ + { 0x5881, "lownoisegain_mode"}, /* Low noise gain mode control , */\ + { 0x5905, "threshold_lvl"}, /* Low noise gain switch trigger level , */\ + { 0x5965, "hold_time"}, /* Low noise mode hold time before entering into low noise mode, */\ + { 0x5a05, "lpm1_cal_offset"}, /* Low power mode1 detector ctrl cal_offset from gain module , */\ + { 0x5a65, "lpm1_zero_lvl"}, /* Low power mode1 zero crossing detection level , */\ + { 0x5ac1, "lpm1_mode"}, /* Low power mode control , */\ + { 0x5b05, "lpm1_threshold_lvl"}, /* Low power mode1 amplitude trigger level , */\ + { 0x5b65, "lpm1_hold_time"}, /* Low power mode hold time before entering into low power mode, */\ + { 0x5bc0, "disable_low_power_mode"}, /* Low power mode1 detector control , */\ + { 0x5c00, "enbl_minion"}, /* Enables minion (small) power stage , */\ + { 0x5c13, "vth_vddpvbat"}, /* Select vddp-vbat threshold signal , */\ + { 0x5c50, "lpen_vddpvbat"}, /* Select vddp-vbat filtred vs unfiltered compare , */\ + { 0x5c61, "ctrl_rfb"}, /* Feedback resistor selection - I2C direct mode , */\ + { 0x5d02, "tdm_source_mapping"}, /* TDM source mapping , */\ + { 0x5d31, "tdm_sourcea_frame_sel"}, /* Sensed value A , */\ + { 0x5d51, "tdm_sourceb_frame_sel"}, /* Sensed value B , */\ + { 0x5d71, "tdm_source0_clip_sel"}, /* Clip information (analog /digital) for source0 , */\ + { 0x5d91, "tdm_source1_clip_sel"}, /* Clip information (analog /digital) for source1 , */\ + { 0x5e02, "rst_min_vbat_delay"}, /* Delay for reseting the min_vbat value inside HW Clipper (number of Fs pulses), */\ + { 0x5e30, "rst_min_vbat_sel"}, /* Control for selecting reset signal for min_bat , */\ + { 0x5f00, "hard_mute"}, /* Hard mute - PWM , */\ + { 0x5f12, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ + { 0x5f42, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ + { 0x5f78, "spare_out"}, /* Spare out register , */\ + { 0x600f, "spare_in"}, /* Spare IN , */\ + { 0x6102, "cursense_comp_delay"}, /* Delay to allign compensation signal with current sense signal, */\ + { 0x6130, "cursense_comp_sign"}, /* Polarity of compensation for current sense , */\ + { 0x6140, "enbl_cursense_comp"}, /* Enable current sense compensation , */\ + { 0x6152, "pwms_clip_lvl"}, /* Set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7005, "frst_boost_voltage"}, /* First Boost Voltage Level , */\ + { 0x7065, "scnd_boost_voltage"}, /* Second Boost Voltage Level , */\ + { 0x70c3, "boost_cur"}, /* Max Coil Current , */\ + { 0x7101, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7120, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7130, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x7140, "dcdcoff_mode"}, /* DCDC on/off , */\ + { 0x7150, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7160, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7170, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x7180, "ignore_flag_voutcomp86"}, /* Determines the maximum PWM frequency be the most efficient in relation to the Booster inductor value, */\ + { 0x7195, "overshoot_correction_lvl"}, /* Threshold level to activate active overshoot control, */\ + { 0x7204, "boost_trip_lvl_1st"}, /* 1st adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7254, "boost_trip_lvl_2nd"}, /* 2nd adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x72a4, "boost_trip_lvl_track"}, /* Track adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x72f0, "enbl_trip_hyst"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7304, "boost_hold_time"}, /* Hold time / Hysteresis for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x7350, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ + { 0x7361, "dcdc_ctrl_maxzercnt"}, /* Number of zero current flags to count before going to pfm mode, */\ + { 0x7386, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ + { 0x73f0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x7404, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7451, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7474, "bst_slopecur"}, /* For testing direct control slope current , */\ + { 0x74c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x74e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x74f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7500, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ + { 0x7510, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ + { 0x7520, "enbl_bst_peakcur"}, /* Enable peak current , */\ + { 0x7530, "enbl_bst_power"}, /* Enable line of the powerstage , */\ + { 0x7540, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x7550, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ + { 0x7560, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x7570, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x7580, "enbl_bst_windac"}, /* Enable window dac , */\ + { 0x7595, "bst_windac"}, /* For testing direct control windac , */\ + { 0x7600, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7611, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7631, "bst_freq"}, /* DCDC boost frequency control , */\ + { 0x7650, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7660, "bst_use_new_zercur_detect"}, /* Enable new zero current detection for boost control, */\ + { 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ + { 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ + { 0x8040, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8050, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8060, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8105, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP) * signal, */\ + { 0x8164, "cs_ktemp2"}, /* Second order temperature compensation coefficient , */\ + { 0x81b0, "enbl_cs_adc"}, /* Enable current sense ADC , */\ + { 0x81c0, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 , */\ + { 0x81d0, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 , */\ + { 0x81e0, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ + { 0x81f0, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 , */\ + { 0x8200, "enbl_cs_ldo"}, /* Enable current sense LDO , */\ + { 0x8210, "enbl_cs_vbatldo"}, /* Enable of current sense LDO , */\ + { 0x8220, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8231, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ + { 0x8250, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x8263, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ + { 0x82a0, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x82b4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ + { 0x8300, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ + { 0x8310, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8320, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8330, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8340, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8350, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if enbl_cs_ldo is high, */\ + { 0x8364, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8800, "ctrl_vs_igen_supply"}, /* Control for selecting supply for VS current generator, */\ + { 0x8810, "ctrl_vs_force_div2"}, /* Select input resistive divider gain , */\ + { 0x8820, "enbl_dc_filter"}, /* Control for enabling the DC blocking filter for voltage and current sense, */\ + { 0x8901, "volsense_pwm_sel"}, /* Voltage sense source selection control , */\ + { 0x8920, "vs_gain_control"}, /* Voltage sense gain control , */\ + { 0x8930, "vs_bypass_gc"}, /* Bypasses the VS gain correction , */\ + { 0x8940, "vs_adc_bsoinv"}, /* Bitstream inversion for voltage sense ADC , */\ + { 0x8950, "vs_adc_nortz"}, /* Return to zero for voltage sense ADC , */\ + { 0x8960, "vs_adc_slowdel"}, /* Select delay for voltage sense ADC (internal decision circuitry), */\ + { 0x8970, "vs_classd_tran_skip"}, /* Skip voltage sense connection during a classD amplifier transition, */\ + { 0x8987, "vs_gain"}, /* Voltage sense gain , */\ + { 0x8a00, "vs_inn_short"}, /* Short voltage sense negative to common mode , */\ + { 0x8a10, "vs_inp_short"}, /* Short voltage sense positive to common mode , */\ + { 0x8a20, "vs_ldo_bypass"}, /* Bypass voltage sense LDO , */\ + { 0x8a30, "vs_ldo_pulldown"}, /* Pull down voltage sense LDO, only valid if enbl_cs_ldo is high, */\ + { 0x8a44, "vs_ldo_voset"}, /* Voltage sense LDO voltage level setting (two's complement), */\ + { 0x8a90, "enbl_vs_adc"}, /* Enable voltage sense ADC , */\ + { 0x8aa0, "enbl_vs_inn1"}, /* Enable connection of voltage sense negative1 , */\ + { 0x8ab0, "enbl_vs_inn2"}, /* Enable connection of voltage sense negative2 , */\ + { 0x8ac0, "enbl_vs_inp1"}, /* Enable connection of voltage sense positive1 , */\ + { 0x8ad0, "enbl_vs_inp2"}, /* Enable connection of voltage sense positive2 , */\ + { 0x8ae0, "enbl_vs_ldo"}, /* Enable voltage sense LDO , */\ + { 0x8af0, "enbl_vs_vbatldo"}, /* Enable of voltage sense LDO , */\ + { 0x9000, "cf_rst_dsp"}, /* Reset for Coolflux DSP , */\ + { 0x9011, "cf_dmem"}, /* Target memory for CFMA using I2C interface , */\ + { 0x9030, "cf_aif"}, /* Auto increment , */\ + { 0x9040, "cf_int"}, /* Coolflux Interrupt - auto clear , */\ + { 0x9050, "cf_cgate_off"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "cf_req_cmd"}, /* Firmware event request rpc command , */\ + { 0x9090, "cf_req_reset"}, /* Firmware event request reset restart , */\ + { 0x90a0, "cf_req_mips"}, /* Firmware event request short on mips , */\ + { 0x90b0, "cf_req_mute_ready"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "cf_req_volume_ready"}, /* Firmware event request volume ready , */\ + { 0x90d0, "cf_req_damage"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "cf_req_calibrate_ready"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "cf_req_reserved"}, /* Firmware event request reserved , */\ + { 0x910f, "cf_madd"}, /* CF memory address , */\ + { 0x920f, "cf_mema"}, /* Activate memory access , */\ + { 0x9307, "cf_err"}, /* CF error flags , */\ + { 0x9380, "cf_ack_cmd"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "cf_ack_reset"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "cf_ack_mips"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "cf_ack_mute_ready"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "cf_ack_volume_ready"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "cf_ack_damage"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "cf_ack_calibrate_ready"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "cf_ack_reserved"}, /* Firmware event acknowledge reserved , */\ + { 0xa007, "mtpkey1"}, /* KEY1 To access KEY1 protected registers 0x5A/90d (default for engineering), */\ + { 0xa107, "mtpkey2"}, /* KEY2 to access KEY2 protected registers, customer key, */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from MTP to I2C mtp register - auto clear, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp - auto clear, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers - auto clear, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp - auto clear, */\ + { 0xa400, "faim_set_clkws"}, /* Sets the FaIM controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the FaIM are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the FaIM are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb000, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb010, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb020, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb030, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb040, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb050, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb060, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb070, "disable_main_ctrl_change_prot"}, /* Disable main control change protection , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ + { 0xc0c0, "use_direct_vs_ctrls"}, /* Voltage sense direct control to overrule several functions for testing, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "enbl_pll"}, /* Enables PLL in I2C direct control mode only , */\ + { 0xc0f0, "enbl_osc"}, /* Enables OSC in I2C direct control mode only , */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ + { 0xc3d0, "test_abistfft_enbl"}, /* Enable ABIST with FFT on Coolflux DSP , */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost Converter Over Current Protection , */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc530, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc540, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc550, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc560, "test_enbl_vs"}, /* Enable for digimux mode of voltage sense , */\ + { 0xc570, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc583, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc5c0, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc607, "digimuxa_sel"}, /* DigimuxA input selection control routed to DATAO , */\ + { 0xc687, "digimuxb_sel"}, /* DigimuxB input selection control routed to INT , */\ + { 0xc707, "digimuxc_sel"}, /* DigimuxC input selection control routed to ADS1 , */\ + { 0xc800, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xc810, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xc820, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xc830, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xc844, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xc894, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ + { 0xc903, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ + { 0xc943, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ + { 0xca05, "pll_inseli"}, /* PLL INSELI - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xca64, "pll_inselp"}, /* PLL INSELP - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcab3, "pll_inselr"}, /* PLL INSELR - PLL direct bandwidth control mode only with pll_bandsel set to 1, */\ + { 0xcaf0, "pll_bandsel"}, /* PLL bandwidth selection control, USE WITH CAUTION , */\ + { 0xcb09, "pll_ndec"}, /* PLL NDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcba0, "pll_mdec_msb"}, /* MSB of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbb0, "pll_bypass"}, /* PLL bypass control during functional mode , */\ + { 0xcbc0, "pll_directi"}, /* PLL directi control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbd0, "pll_directo"}, /* PLL directo control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbe0, "pll_frm_clockstable"}, /* PLL FRM clock stable control in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcbf0, "pll_frm"}, /* PLL free running mode control in functional mode , */\ + { 0xcc0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcd06, "pll_pdec"}, /* PLL PDEC in direct control mode only, use_direct_pll_ctrl set to 1, */\ + { 0xcd70, "use_direct_pll_ctrl"}, /* Enabled PLL direct control mode, overrules the PLL LUT with I2C register values, */\ + { 0xcd80, "use_direct_clk_ctrl"}, /* Enabled CGU clock divider direct control mode , */\ + { 0xcd90, "pll_limup_off"}, /* PLL up limiter control in PLL direct bandwidth control mode, pll_bandsel set to 1, */\ + { 0xce0f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xcf02, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xcf33, "tsig_gain"}, /* Test signal gain , */\ + { 0xd000, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd011, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd032, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd064, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd0b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd0c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd109, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd201, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ + { 0xd301, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO datasheet), */\ + { 0xd321, "datao_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO datasheet), */\ + { 0xd340, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xd407, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd480, "enbl_clk_out_of_range"}, /* Clock out of range , */\ + { 0xd491, "sel_wdt_clk"}, /* Watch dog clock divider settings , */\ + { 0xd4b0, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd500, "source_in_testmode"}, /* TDM source in test mode (return only current and voltage sense), */\ + { 0xd510, "gainatt_feedback"}, /* Gainatt feedback to tdm , */\ + { 0xd522, "test_parametric_io"}, /* Test IO parametric , */\ + { 0xd550, "ctrl_bst_clk_lp1"}, /* Boost clock control in low power mode1 , */\ + { 0xd561, "test_spare_out1"}, /* Test spare out 1 , */\ + { 0xd580, "bst_dcmbst"}, /* DCM boost , */\ + { 0xd593, "test_spare_out2"}, /* Test spare out 2 , */\ + { 0xe00f, "sw_profile"}, /* Software profile data , */\ + { 0xe10f, "sw_vstep"}, /* Software vstep information , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf163, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ + { 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ + { 0xf307, "calibr_gain_vs"}, /* Voltage sense gain , */\ + { 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ + { 0xf40f, "mtpdata4"}, /* MTP4 data , */\ + { 0xf50f, "calibr_R25C"}, /* Ron resistance of speaker coil , */\ + { 0xf60f, "mtpdata6"}, /* MTP6 data , */\ + { 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ + { 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable functionality of dcdcoff_mode bit , */\ + { 0xf910, "mtp_lock_enbl_coolflux"}, /* Disable functionality of enbl_coolflux bit , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_enbl_pwm_delay_clock_gating"}, /* PWM delay clock auto gating , */\ + { 0xf940, "mtp_enbl_ocp_clock_gating"}, /* OCP clock auto gating , */\ + { 0xf987, "type_bits_fw"}, /* MTP control for firmware features - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE , */\ + { 0xff07, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; +#if 0 +enum tfa9894_irq { + tfa9894_irq_max = -1, + tfa9894_irq_all = -1 /* all irqs */}; +#endif// +#define TFA9894_IRQ_NAMETABLE static tfaIrqName_t Tfa9894IrqNames[] = {\ +}; +#endif /* _TFA9894_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa9896_tfafieldnames.h b/sound/soc/codecs/tfa9896_tfafieldnames.h new file mode 100644 index 000000000000..db708b4e5f62 --- /dev/null +++ b/sound/soc/codecs/tfa9896_tfafieldnames.h @@ -0,0 +1,923 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9896_TFAFIELDNAMES_H +#define _TFA9896_TFAFIELDNAMES_H + + +#define TFA9896_I2CVERSION 16 + +typedef enum nxpTFA9896BfEnumList { + TFA9896_BF_VDDS = 0x0000, /*!< Power-on-reset flag (auto clear by reading) */ + TFA9896_BF_PLLS = 0x0010, /*!< PLL lock to programmed frequency */ + TFA9896_BF_OTDS = 0x0020, /*!< Over Temperature Protection alarm */ + TFA9896_BF_OVDS = 0x0030, /*!< Over Voltage Protection alarm */ + TFA9896_BF_UVDS = 0x0040, /*!< Under Voltage Protection alarm */ + TFA9896_BF_OCDS = 0x0050, /*!< Over Current Protection alarm */ + TFA9896_BF_CLKS = 0x0060, /*!< Clocks stable flag */ + TFA9896_BF_CLIPS = 0x0070, /*!< Amplifier clipping */ + TFA9896_BF_MTPB = 0x0080, /*!< MTP busy copying data to/from I2C registers */ + TFA9896_BF_NOCLK = 0x0090, /*!< lost clock detection (reference input clock) */ + TFA9896_BF_SPKS = 0x00a0, /*!< Speaker error */ + TFA9896_BF_ACS = 0x00b0, /*!< Cold Start required */ + TFA9896_BF_SWS = 0x00c0, /*!< Amplifier engage (Amp Switching) */ + TFA9896_BF_WDS = 0x00d0, /*!< watchdog reset (activates reset) */ + TFA9896_BF_AMPS = 0x00e0, /*!< Amplifier is enabled by manager */ + TFA9896_BF_AREFS = 0x00f0, /*!< References are enabled by manager */ + TFA9896_BF_BATS = 0x0109, /*!< Battery voltage from ADC readout */ + TFA9896_BF_TEMPS = 0x0208, /*!< Temperature readout from the temperature sensor ( C) */ + TFA9896_BF_REV = 0x030f, /*!< Device revision information */ + TFA9896_BF_RCV = 0x0420, /*!< Enable receiver mode */ + TFA9896_BF_CHS12 = 0x0431, /*!< Channel Selection TDM input for Coolflux */ + TFA9896_BF_INPLVL = 0x0450, /*!< Input level selection attenuator ( */ + TFA9896_BF_CHSA = 0x0461, /*!< Input selection for amplifier */ + TFA9896_BF_AUDFS = 0x04c3, /*!< Audio sample rate setting */ + TFA9896_BF_BSSCR = 0x0501, /*!< Batteery protection attack time */ + TFA9896_BF_BSST = 0x0523, /*!< Battery protection threshold level */ + TFA9896_BF_BSSRL = 0x0561, /*!< Battery protection maximum reduction */ + TFA9896_BF_BSSRR = 0x0582, /*!< Battery protection release time */ + TFA9896_BF_BSSHY = 0x05b1, /*!< Battery Protection Hysteresis */ + TFA9896_BF_BSSR = 0x05e0, /*!< Battery voltage value for read out (only) */ + TFA9896_BF_BSSBY = 0x05f0, /*!< Bypass clipper battery protection */ + TFA9896_BF_DPSA = 0x0600, /*!< Enable dynamic powerstage activation (DPSA) */ + TFA9896_BF_ATTEN = 0x0613, /*!< Gain attenuation setting */ + TFA9896_BF_CFSM = 0x0650, /*!< Soft mute in CoolFlux */ + TFA9896_BF_BSSS = 0x0670, /*!< Battery sense steepness */ + TFA9896_BF_VOL = 0x0687, /*!< Coolflux volume control */ + TFA9896_BF_DCVO2 = 0x0702, /*!< Second Boost Voltage */ + TFA9896_BF_DCMCC = 0x0733, /*!< Max boost coil current - step of 175 mA */ + TFA9896_BF_DCVO1 = 0x0772, /*!< First Boost Voltage */ + TFA9896_BF_DCIE = 0x07a0, /*!< Adaptive boost mode */ + TFA9896_BF_DCSR = 0x07b0, /*!< Soft Rampup/down mode for DCDC controller */ + TFA9896_BF_DCPAVG = 0x07c0, /*!< ctrl_peak2avg for analog part of DCDC */ + TFA9896_BF_DCPWM = 0x07d0, /*!< DCDC PWM only mode */ + TFA9896_BF_TROS = 0x0800, /*!< Selection ambient temperature for speaker calibration */ + TFA9896_BF_EXTTS = 0x0818, /*!< External temperature for speaker calibration (C) */ + TFA9896_BF_PWDN = 0x0900, /*!< powerdown selection */ + TFA9896_BF_I2CR = 0x0910, /*!< All I2C registers reset to default */ + TFA9896_BF_CFE = 0x0920, /*!< Enable CoolFlux */ + TFA9896_BF_AMPE = 0x0930, /*!< Enable Amplifier */ + TFA9896_BF_DCA = 0x0940, /*!< Enable DCDC Boost converter */ + TFA9896_BF_SBSL = 0x0950, /*!< Coolflux configured */ + TFA9896_BF_AMPC = 0x0960, /*!< Selection if Coolflux enables amplifier */ + TFA9896_BF_DCDIS = 0x0970, /*!< DCDC boost converter not connected */ + TFA9896_BF_PSDR = 0x0980, /*!< IDDQ amplifier test selection */ + TFA9896_BF_INTPAD = 0x09c1, /*!< INT pad (interrupt bump output) configuration */ + TFA9896_BF_IPLL = 0x09e0, /*!< PLL input reference clock selection */ + TFA9896_BF_DCTRIP = 0x0a04, /*!< Adaptive boost trip levels (effective only when boost_intel is set to 1) */ + TFA9896_BF_DCHOLD = 0x0a54, /*!< Hold time for DCDC booster (effective only when boost_intel is set to 1) */ + TFA9896_BF_MTPK = 0x0b07, /*!< KEY2 to access key2 protected registers (default for engineering) */ + TFA9896_BF_CVFDLY = 0x0c25, /*!< Fractional delay adjustment between current and voltage sense */ + TFA9896_BF_OPENMTP = 0x0ec0, /*!< Enable programming of the MTP memory */ + TFA9896_BF_TDMPRF = 0x1011, /*!< TDM usecase selection control */ + TFA9896_BF_TDMEN = 0x1030, /*!< TDM interface enable */ + TFA9896_BF_TDMCKINV = 0x1040, /*!< TDM clock inversion, receive on */ + TFA9896_BF_TDMFSLN = 0x1053, /*!< TDM FS length */ + TFA9896_BF_TDMFSPOL = 0x1090, /*!< TDM FS polarity (start frame) */ + TFA9896_BF_TDMSAMSZ = 0x10a4, /*!< TDM sample size for all TDM sinks and sources */ + TFA9896_BF_TDMSLOTS = 0x1103, /*!< TDM number of slots */ + TFA9896_BF_TDMSLLN = 0x1144, /*!< TDM slot length */ + TFA9896_BF_TDMBRMG = 0x1194, /*!< TDM bits remaining after the last slot */ + TFA9896_BF_TDMDDEL = 0x11e0, /*!< TDM data delay */ + TFA9896_BF_TDMDADJ = 0x11f0, /*!< TDM data adjustment */ + TFA9896_BF_TDMTXFRM = 0x1201, /*!< TDM TXDATA format */ + TFA9896_BF_TDMUUS0 = 0x1221, /*!< TDM TXDATA format unused slot SD0 */ + TFA9896_BF_TDMUUS1 = 0x1241, /*!< TDM TXDATA format unused slot SD1 */ + TFA9896_BF_TDMSI0EN = 0x1270, /*!< TDM sink0 enable */ + TFA9896_BF_TDMSI1EN = 0x1280, /*!< TDM sink1 enable */ + TFA9896_BF_TDMSI2EN = 0x1290, /*!< TDM sink2 enable */ + TFA9896_BF_TDMSO0EN = 0x12a0, /*!< TDM source0 enable */ + TFA9896_BF_TDMSO1EN = 0x12b0, /*!< TDM source1 enable */ + TFA9896_BF_TDMSO2EN = 0x12c0, /*!< TDM source2 enable */ + TFA9896_BF_TDMSI0IO = 0x12d0, /*!< TDM sink0 IO selection */ + TFA9896_BF_TDMSI1IO = 0x12e0, /*!< TDM sink1 IO selection */ + TFA9896_BF_TDMSI2IO = 0x12f0, /*!< TDM sink2 IO selection */ + TFA9896_BF_TDMSO0IO = 0x1300, /*!< TDM source0 IO selection */ + TFA9896_BF_TDMSO1IO = 0x1310, /*!< TDM source1 IO selection */ + TFA9896_BF_TDMSO2IO = 0x1320, /*!< TDM source2 IO selection */ + TFA9896_BF_TDMSI0SL = 0x1333, /*!< TDM sink0 slot position [GAIN IN] */ + TFA9896_BF_TDMSI1SL = 0x1373, /*!< TDM sink1 slot position [CH1 IN] */ + TFA9896_BF_TDMSI2SL = 0x13b3, /*!< TDM sink2 slot position [CH2 IN] */ + TFA9896_BF_TDMSO0SL = 0x1403, /*!< TDM source0 slot position [GAIN OUT] */ + TFA9896_BF_TDMSO1SL = 0x1443, /*!< TDM source1 slot position [Voltage Sense] */ + TFA9896_BF_TDMSO2SL = 0x1483, /*!< TDM source2 slot position [Current Sense] */ + TFA9896_BF_NBCK = 0x14c3, /*!< TDM NBCK bit clock ratio */ + TFA9896_BF_INTOVDDS = 0x2000, /*!< flag_por_int_out */ + TFA9896_BF_INTOPLLS = 0x2010, /*!< flag_pll_lock_int_out */ + TFA9896_BF_INTOOTDS = 0x2020, /*!< flag_otpok_int_out */ + TFA9896_BF_INTOOVDS = 0x2030, /*!< flag_ovpok_int_out */ + TFA9896_BF_INTOUVDS = 0x2040, /*!< flag_uvpok_int_out */ + TFA9896_BF_INTOOCDS = 0x2050, /*!< flag_ocp_alarm_int_out */ + TFA9896_BF_INTOCLKS = 0x2060, /*!< flag_clocks_stable_int_out */ + TFA9896_BF_INTOCLIPS = 0x2070, /*!< flag_clip_int_out */ + TFA9896_BF_INTOMTPB = 0x2080, /*!< mtp_busy_int_out */ + TFA9896_BF_INTONOCLK = 0x2090, /*!< flag_lost_clk_int_out */ + TFA9896_BF_INTOSPKS = 0x20a0, /*!< flag_cf_speakererror_int_out */ + TFA9896_BF_INTOACS = 0x20b0, /*!< flag_cold_started_int_out */ + TFA9896_BF_INTOSWS = 0x20c0, /*!< flag_engage_int_out */ + TFA9896_BF_INTOWDS = 0x20d0, /*!< flag_watchdog_reset_int_out */ + TFA9896_BF_INTOAMPS = 0x20e0, /*!< flag_enbl_amp_int_out */ + TFA9896_BF_INTOAREFS = 0x20f0, /*!< flag_enbl_ref_int_out */ + TFA9896_BF_INTOERR = 0x2200, /*!< flag_cfma_err_int_out */ + TFA9896_BF_INTOACK = 0x2210, /*!< flag_cfma_ack_int_out */ + TFA9896_BF_INTIVDDS = 0x2300, /*!< flag_por_int_in */ + TFA9896_BF_INTIPLLS = 0x2310, /*!< flag_pll_lock_int_in */ + TFA9896_BF_INTIOTDS = 0x2320, /*!< flag_otpok_int_in */ + TFA9896_BF_INTIOVDS = 0x2330, /*!< flag_ovpok_int_in */ + TFA9896_BF_INTIUVDS = 0x2340, /*!< flag_uvpok_int_in */ + TFA9896_BF_INTIOCDS = 0x2350, /*!< flag_ocp_alarm_int_in */ + TFA9896_BF_INTICLKS = 0x2360, /*!< flag_clocks_stable_int_in */ + TFA9896_BF_INTICLIPS = 0x2370, /*!< flag_clip_int_in */ + TFA9896_BF_INTIMTPB = 0x2380, /*!< mtp_busy_int_in */ + TFA9896_BF_INTINOCLK = 0x2390, /*!< flag_lost_clk_int_in */ + TFA9896_BF_INTISPKS = 0x23a0, /*!< flag_cf_speakererror_int_in */ + TFA9896_BF_INTIACS = 0x23b0, /*!< flag_cold_started_int_in */ + TFA9896_BF_INTISWS = 0x23c0, /*!< flag_engage_int_in */ + TFA9896_BF_INTIWDS = 0x23d0, /*!< flag_watchdog_reset_int_in */ + TFA9896_BF_INTIAMPS = 0x23e0, /*!< flag_enbl_amp_int_in */ + TFA9896_BF_INTIAREFS = 0x23f0, /*!< flag_enbl_ref_int_in */ + TFA9896_BF_INTIERR = 0x2500, /*!< flag_cfma_err_int_in */ + TFA9896_BF_INTIACK = 0x2510, /*!< flag_cfma_ack_int_in */ + TFA9896_BF_INTENVDDS = 0x2600, /*!< flag_por_int_enable */ + TFA9896_BF_INTENPLLS = 0x2610, /*!< flag_pll_lock_int_enable */ + TFA9896_BF_INTENOTDS = 0x2620, /*!< flag_otpok_int_enable */ + TFA9896_BF_INTENOVDS = 0x2630, /*!< flag_ovpok_int_enable */ + TFA9896_BF_INTENUVDS = 0x2640, /*!< flag_uvpok_int_enable */ + TFA9896_BF_INTENOCDS = 0x2650, /*!< flag_ocp_alarm_int_enable */ + TFA9896_BF_INTENCLKS = 0x2660, /*!< flag_clocks_stable_int_enable */ + TFA9896_BF_INTENCLIPS = 0x2670, /*!< flag_clip_int_enable */ + TFA9896_BF_INTENMTPB = 0x2680, /*!< mtp_busy_int_enable */ + TFA9896_BF_INTENNOCLK = 0x2690, /*!< flag_lost_clk_int_enable */ + TFA9896_BF_INTENSPKS = 0x26a0, /*!< flag_cf_speakererror_int_enable */ + TFA9896_BF_INTENACS = 0x26b0, /*!< flag_cold_started_int_enable */ + TFA9896_BF_INTENSWS = 0x26c0, /*!< flag_engage_int_enable */ + TFA9896_BF_INTENWDS = 0x26d0, /*!< flag_watchdog_reset_int_enable */ + TFA9896_BF_INTENAMPS = 0x26e0, /*!< flag_enbl_amp_int_enable */ + TFA9896_BF_INTENAREFS = 0x26f0, /*!< flag_enbl_ref_int_enable */ + TFA9896_BF_INTENERR = 0x2800, /*!< flag_cfma_err_int_enable */ + TFA9896_BF_INTENACK = 0x2810, /*!< flag_cfma_ack_int_enable */ + TFA9896_BF_INTPOLVDDS = 0x2900, /*!< flag_por_int_pol */ + TFA9896_BF_INTPOLPLLS = 0x2910, /*!< flag_pll_lock_int_pol */ + TFA9896_BF_INTPOLOTDS = 0x2920, /*!< flag_otpok_int_pol */ + TFA9896_BF_INTPOLOVDS = 0x2930, /*!< flag_ovpok_int_pol */ + TFA9896_BF_INTPOLUVDS = 0x2940, /*!< flag_uvpok_int_pol */ + TFA9896_BF_INTPOLOCDS = 0x2950, /*!< flag_ocp_alarm_int_pol */ + TFA9896_BF_INTPOLCLKS = 0x2960, /*!< flag_clocks_stable_int_pol */ + TFA9896_BF_INTPOLCLIPS = 0x2970, /*!< flag_clip_int_pol */ + TFA9896_BF_INTPOLMTPB = 0x2980, /*!< mtp_busy_int_pol */ + TFA9896_BF_INTPOLNOCLK = 0x2990, /*!< flag_lost_clk_int_pol */ + TFA9896_BF_INTPOLSPKS = 0x29a0, /*!< flag_cf_speakererror_int_pol */ + TFA9896_BF_INTPOLACS = 0x29b0, /*!< flag_cold_started_int_pol */ + TFA9896_BF_INTPOLSWS = 0x29c0, /*!< flag_engage_int_pol */ + TFA9896_BF_INTPOLWDS = 0x29d0, /*!< flag_watchdog_reset_int_pol */ + TFA9896_BF_INTPOLAMPS = 0x29e0, /*!< flag_enbl_amp_int_pol */ + TFA9896_BF_INTPOLAREFS = 0x29f0, /*!< flag_enbl_ref_int_pol */ + TFA9896_BF_INTPOLERR = 0x2b00, /*!< flag_cfma_err_int_pol */ + TFA9896_BF_INTPOLACK = 0x2b10, /*!< flag_cfma_ack_int_pol */ + TFA9896_BF_CLIP = 0x4900, /*!< Bypass clip control */ + TFA9896_BF_CIMTP = 0x62b0, /*!< Start copying data from I2C mtp registers to mtp */ + TFA9896_BF_RST = 0x7000, /*!< Reset CoolFlux DSP */ + TFA9896_BF_DMEM = 0x7011, /*!< Target memory for access */ + TFA9896_BF_AIF = 0x7030, /*!< Auto increment flag for memory-address */ + TFA9896_BF_CFINT = 0x7040, /*!< CF Interrupt - auto clear */ + TFA9896_BF_REQ = 0x7087, /*!< CF request for accessing the 8 channels */ + TFA9896_BF_MADD = 0x710f, /*!< Memory address */ + TFA9896_BF_MEMA = 0x720f, /*!< Activate memory access */ + TFA9896_BF_ERR = 0x7307, /*!< CF error flags */ + TFA9896_BF_ACK = 0x7387, /*!< CF acknowledgement of the requests channels */ + TFA9896_BF_MTPOTC = 0x8000, /*!< Calibration schedule selection */ + TFA9896_BF_MTPEX = 0x8010, /*!< Calibration of RON status bit */ +} nxpTFA9896BfEnumList_t; +#define TFA9896_NAMETABLE static tfaBfName_t Tfa9896DatasheetNames[] = {\ + { 0x0, "VDDS"}, /* Power-on-reset flag (auto clear by reading) , */\ + { 0x10, "PLLS"}, /* PLL lock to programmed frequency , */\ + { 0x20, "OTDS"}, /* Over Temperature Protection alarm , */\ + { 0x30, "OVDS"}, /* Over Voltage Protection alarm , */\ + { 0x40, "UVDS"}, /* Under Voltage Protection alarm , */\ + { 0x50, "OCDS"}, /* Over Current Protection alarm , */\ + { 0x60, "CLKS"}, /* Clocks stable flag , */\ + { 0x70, "CLIPS"}, /* Amplifier clipping , */\ + { 0x80, "MTPB"}, /* MTP busy copying data to/from I2C registers , */\ + { 0x90, "NOCLK"}, /* lost clock detection (reference input clock) , */\ + { 0xa0, "SPKS"}, /* Speaker error , */\ + { 0xb0, "ACS"}, /* Cold Start required , */\ + { 0xc0, "SWS"}, /* Amplifier engage (Amp Switching) , */\ + { 0xd0, "WDS"}, /* watchdog reset (activates reset) , */\ + { 0xe0, "AMPS"}, /* Amplifier is enabled by manager , */\ + { 0xf0, "AREFS"}, /* References are enabled by manager , */\ + { 0x109, "BATS"}, /* Battery voltage from ADC readout , */\ + { 0x208, "TEMPS"}, /* Temperature readout from the temperature sensor ( C), */\ + { 0x30f, "REV"}, /* Device revision information , */\ + { 0x420, "RCV"}, /* Enable receiver mode , */\ + { 0x431, "CHS12"}, /* Channel Selection TDM input for Coolflux , */\ + { 0x450, "INPLVL"}, /* Input level selection attenuator ( , */\ + { 0x461, "CHSA"}, /* Input selection for amplifier , */\ + { 0x4c3, "AUDFS"}, /* Audio sample rate setting , */\ + { 0x501, "BSSCR"}, /* Batteery protection attack time , */\ + { 0x523, "BSST"}, /* Battery protection threshold level , */\ + { 0x561, "BSSRL"}, /* Battery protection maximum reduction , */\ + { 0x582, "BSSRR"}, /* Battery protection release time , */\ + { 0x5b1, "BSSHY"}, /* Battery Protection Hysteresis , */\ + { 0x5e0, "BSSR"}, /* Battery voltage value for read out (only) , */\ + { 0x5f0, "BSSBY"}, /* Bypass clipper battery protection , */\ + { 0x600, "DPSA"}, /* Enable dynamic powerstage activation (DPSA) , */\ + { 0x613, "ATTEN"}, /* Gain attenuation setting , */\ + { 0x650, "CFSM"}, /* Soft mute in CoolFlux , */\ + { 0x670, "BSSS"}, /* Battery sense steepness , */\ + { 0x687, "VOL"}, /* Coolflux volume control , */\ + { 0x702, "DCVO2"}, /* Second Boost Voltage , */\ + { 0x733, "DCMCC"}, /* Max boost coil current - step of 175 mA , */\ + { 0x772, "DCVO1"}, /* First Boost Voltage , */\ + { 0x7a0, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7b0, "DCSR"}, /* Soft Rampup/down mode for DCDC controller , */\ + { 0x7c0, "DCPAVG"}, /* ctrl_peak2avg for analog part of DCDC , */\ + { 0x7d0, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x800, "TROS"}, /* Selection ambient temperature for speaker calibration , */\ + { 0x818, "EXTTS"}, /* External temperature for speaker calibration (C) , */\ + { 0x900, "PWDN"}, /* powerdown selection , */\ + { 0x910, "I2CR"}, /* All I2C registers reset to default , */\ + { 0x920, "CFE"}, /* Enable CoolFlux , */\ + { 0x930, "AMPE"}, /* Enable Amplifier , */\ + { 0x940, "DCA"}, /* Enable DCDC Boost converter , */\ + { 0x950, "SBSL"}, /* Coolflux configured , */\ + { 0x960, "AMPC"}, /* Selection if Coolflux enables amplifier , */\ + { 0x970, "DCDIS"}, /* DCDC boost converter not connected , */\ + { 0x980, "PSDR"}, /* IDDQ amplifier test selection , */\ + { 0x9c1, "INTPAD"}, /* INT pad (interrupt bump output) configuration , */\ + { 0x9e0, "IPLL"}, /* PLL input reference clock selection , */\ + { 0xa04, "DCTRIP"}, /* Adaptive boost trip levels (effective only when boost_intel is set to 1), */\ + { 0xa54, "DCHOLD"}, /* Hold time for DCDC booster (effective only when boost_intel is set to 1), */\ + { 0xb07, "MTPK"}, /* KEY2 to access key2 protected registers (default for engineering), */\ + { 0xc25, "CVFDLY"}, /* Fractional delay adjustment between current and voltage sense, */\ + { 0xec0, "OPENMTP"}, /* Enable programming of the MTP memory , */\ + { 0x1011, "TDMPRF"}, /* TDM usecase selection control , */\ + { 0x1030, "TDMEN"}, /* TDM interface enable , */\ + { 0x1040, "TDMCKINV"}, /* TDM clock inversion, receive on , */\ + { 0x1053, "TDMFSLN"}, /* TDM FS length , */\ + { 0x1090, "TDMFSPOL"}, /* TDM FS polarity (start frame) , */\ + { 0x10a4, "TDMSAMSZ"}, /* TDM sample size for all TDM sinks and sources , */\ + { 0x1103, "TDMSLOTS"}, /* TDM number of slots , */\ + { 0x1144, "TDMSLLN"}, /* TDM slot length , */\ + { 0x1194, "TDMBRMG"}, /* TDM bits remaining after the last slot , */\ + { 0x11e0, "TDMDDEL"}, /* TDM data delay , */\ + { 0x11f0, "TDMDADJ"}, /* TDM data adjustment , */\ + { 0x1201, "TDMTXFRM"}, /* TDM TXDATA format , */\ + { 0x1221, "TDMUUS0"}, /* TDM TXDATA format unused slot SD0 , */\ + { 0x1241, "TDMUUS1"}, /* TDM TXDATA format unused slot SD1 , */\ + { 0x1270, "TDMSI0EN"}, /* TDM sink0 enable , */\ + { 0x1280, "TDMSI1EN"}, /* TDM sink1 enable , */\ + { 0x1290, "TDMSI2EN"}, /* TDM sink2 enable , */\ + { 0x12a0, "TDMSO0EN"}, /* TDM source0 enable , */\ + { 0x12b0, "TDMSO1EN"}, /* TDM source1 enable , */\ + { 0x12c0, "TDMSO2EN"}, /* TDM source2 enable , */\ + { 0x12d0, "TDMSI0IO"}, /* TDM sink0 IO selection , */\ + { 0x12e0, "TDMSI1IO"}, /* TDM sink1 IO selection , */\ + { 0x12f0, "TDMSI2IO"}, /* TDM sink2 IO selection , */\ + { 0x1300, "TDMSO0IO"}, /* TDM source0 IO selection , */\ + { 0x1310, "TDMSO1IO"}, /* TDM source1 IO selection , */\ + { 0x1320, "TDMSO2IO"}, /* TDM source2 IO selection , */\ + { 0x1333, "TDMSI0SL"}, /* TDM sink0 slot position [GAIN IN] , */\ + { 0x1373, "TDMSI1SL"}, /* TDM sink1 slot position [CH1 IN] , */\ + { 0x13b3, "TDMSI2SL"}, /* TDM sink2 slot position [CH2 IN] , */\ + { 0x1403, "TDMSO0SL"}, /* TDM source0 slot position [GAIN OUT] , */\ + { 0x1443, "TDMSO1SL"}, /* TDM source1 slot position [Voltage Sense] , */\ + { 0x1483, "TDMSO2SL"}, /* TDM source2 slot position [Current Sense] , */\ + { 0x14c3, "NBCK"}, /* TDM NBCK bit clock ratio , */\ + { 0x2000, "INTOVDDS"}, /* flag_por_int_out , */\ + { 0x2010, "INTOPLLS"}, /* flag_pll_lock_int_out , */\ + { 0x2020, "INTOOTDS"}, /* flag_otpok_int_out , */\ + { 0x2030, "INTOOVDS"}, /* flag_ovpok_int_out , */\ + { 0x2040, "INTOUVDS"}, /* flag_uvpok_int_out , */\ + { 0x2050, "INTOOCDS"}, /* flag_ocp_alarm_int_out , */\ + { 0x2060, "INTOCLKS"}, /* flag_clocks_stable_int_out , */\ + { 0x2070, "INTOCLIPS"}, /* flag_clip_int_out , */\ + { 0x2080, "INTOMTPB"}, /* mtp_busy_int_out , */\ + { 0x2090, "INTONOCLK"}, /* flag_lost_clk_int_out , */\ + { 0x20a0, "INTOSPKS"}, /* flag_cf_speakererror_int_out , */\ + { 0x20b0, "INTOACS"}, /* flag_cold_started_int_out , */\ + { 0x20c0, "INTOSWS"}, /* flag_engage_int_out , */\ + { 0x20d0, "INTOWDS"}, /* flag_watchdog_reset_int_out , */\ + { 0x20e0, "INTOAMPS"}, /* flag_enbl_amp_int_out , */\ + { 0x20f0, "INTOAREFS"}, /* flag_enbl_ref_int_out , */\ + { 0x2200, "INTOERR"}, /* flag_cfma_err_int_out , */\ + { 0x2210, "INTOACK"}, /* flag_cfma_ack_int_out , */\ + { 0x2300, "INTIVDDS"}, /* flag_por_int_in , */\ + { 0x2310, "INTIPLLS"}, /* flag_pll_lock_int_in , */\ + { 0x2320, "INTIOTDS"}, /* flag_otpok_int_in , */\ + { 0x2330, "INTIOVDS"}, /* flag_ovpok_int_in , */\ + { 0x2340, "INTIUVDS"}, /* flag_uvpok_int_in , */\ + { 0x2350, "INTIOCDS"}, /* flag_ocp_alarm_int_in , */\ + { 0x2360, "INTICLKS"}, /* flag_clocks_stable_int_in , */\ + { 0x2370, "INTICLIPS"}, /* flag_clip_int_in , */\ + { 0x2380, "INTIMTPB"}, /* mtp_busy_int_in , */\ + { 0x2390, "INTINOCLK"}, /* flag_lost_clk_int_in , */\ + { 0x23a0, "INTISPKS"}, /* flag_cf_speakererror_int_in , */\ + { 0x23b0, "INTIACS"}, /* flag_cold_started_int_in , */\ + { 0x23c0, "INTISWS"}, /* flag_engage_int_in , */\ + { 0x23d0, "INTIWDS"}, /* flag_watchdog_reset_int_in , */\ + { 0x23e0, "INTIAMPS"}, /* flag_enbl_amp_int_in , */\ + { 0x23f0, "INTIAREFS"}, /* flag_enbl_ref_int_in , */\ + { 0x2500, "INTIERR"}, /* flag_cfma_err_int_in , */\ + { 0x2510, "INTIACK"}, /* flag_cfma_ack_int_in , */\ + { 0x2600, "INTENVDDS"}, /* flag_por_int_enable , */\ + { 0x2610, "INTENPLLS"}, /* flag_pll_lock_int_enable , */\ + { 0x2620, "INTENOTDS"}, /* flag_otpok_int_enable , */\ + { 0x2630, "INTENOVDS"}, /* flag_ovpok_int_enable , */\ + { 0x2640, "INTENUVDS"}, /* flag_uvpok_int_enable , */\ + { 0x2650, "INTENOCDS"}, /* flag_ocp_alarm_int_enable , */\ + { 0x2660, "INTENCLKS"}, /* flag_clocks_stable_int_enable , */\ + { 0x2670, "INTENCLIPS"}, /* flag_clip_int_enable , */\ + { 0x2680, "INTENMTPB"}, /* mtp_busy_int_enable , */\ + { 0x2690, "INTENNOCLK"}, /* flag_lost_clk_int_enable , */\ + { 0x26a0, "INTENSPKS"}, /* flag_cf_speakererror_int_enable , */\ + { 0x26b0, "INTENACS"}, /* flag_cold_started_int_enable , */\ + { 0x26c0, "INTENSWS"}, /* flag_engage_int_enable , */\ + { 0x26d0, "INTENWDS"}, /* flag_watchdog_reset_int_enable , */\ + { 0x26e0, "INTENAMPS"}, /* flag_enbl_amp_int_enable , */\ + { 0x26f0, "INTENAREFS"}, /* flag_enbl_ref_int_enable , */\ + { 0x2800, "INTENERR"}, /* flag_cfma_err_int_enable , */\ + { 0x2810, "INTENACK"}, /* flag_cfma_ack_int_enable , */\ + { 0x2900, "INTPOLVDDS"}, /* flag_por_int_pol , */\ + { 0x2910, "INTPOLPLLS"}, /* flag_pll_lock_int_pol , */\ + { 0x2920, "INTPOLOTDS"}, /* flag_otpok_int_pol , */\ + { 0x2930, "INTPOLOVDS"}, /* flag_ovpok_int_pol , */\ + { 0x2940, "INTPOLUVDS"}, /* flag_uvpok_int_pol , */\ + { 0x2950, "INTPOLOCDS"}, /* flag_ocp_alarm_int_pol , */\ + { 0x2960, "INTPOLCLKS"}, /* flag_clocks_stable_int_pol , */\ + { 0x2970, "INTPOLCLIPS"}, /* flag_clip_int_pol , */\ + { 0x2980, "INTPOLMTPB"}, /* mtp_busy_int_pol , */\ + { 0x2990, "INTPOLNOCLK"}, /* flag_lost_clk_int_pol , */\ + { 0x29a0, "INTPOLSPKS"}, /* flag_cf_speakererror_int_pol , */\ + { 0x29b0, "INTPOLACS"}, /* flag_cold_started_int_pol , */\ + { 0x29c0, "INTPOLSWS"}, /* flag_engage_int_pol , */\ + { 0x29d0, "INTPOLWDS"}, /* flag_watchdog_reset_int_pol , */\ + { 0x29e0, "INTPOLAMPS"}, /* flag_enbl_amp_int_pol , */\ + { 0x29f0, "INTPOLAREFS"}, /* flag_enbl_ref_int_pol , */\ + { 0x2b00, "INTPOLERR"}, /* flag_cfma_err_int_pol , */\ + { 0x2b10, "INTPOLACK"}, /* flag_cfma_ack_int_pol , */\ + { 0x4900, "CLIP"}, /* Bypass clip control , */\ + { 0x62b0, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0x7000, "RST"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "DMEM"}, /* Target memory for access , */\ + { 0x7030, "AIF"}, /* Auto increment flag for memory-address , */\ + { 0x7040, "CFINT"}, /* CF Interrupt - auto clear , */\ + { 0x7087, "REQ"}, /* CF request for accessing the 8 channels , */\ + { 0x710f, "MADD"}, /* Memory address , */\ + { 0x720f, "MEMA"}, /* Activate memory access , */\ + { 0x7307, "ERR"}, /* CF error flags , */\ + { 0x7387, "ACK"}, /* CF acknowledgement of the requests channels , */\ + { 0x8000, "MTPOTC"}, /* Calibration schedule selection , */\ + { 0x8010, "MTPEX"}, /* Calibration of RON status bit , */\ + { 0x8045, "SWPROFIL" },\ + { 0x80a5, "SWVSTEP" },\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9896_BITNAMETABLE static tfaBfName_t Tfa9896BitNames[] = {\ + { 0x0, "flag_por"}, /* Power-on-reset flag (auto clear by reading) , */\ + { 0x10, "flag_pll_lock"}, /* PLL lock to programmed frequency , */\ + { 0x20, "flag_otpok"}, /* Over Temperature Protection alarm , */\ + { 0x30, "flag_ovpok"}, /* Over Voltage Protection alarm , */\ + { 0x40, "flag_uvpok"}, /* Under Voltage Protection alarm , */\ + { 0x50, "flag_ocp_alarm"}, /* Over Current Protection alarm , */\ + { 0x60, "flag_clocks_stable"}, /* Clocks stable flag , */\ + { 0x70, "flag_clip"}, /* Amplifier clipping , */\ + { 0x80, "mtp_busy"}, /* MTP busy copying data to/from I2C registers , */\ + { 0x90, "flag_lost_clk"}, /* lost clock detection (reference input clock) , */\ + { 0xa0, "flag_cf_speakererror"}, /* Speaker error , */\ + { 0xb0, "flag_cold_started"}, /* Cold Start required , */\ + { 0xc0, "flag_engage"}, /* Amplifier engage (Amp Switching) , */\ + { 0xd0, "flag_watchdog_reset"}, /* watchdog reset (activates reset) , */\ + { 0xe0, "flag_enbl_amp"}, /* Amplifier is enabled by manager , */\ + { 0xf0, "flag_enbl_ref"}, /* References are enabled by manager , */\ + { 0x109, "bat_adc"}, /* Battery voltage from ADC readout , */\ + { 0x208, "temp_adc"}, /* Temperature readout from the temperature sensor ( C), */\ + { 0x30f, "device_rev"}, /* Device revision information , */\ + { 0x420, "ctrl_rcv"}, /* Enable receiver mode , */\ + { 0x431, "chan_sel"}, /* Channel Selection TDM input for Coolflux , */\ + { 0x450, "input_level"}, /* Input level selection attenuator ( , */\ + { 0x461, "vamp_sel"}, /* Input selection for amplifier , */\ + { 0x4c3, "audio_fs"}, /* Audio sample rate setting , */\ + { 0x501, "vbat_prot_attacktime"}, /* Batteery protection attack time , */\ + { 0x523, "vbat_prot_thlevel"}, /* Battery protection threshold level , */\ + { 0x561, "vbat_prot_max_reduct"}, /* Battery protection maximum reduction , */\ + { 0x582, "vbat_prot_release_t"}, /* Battery protection release time , */\ + { 0x5b1, "vbat_prot_hysterese"}, /* Battery Protection Hysteresis , */\ + { 0x5d0, "reset_min_vbat"}, /* Battery supply safeguard clipper reset ( if CF_DSP is bypassed), */\ + { 0x5e0, "sel_vbat"}, /* Battery voltage value for read out (only) , */\ + { 0x5f0, "bypass_clipper"}, /* Bypass clipper battery protection , */\ + { 0x600, "dpsa"}, /* Enable dynamic powerstage activation (DPSA) , */\ + { 0x613, "ctrl_att"}, /* Gain attenuation setting , */\ + { 0x650, "cf_mute"}, /* Soft mute in CoolFlux , */\ + { 0x670, "batsense_steepness"}, /* Battery sense steepness , */\ + { 0x687, "vol"}, /* Coolflux volume control , */\ + { 0x702, "scnd_boost_voltage"}, /* Second Boost Voltage , */\ + { 0x733, "boost_cur"}, /* Max boost coil current - step of 175 mA , */\ + { 0x772, "frst_boost_voltage"}, /* First Boost Voltage , */\ + { 0x7a0, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7b0, "boost_speed"}, /* Soft Rampup/down mode for DCDC controller , */\ + { 0x7c0, "boost_peak2avg"}, /* ctrl_peak2avg for analog part of DCDC , */\ + { 0x7d0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7e0, "ignore_flag_voutcomp86"}, /* Ignore flag_voutcomp86 (flag from analog) , */\ + { 0x800, "ext_temp_sel"}, /* Selection ambient temperature for speaker calibration , */\ + { 0x818, "ext_temp"}, /* External temperature for speaker calibration (C) , */\ + { 0x900, "powerdown"}, /* powerdown selection , */\ + { 0x910, "reset"}, /* All I2C registers reset to default , */\ + { 0x920, "enbl_coolflux"}, /* Enable CoolFlux , */\ + { 0x930, "enbl_amplifier"}, /* Enable Amplifier , */\ + { 0x940, "enbl_boost"}, /* Enable DCDC Boost converter , */\ + { 0x950, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x960, "sel_enbl_amplifier"}, /* Selection if Coolflux enables amplifier , */\ + { 0x970, "dcdcoff_mode"}, /* DCDC boost converter not connected , */\ + { 0x980, "iddqtest"}, /* IDDQ amplifier test selection , */\ + { 0x9c1, "int_pad_io"}, /* INT pad (interrupt bump output) configuration , */\ + { 0x9e0, "sel_fs_bck"}, /* PLL input reference clock selection , */\ + { 0x9f0, "sel_scl_cf_clock"}, /* Coolflux sub-system clock selection , */\ + { 0xa04, "boost_trip_lvl"}, /* Adaptive boost trip levels (effective only when boost_intel is set to 1), */\ + { 0xa54, "boost_hold_time"}, /* Hold time for DCDC booster (effective only when boost_intel is set to 1), */\ + { 0xaa1, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0xb07, "mtpkey2"}, /* KEY2 to access key2 protected registers (default for engineering), */\ + { 0xc00, "enbl_volt_sense"}, /* Voltage sense enabling control bit , */\ + { 0xc10, "vsense_pwm_sel"}, /* Voltage sense source selection , */\ + { 0xc25, "vi_frac_delay"}, /* Fractional delay adjustment between current and voltage sense, */\ + { 0xc80, "sel_voltsense_out"}, /* TDM output data selection for AEC , */\ + { 0xc90, "vsense_bypass_avg"}, /* Voltage sense average block bypass , */\ + { 0xd05, "cf_frac_delay"}, /* Fractional delay adjustment between current and voltage sense by firmware, */\ + { 0xe00, "bypass_dcdc_curr_prot"}, /* Control to switch off dcdc current reduction with bat protection, */\ + { 0xe10, "bypass_ocp"}, /* Bypass OCP (digital IP block) , */\ + { 0xe20, "ocptest"}, /* ocptest (analog IP block) enable , */\ + { 0xe80, "disable_clock_sh_prot"}, /* Disable clock_sh protection , */\ + { 0xe92, "reserve_reg_15_09"}, /* Spare control bits for future usage , */\ + { 0xec0, "unprotect_mtp"}, /* Enable programming of the MTP memory , */\ + { 0xed2, "reserve_reg_15_13"}, /* Spare control bits for future usage , */\ + { 0xf00, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode forcing each 50us a pwm pulse , */\ + { 0xf11, "dcdc_ctrl_maxzercnt"}, /* DCDC number of zero current flags required to go to pfm mode, */\ + { 0xf36, "dcdc_vbat_delta_detect"}, /* DCDC threshold required on a delta Vbat (in PFM mode) switching to PWM mode, */\ + { 0xfa0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x1011, "tdm_usecase"}, /* TDM usecase selection control , */\ + { 0x1030, "tdm_enable"}, /* TDM interface enable , */\ + { 0x1040, "tdm_clk_inversion"}, /* TDM clock inversion, receive on , */\ + { 0x1053, "tdm_fs_ws_length"}, /* TDM FS length , */\ + { 0x1090, "tdm_fs_ws_polarity"}, /* TDM FS polarity (start frame) , */\ + { 0x10a4, "tdm_sample_size"}, /* TDM sample size for all TDM sinks and sources , */\ + { 0x1103, "tdm_nb_of_slots"}, /* TDM number of slots , */\ + { 0x1144, "tdm_slot_length"}, /* TDM slot length , */\ + { 0x1194, "tdm_bits_remaining"}, /* TDM bits remaining after the last slot , */\ + { 0x11e0, "tdm_data_delay"}, /* TDM data delay , */\ + { 0x11f0, "tdm_data_adjustment"}, /* TDM data adjustment , */\ + { 0x1201, "tdm_txdata_format"}, /* TDM TXDATA format , */\ + { 0x1221, "tdm_txdata_format_unused_slot_sd0"}, /* TDM TXDATA format unused slot SD0 , */\ + { 0x1241, "tdm_txdata_format_unused_slot_sd1"}, /* TDM TXDATA format unused slot SD1 , */\ + { 0x1270, "tdm_sink0_enable"}, /* TDM sink0 enable , */\ + { 0x1280, "tdm_sink1_enable"}, /* TDM sink1 enable , */\ + { 0x1290, "tdm_sink2_enable"}, /* TDM sink2 enable , */\ + { 0x12a0, "tdm_source0_enable"}, /* TDM source0 enable , */\ + { 0x12b0, "tdm_source1_enable"}, /* TDM source1 enable , */\ + { 0x12c0, "tdm_source2_enable"}, /* TDM source2 enable , */\ + { 0x12d0, "tdm_sink0_io"}, /* TDM sink0 IO selection , */\ + { 0x12e0, "tdm_sink1_io"}, /* TDM sink1 IO selection , */\ + { 0x12f0, "tdm_sink2_io"}, /* TDM sink2 IO selection , */\ + { 0x1300, "tdm_source0_io"}, /* TDM source0 IO selection , */\ + { 0x1310, "tdm_source1_io"}, /* TDM source1 IO selection , */\ + { 0x1320, "tdm_source2_io"}, /* TDM source2 IO selection , */\ + { 0x1333, "tdm_sink0_slot"}, /* TDM sink0 slot position [GAIN IN] , */\ + { 0x1373, "tdm_sink1_slot"}, /* TDM sink1 slot position [CH1 IN] , */\ + { 0x13b3, "tdm_sink2_slot"}, /* TDM sink2 slot position [CH2 IN] , */\ + { 0x1403, "tdm_source0_slot"}, /* TDM source0 slot position [GAIN OUT] , */\ + { 0x1443, "tdm_source1_slot"}, /* TDM source1 slot position [Voltage Sense] , */\ + { 0x1483, "tdm_source2_slot"}, /* TDM source2 slot position [Current Sense] , */\ + { 0x14c3, "tdm_nbck"}, /* TDM NBCK bit clock ratio , */\ + { 0x1500, "flag_tdm_lut_error"}, /* TDM LUT error flag , */\ + { 0x1512, "flag_tdm_status"}, /* TDM interface status bits , */\ + { 0x1540, "flag_tdm_error"}, /* TDM interface error indicator , */\ + { 0x1551, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x2000, "flag_por_int_out"}, /* flag_por_int_out , */\ + { 0x2010, "flag_pll_lock_int_out"}, /* flag_pll_lock_int_out , */\ + { 0x2020, "flag_otpok_int_out"}, /* flag_otpok_int_out , */\ + { 0x2030, "flag_ovpok_int_out"}, /* flag_ovpok_int_out , */\ + { 0x2040, "flag_uvpok_int_out"}, /* flag_uvpok_int_out , */\ + { 0x2050, "flag_ocp_alarm_int_out"}, /* flag_ocp_alarm_int_out , */\ + { 0x2060, "flag_clocks_stable_int_out"}, /* flag_clocks_stable_int_out , */\ + { 0x2070, "flag_clip_int_out"}, /* flag_clip_int_out , */\ + { 0x2080, "mtp_busy_int_out"}, /* mtp_busy_int_out , */\ + { 0x2090, "flag_lost_clk_int_out"}, /* flag_lost_clk_int_out , */\ + { 0x20a0, "flag_cf_speakererror_int_out"}, /* flag_cf_speakererror_int_out , */\ + { 0x20b0, "flag_cold_started_int_out"}, /* flag_cold_started_int_out , */\ + { 0x20c0, "flag_engage_int_out"}, /* flag_engage_int_out , */\ + { 0x20d0, "flag_watchdog_reset_int_out"}, /* flag_watchdog_reset_int_out , */\ + { 0x20e0, "flag_enbl_amp_int_out"}, /* flag_enbl_amp_int_out , */\ + { 0x20f0, "flag_enbl_ref_int_out"}, /* flag_enbl_ref_int_out , */\ + { 0x2100, "flag_voutcomp_int_out"}, /* flag_voutcomp_int_out , */\ + { 0x2110, "flag_voutcomp93_int_out"}, /* flag_voutcomp93_int_out , */\ + { 0x2120, "flag_voutcomp86_int_out"}, /* flag_voutcomp86_int_out , */\ + { 0x2130, "flag_hiz_int_out"}, /* flag_hiz_int_out , */\ + { 0x2140, "flag_ocpokbst_int_out"}, /* flag_ocpokbst_int_out , */\ + { 0x2150, "flag_peakcur_int_out"}, /* flag_peakcur_int_out , */\ + { 0x2160, "flag_ocpokap_int_out"}, /* flag_ocpokap_int_out , */\ + { 0x2170, "flag_ocpokan_int_out"}, /* flag_ocpokan_int_out , */\ + { 0x2180, "flag_ocpokbp_int_out"}, /* flag_ocpokbp_int_out , */\ + { 0x2190, "flag_ocpokbn_int_out"}, /* flag_ocpokbn_int_out , */\ + { 0x21a0, "flag_adc10_ready_int_out"}, /* flag_adc10_ready_int_out , */\ + { 0x21b0, "flag_clipa_high_int_out"}, /* flag_clipa_high_int_out , */\ + { 0x21c0, "flag_clipa_low_int_out"}, /* flag_clipa_low_int_out , */\ + { 0x21d0, "flag_clipb_high_int_out"}, /* flag_clipb_high_int_out , */\ + { 0x21e0, "flag_clipb_low_int_out"}, /* flag_clipb_low_int_out , */\ + { 0x21f0, "flag_tdm_error_int_out"}, /* flag_tdm_error_int_out , */\ + { 0x2200, "flag_cfma_err_int_out"}, /* flag_cfma_err_int_out , */\ + { 0x2210, "flag_cfma_ack_int_out"}, /* flag_cfma_ack_int_out , */\ + { 0x2300, "flag_por_int_in"}, /* flag_por_int_in , */\ + { 0x2310, "flag_pll_lock_int_in"}, /* flag_pll_lock_int_in , */\ + { 0x2320, "flag_otpok_int_in"}, /* flag_otpok_int_in , */\ + { 0x2330, "flag_ovpok_int_in"}, /* flag_ovpok_int_in , */\ + { 0x2340, "flag_uvpok_int_in"}, /* flag_uvpok_int_in , */\ + { 0x2350, "flag_ocp_alarm_int_in"}, /* flag_ocp_alarm_int_in , */\ + { 0x2360, "flag_clocks_stable_int_in"}, /* flag_clocks_stable_int_in , */\ + { 0x2370, "flag_clip_int_in"}, /* flag_clip_int_in , */\ + { 0x2380, "mtp_busy_int_in"}, /* mtp_busy_int_in , */\ + { 0x2390, "flag_lost_clk_int_in"}, /* flag_lost_clk_int_in , */\ + { 0x23a0, "flag_cf_speakererror_int_in"}, /* flag_cf_speakererror_int_in , */\ + { 0x23b0, "flag_cold_started_int_in"}, /* flag_cold_started_int_in , */\ + { 0x23c0, "flag_engage_int_in"}, /* flag_engage_int_in , */\ + { 0x23d0, "flag_watchdog_reset_int_in"}, /* flag_watchdog_reset_int_in , */\ + { 0x23e0, "flag_enbl_amp_int_in"}, /* flag_enbl_amp_int_in , */\ + { 0x23f0, "flag_enbl_ref_int_in"}, /* flag_enbl_ref_int_in , */\ + { 0x2400, "flag_voutcomp_int_in"}, /* flag_voutcomp_int_in , */\ + { 0x2410, "flag_voutcomp93_int_in"}, /* flag_voutcomp93_int_in , */\ + { 0x2420, "flag_voutcomp86_int_in"}, /* flag_voutcomp86_int_in , */\ + { 0x2430, "flag_hiz_int_in"}, /* flag_hiz_int_in , */\ + { 0x2440, "flag_ocpokbst_int_in"}, /* flag_ocpokbst_int_in , */\ + { 0x2450, "flag_peakcur_int_in"}, /* flag_peakcur_int_in , */\ + { 0x2460, "flag_ocpokap_int_in"}, /* flag_ocpokap_int_in , */\ + { 0x2470, "flag_ocpokan_int_in"}, /* flag_ocpokan_int_in , */\ + { 0x2480, "flag_ocpokbp_int_in"}, /* flag_ocpokbp_int_in , */\ + { 0x2490, "flag_ocpokbn_int_in"}, /* flag_ocpokbn_int_in , */\ + { 0x24a0, "flag_adc10_ready_int_in"}, /* flag_adc10_ready_int_in , */\ + { 0x24b0, "flag_clipa_high_int_in"}, /* flag_clipa_high_int_in , */\ + { 0x24c0, "flag_clipa_low_int_in"}, /* flag_clipa_low_int_in , */\ + { 0x24d0, "flag_clipb_high_int_in"}, /* flag_clipb_high_int_in , */\ + { 0x24e0, "flag_clipb_low_int_in"}, /* flag_clipb_low_int_in , */\ + { 0x24f0, "flag_tdm_error_int_in"}, /* flag_tdm_error_int_in , */\ + { 0x2500, "flag_cfma_err_int_in"}, /* flag_cfma_err_int_in , */\ + { 0x2510, "flag_cfma_ack_int_in"}, /* flag_cfma_ack_int_in , */\ + { 0x2600, "flag_por_int_enable"}, /* flag_por_int_enable , */\ + { 0x2610, "flag_pll_lock_int_enable"}, /* flag_pll_lock_int_enable , */\ + { 0x2620, "flag_otpok_int_enable"}, /* flag_otpok_int_enable , */\ + { 0x2630, "flag_ovpok_int_enable"}, /* flag_ovpok_int_enable , */\ + { 0x2640, "flag_uvpok_int_enable"}, /* flag_uvpok_int_enable , */\ + { 0x2650, "flag_ocp_alarm_int_enable"}, /* flag_ocp_alarm_int_enable , */\ + { 0x2660, "flag_clocks_stable_int_enable"}, /* flag_clocks_stable_int_enable , */\ + { 0x2670, "flag_clip_int_enable"}, /* flag_clip_int_enable , */\ + { 0x2680, "mtp_busy_int_enable"}, /* mtp_busy_int_enable , */\ + { 0x2690, "flag_lost_clk_int_enable"}, /* flag_lost_clk_int_enable , */\ + { 0x26a0, "flag_cf_speakererror_int_enable"}, /* flag_cf_speakererror_int_enable , */\ + { 0x26b0, "flag_cold_started_int_enable"}, /* flag_cold_started_int_enable , */\ + { 0x26c0, "flag_engage_int_enable"}, /* flag_engage_int_enable , */\ + { 0x26d0, "flag_watchdog_reset_int_enable"}, /* flag_watchdog_reset_int_enable , */\ + { 0x26e0, "flag_enbl_amp_int_enable"}, /* flag_enbl_amp_int_enable , */\ + { 0x26f0, "flag_enbl_ref_int_enable"}, /* flag_enbl_ref_int_enable , */\ + { 0x2700, "flag_voutcomp_int_enable"}, /* flag_voutcomp_int_enable , */\ + { 0x2710, "flag_voutcomp93_int_enable"}, /* flag_voutcomp93_int_enable , */\ + { 0x2720, "flag_voutcomp86_int_enable"}, /* flag_voutcomp86_int_enable , */\ + { 0x2730, "flag_hiz_int_enable"}, /* flag_hiz_int_enable , */\ + { 0x2740, "flag_ocpokbst_int_enable"}, /* flag_ocpokbst_int_enable , */\ + { 0x2750, "flag_peakcur_int_enable"}, /* flag_peakcur_int_enable , */\ + { 0x2760, "flag_ocpokap_int_enable"}, /* flag_ocpokap_int_enable , */\ + { 0x2770, "flag_ocpokan_int_enable"}, /* flag_ocpokan_int_enable , */\ + { 0x2780, "flag_ocpokbp_int_enable"}, /* flag_ocpokbp_int_enable , */\ + { 0x2790, "flag_ocpokbn_int_enable"}, /* flag_ocpokbn_int_enable , */\ + { 0x27a0, "flag_adc10_ready_int_enable"}, /* flag_adc10_ready_int_enable , */\ + { 0x27b0, "flag_clipa_high_int_enable"}, /* flag_clipa_high_int_enable , */\ + { 0x27c0, "flag_clipa_low_int_enable"}, /* flag_clipa_low_int_enable , */\ + { 0x27d0, "flag_clipb_high_int_enable"}, /* flag_clipb_high_int_enable , */\ + { 0x27e0, "flag_clipb_low_int_enable"}, /* flag_clipb_low_int_enable , */\ + { 0x27f0, "flag_tdm_error_int_enable"}, /* flag_tdm_error_int_enable , */\ + { 0x2800, "flag_cfma_err_int_enable"}, /* flag_cfma_err_int_enable , */\ + { 0x2810, "flag_cfma_ack_int_enable"}, /* flag_cfma_ack_int_enable , */\ + { 0x2900, "flag_por_int_pol"}, /* flag_por_int_pol , */\ + { 0x2910, "flag_pll_lock_int_pol"}, /* flag_pll_lock_int_pol , */\ + { 0x2920, "flag_otpok_int_pol"}, /* flag_otpok_int_pol , */\ + { 0x2930, "flag_ovpok_int_pol"}, /* flag_ovpok_int_pol , */\ + { 0x2940, "flag_uvpok_int_pol"}, /* flag_uvpok_int_pol , */\ + { 0x2950, "flag_ocp_alarm_int_pol"}, /* flag_ocp_alarm_int_pol , */\ + { 0x2960, "flag_clocks_stable_int_pol"}, /* flag_clocks_stable_int_pol , */\ + { 0x2970, "flag_clip_int_pol"}, /* flag_clip_int_pol , */\ + { 0x2980, "mtp_busy_int_pol"}, /* mtp_busy_int_pol , */\ + { 0x2990, "flag_lost_clk_int_pol"}, /* flag_lost_clk_int_pol , */\ + { 0x29a0, "flag_cf_speakererror_int_pol"}, /* flag_cf_speakererror_int_pol , */\ + { 0x29b0, "flag_cold_started_int_pol"}, /* flag_cold_started_int_pol , */\ + { 0x29c0, "flag_engage_int_pol"}, /* flag_engage_int_pol , */\ + { 0x29d0, "flag_watchdog_reset_int_pol"}, /* flag_watchdog_reset_int_pol , */\ + { 0x29e0, "flag_enbl_amp_int_pol"}, /* flag_enbl_amp_int_pol , */\ + { 0x29f0, "flag_enbl_ref_int_pol"}, /* flag_enbl_ref_int_pol , */\ + { 0x2a00, "flag_voutcomp_int_pol"}, /* flag_voutcomp_int_pol , */\ + { 0x2a10, "flag_voutcomp93_int_pol"}, /* flag_voutcomp93_int_pol , */\ + { 0x2a20, "flag_voutcomp86_int_pol"}, /* flag_voutcomp86_int_pol , */\ + { 0x2a30, "flag_hiz_int_pol"}, /* flag_hiz_int_pol , */\ + { 0x2a40, "flag_ocpokbst_int_pol"}, /* flag_ocpokbst_int_pol , */\ + { 0x2a50, "flag_peakcur_int_pol"}, /* flag_peakcur_int_pol , */\ + { 0x2a60, "flag_ocpokap_int_pol"}, /* flag_ocpokap_int_pol , */\ + { 0x2a70, "flag_ocpokan_int_pol"}, /* flag_ocpokan_int_pol , */\ + { 0x2a80, "flag_ocpokbp_int_pol"}, /* flag_ocpokbp_int_pol , */\ + { 0x2a90, "flag_ocpokbn_int_pol"}, /* flag_ocpokbn_int_pol , */\ + { 0x2aa0, "flag_adc10_ready_int_pol"}, /* flag_adc10_ready_int_pol , */\ + { 0x2ab0, "flag_clipa_high_int_pol"}, /* flag_clipa_high_int_pol , */\ + { 0x2ac0, "flag_clipa_low_int_pol"}, /* flag_clipa_low_int_pol , */\ + { 0x2ad0, "flag_clipb_high_int_pol"}, /* flag_clipb_high_int_pol , */\ + { 0x2ae0, "flag_clipb_low_int_pol"}, /* flag_clipb_low_int_pol , */\ + { 0x2af0, "flag_tdm_error_int_pol"}, /* flag_tdm_error_int_pol , */\ + { 0x2b00, "flag_cfma_err_int_pol"}, /* flag_cfma_err_int_pol , */\ + { 0x2b10, "flag_cfma_ack_int_pol"}, /* flag_cfma_ack_int_pol , */\ + { 0x3000, "flag_voutcomp"}, /* Status flag_voutcomp, indication Vset is larger than Vbat, */\ + { 0x3010, "flag_voutcomp93"}, /* Status flag_voutcomp93, indication Vset is larger than 1.07 x Vbat, */\ + { 0x3020, "flag_voutcomp86"}, /* Status flag voutcomp86, indication Vset is larger than 1.14 x Vbat, */\ + { 0x3030, "flag_hiz"}, /* Status flag_hiz, indication Vbst is larger than Vbat, */\ + { 0x3040, "flag_ocpokbst"}, /* Status flag_ocpokbst, indication no over current in boost converter PMOS switch, */\ + { 0x3050, "flag_peakcur"}, /* Status flag_peakcur, indication current is max in dcdc converter, */\ + { 0x3060, "flag_ocpokap"}, /* Status flag_ocpokap, indication no over current in amplifier A PMOS output stage, */\ + { 0x3070, "flag_ocpokan"}, /* Status flag_ocpokan, indication no over current in amplifier A NMOS output stage, */\ + { 0x3080, "flag_ocpokbp"}, /* Status flag_ocpokbp, indication no over current in amplifier B PMOS output stage, */\ + { 0x3090, "flag_ocpokbn"}, /* Status flag_ocpokbn, indication no over current in amplifier B NMOS output stage, */\ + { 0x30a0, "flag_adc10_ready"}, /* Status flag_adc10_ready, indication adc10 is ready, */\ + { 0x30b0, "flag_clipa_high"}, /* Status flag_clipa_high, indication pmos amplifier A is clipping, */\ + { 0x30c0, "flag_clipa_low"}, /* Status flag_clipa_low, indication nmos amplifier A is clipping, */\ + { 0x30d0, "flag_clipb_high"}, /* Status flag_clipb_high, indication pmos amplifier B is clipping, */\ + { 0x30e0, "flag_clipb_low"}, /* Status flag_clipb_low, indication nmos amplifier B is clipping, */\ + { 0x310f, "mtp_man_data_out"}, /* MTP manual read out data , */\ + { 0x3200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0x3210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0x3225, "mtp_ecc_tcout"}, /* MTP error correction test data out , */\ + { 0x3280, "mtpctrl_valid_test_rd"}, /* MTP test readout for read , */\ + { 0x3290, "mtpctrl_valid_test_wr"}, /* MTP test readout for write , */\ + { 0x32a0, "flag_in_alarm_state"}, /* Flag alarm state , */\ + { 0x32b0, "mtp_ecc_err2"}, /* Two or more bit errors detected in MTP, can not reconstruct value, */\ + { 0x32c0, "mtp_ecc_err1"}, /* One bit error detected in MTP, reconstructed value, */\ + { 0x32d0, "mtp_mtp_hvf"}, /* High voltage ready flag for MTP , */\ + { 0x32f0, "mtp_zero_check_fail"}, /* Zero check failed for MTP , */\ + { 0x3309, "data_adc10_tempbat"}, /* ADC10 data output for testing battery voltage and temperature, */\ + { 0x400f, "hid_code"}, /* 5A6Bh, 23147d to access hidden registers (default for engineering), */\ + { 0x4100, "bypass_hp"}, /* Bypass High Pass Filter , */\ + { 0x4110, "hard_mute"}, /* Hard Mute , */\ + { 0x4120, "soft_mute"}, /* Soft Mute , */\ + { 0x4134, "pwm_delay"}, /* PWM delay setting , */\ + { 0x4180, "pwm_shape"}, /* PWM Shape , */\ + { 0x4190, "pwm_bitlength"}, /* PWM Bitlength in noise shaper , */\ + { 0x4203, "drive"}, /* Drive bits to select number of amplifier power stages, */\ + { 0x4240, "reclock_pwm"}, /* Control for enabling reclocking of PWM signal , */\ + { 0x4250, "reclock_voltsense"}, /* Control for enabling reclocking of voltage sense signal, */\ + { 0x4281, "dpsalevel"}, /* DPSA threshold level , */\ + { 0x42a1, "dpsa_release"}, /* DPSA release time , */\ + { 0x42c0, "coincidence"}, /* Prevent simultaneously switching of output stage , */\ + { 0x42d0, "kickback"}, /* Prevent double pulses of output stage , */\ + { 0x4306, "drivebst"}, /* Drive bits to select the power transistor sections boost converter, */\ + { 0x4370, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x4381, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x43a0, "ocptestbst"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0); For new ocp (ctrl_reversebst is 1), */\ + { 0x43d0, "test_abistfft_enbl"}, /* FFT Coolflux , */\ + { 0x43e0, "bst_dcmbst"}, /* DCM mode control for DCDC during I2C direct control mode, */\ + { 0x43f0, "test_bcontrol"}, /* test_bcontrol , */\ + { 0x4400, "reversebst"}, /* OverCurrent Protection selection of power stage boost converter, */\ + { 0x4410, "sensetest"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0x4420, "enbl_engagebst"}, /* Enable power stage of dcdc controller , */\ + { 0x4470, "enbl_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x4480, "enbl_voutcomp"}, /* Enable vout comparators , */\ + { 0x4490, "enbl_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x44a0, "enbl_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x44b0, "enbl_hizcom"}, /* Enable hiz comparator , */\ + { 0x44c0, "enbl_peakcur"}, /* Enable peak current , */\ + { 0x44d0, "bypass_ovpglitch"}, /* Bypass OVP Glitch Filter , */\ + { 0x44e0, "enbl_windac"}, /* Enable window dac , */\ + { 0x44f0, "enbl_powerbst"}, /* Enable line of the powerstage , */\ + { 0x4507, "ocp_thr"}, /* OCP threshold level , */\ + { 0x4580, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0x4590, "bypass_ovp"}, /* Bypass OVP , */\ + { 0x45a0, "bypass_uvp"}, /* Bypass UVP , */\ + { 0x45b0, "bypass_otp"}, /* Bypass OTP , */\ + { 0x45d0, "bypass_ocpcounter"}, /* Bypass OCP counter , */\ + { 0x45e0, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0x45f0, "vpalarm"}, /* vpalarm (UVP/OUP handling) , */\ + { 0x4600, "bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x4610, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x4627, "cs_gain"}, /* Current sense gain , */\ + { 0x46a0, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x46b0, "bypass_pwmcounter"}, /* Bypass PWM Counter , */\ + { 0x46c0, "cs_negfixed"}, /* Current sense does not switch to neg , */\ + { 0x46d2, "cs_neghyst"}, /* Current sense switches to neg depending on hyseteris level, */\ + { 0x4700, "switch_fb"}, /* Current sense control switch_fb , */\ + { 0x4713, "se_hyst"}, /* Current sense control se_hyst , */\ + { 0x4754, "se_level"}, /* Current sense control se_level , */\ + { 0x47a5, "ktemp"}, /* Current sense control temperature compensation trimming, */\ + { 0x4800, "cs_negin"}, /* Current sense control negin , */\ + { 0x4810, "cs_sein"}, /* Current sense control cs_sein , */\ + { 0x4820, "cs_coincidence"}, /* Coincidence current sense , */\ + { 0x4830, "iddqtestbst"}, /* IDDQ testing in powerstage of DCDC boost converter, */\ + { 0x4840, "coincidencebst"}, /* Switch protection on to prevent simultaneously switching power stages bst and amp, */\ + { 0x4876, "delay_se_neg"}, /* delay of se and neg , */\ + { 0x48e1, "cs_ttrack"}, /* Sample and hold track time , */\ + { 0x4900, "bypass_clip"}, /* Bypass clip control , */\ + { 0x4920, "cf_cgate_off"}, /* Disable clock gating in the coolflux , */\ + { 0x4940, "clipfast"}, /* Clock selection for HW clipper for battery safeguard, */\ + { 0x4950, "cs_8ohm"}, /* 8 ohm mode for current sense (gain mode) , */\ + { 0x4974, "delay_clock_sh"}, /* delay_sh, tunes S7H delay , */\ + { 0x49c0, "inv_clksh"}, /* Invert the sample/hold clock for current sense ADC, */\ + { 0x49d0, "inv_neg"}, /* Invert neg signal , */\ + { 0x49e0, "inv_se"}, /* Invert se signal , */\ + { 0x49f0, "setse"}, /* Switches between Single Ended and differential mode; 1 is single ended, */\ + { 0x4a12, "adc10_sel"}, /* Select the input to convert the 10b ADC , */\ + { 0x4a60, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0x4a81, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0x4aa0, "bypass_lp_vbat"}, /* LP filter in batt sensor , */\ + { 0x4ae0, "dc_offset"}, /* Current sense decimator offset control , */\ + { 0x4af0, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0x4b00, "adc13_iset"}, /* MICADC setting of current consumption (debug use only), */\ + { 0x4b14, "adc13_gain"}, /* MICADC gain setting (two's complement format) , */\ + { 0x4b61, "adc13_slowdel"}, /* MICADC delay setting for internal clock (debug use only), */\ + { 0x4b83, "adc13_offset"}, /* MICADC offset setting , */\ + { 0x4bc0, "adc13_bsoinv"}, /* MICADC bit stream output invert mode for test , */\ + { 0x4bd0, "adc13_resonator_enable"}, /* MICADC give extra SNR with less stability (debug use only), */\ + { 0x4be0, "testmicadc"}, /* Mux at input of MICADC for test purpose , */\ + { 0x4c0f, "abist_offset"}, /* Offset control for ABIST testing , */\ + { 0x4d05, "windac"}, /* For testing direct control windac , */\ + { 0x4dc3, "pwm_dcc_cnt"}, /* control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0x4e04, "slopecur"}, /* For testing direct control slopecur , */\ + { 0x4e50, "ctrl_dem"}, /* Dynamic element matching control, rest of codes are optional, */\ + { 0x4ed0, "enbl_pwm_dcc"}, /* Enable direct control of pwm duty cycle , */\ + { 0x4f00, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x4f10, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x4f20, "bst_ctrl_azbst"}, /* Control of auto-zeroing of zero current comparator, */\ + { 0x5007, "gain"}, /* Gain setting of the gain multiplier , */\ + { 0x5081, "sourceb"}, /* PWM OUTB selection control , */\ + { 0x50a1, "sourcea"}, /* PWM OUTA selection control , */\ + { 0x50c1, "sourcebst"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0x50e0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0x5104, "pulselengthbst"}, /* Pulse length setting test input for boost converter, */\ + { 0x5150, "bypasslatchbst"}, /* Bypass latch in boost converter , */\ + { 0x5160, "invertbst"}, /* Invert pwmbst test signal , */\ + { 0x5174, "pulselength"}, /* Pulse length setting test input for amplifier , */\ + { 0x51c0, "bypasslatch"}, /* Bypass latch in PWM source selection module , */\ + { 0x51d0, "invertb"}, /* invert pwmb test signal , */\ + { 0x51e0, "inverta"}, /* invert pwma test signal , */\ + { 0x51f0, "bypass_ctrlloop"}, /* bypass_ctrlloop bypasses the control loop of the amplifier, */\ + { 0x5210, "test_rdsona"}, /* tbd for rdson testing , */\ + { 0x5220, "test_rdsonb"}, /* tbd for rdson testing , */\ + { 0x5230, "test_rdsonbst"}, /* tbd for rdson testing , */\ + { 0x5240, "test_cvia"}, /* tbd for rdson testing , */\ + { 0x5250, "test_cvib"}, /* tbd for rdson testing , */\ + { 0x5260, "test_cvibst"}, /* tbd for rdson testing , */\ + { 0x5306, "digimuxa_sel"}, /* DigimuxA input selection control (see Digimux list for details), */\ + { 0x5376, "digimuxb_sel"}, /* DigimuxB input selection control (see Digimux list for details), */\ + { 0x5400, "hs_mode"}, /* I2C high speed mode selection control , */\ + { 0x5412, "test_parametric_io"}, /* Control for parametric tests of IO cells , */\ + { 0x5440, "enbl_ringo"}, /* Enable ring oscillator control, for test purpose to check with ringo, */\ + { 0x5456, "digimuxc_sel"}, /* DigimuxC input selection control (see Digimux list for details), */\ + { 0x54c0, "dio_ehs"}, /* Slew control for DIO in output mode , */\ + { 0x54d0, "gainio_ehs"}, /* Slew control for GAINIO in output mode , */\ + { 0x550d, "enbl_amp"}, /* enbl_amp for testing to enable all analoge blocks in amplifier, */\ + { 0x5600, "use_direct_ctrls"}, /* Use direct controls to overrule several functions for testing - I2C direct control mode, */\ + { 0x5610, "rst_datapath"}, /* Reset datapath during direct control mode , */\ + { 0x5620, "rst_cgu"}, /* Reset CGU during durect control mode , */\ + { 0x5637, "enbl_ref"}, /* For testing to enable all analoge blocks in references, */\ + { 0x56b0, "enbl_engage"}, /* Enable output stage amplifier , */\ + { 0x56c0, "use_direct_clk_ctrl"}, /* use_direct_clk_ctrl, to overrule several functions direct for testing, */\ + { 0x56d0, "use_direct_pll_ctrl"}, /* use_direct_pll_ctrl, to overrule several functions direct for testing, */\ + { 0x5707, "anamux"}, /* Anamux control , */\ + { 0x57e0, "otptest"}, /* otptest, test mode otp amplifier , */\ + { 0x57f0, "reverse"}, /* 1b = Normal mode, slope is controlled , */\ + { 0x5813, "pll_selr"}, /* PLL pll_selr , */\ + { 0x5854, "pll_selp"}, /* PLL pll_selp , */\ + { 0x58a5, "pll_seli"}, /* PLL pll_seli , */\ + { 0x5950, "pll_mdec_msb"}, /* Most significant bits of pll_mdec[16] , */\ + { 0x5960, "pll_ndec_msb"}, /* Most significant bits of pll_ndec[9] , */\ + { 0x5970, "pll_frm"}, /* PLL pll_frm , */\ + { 0x5980, "pll_directi"}, /* PLL pll_directi , */\ + { 0x5990, "pll_directo"}, /* PLL pll_directo , */\ + { 0x59a0, "enbl_pll"}, /* PLL enbl_pll , */\ + { 0x59f0, "pll_bypass"}, /* PLL bypass , */\ + { 0x5a0f, "tsig_freq"}, /* Internal sinus test generator frequency control LSB bits, */\ + { 0x5b02, "tsig_freq_msb"}, /* Select internal sine wave generator, frequency control MSB bits, */\ + { 0x5b30, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0x5b44, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0x5c0f, "pll_mdec"}, /* PLL MDEC - I2C direct PLL control mode only , */\ + { 0x5d06, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0x5d78, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0x6007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0x6185, "mtp_ecc_tcin"}, /* MTP ECC TCIN data , */\ + { 0x6203, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0x6260, "mtp_ecc_eeb"}, /* Enable code bit generation (active low!) , */\ + { 0x6270, "mtp_ecc_ecb"}, /* Enable correction signal (active low!) , */\ + { 0x6280, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ + { 0x6290, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ + { 0x62a0, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0x62b0, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0x62d2, "mtp_speed_mode"}, /* MTP speed mode , */\ + { 0x6340, "mtp_direct_enable"}, /* mtp_direct_enable , */\ + { 0x6350, "mtp_direct_wr"}, /* mtp_direct_wr , */\ + { 0x6360, "mtp_direct_rd"}, /* mtp_direct_rd , */\ + { 0x6370, "mtp_direct_rst"}, /* mtp_direct_rst , */\ + { 0x6380, "mtp_direct_ers"}, /* mtp_direct_ers , */\ + { 0x6390, "mtp_direct_prg"}, /* mtp_direct_prg , */\ + { 0x63a0, "mtp_direct_epp"}, /* mtp_direct_epp , */\ + { 0x63b4, "mtp_direct_test"}, /* mtp_direct_test , */\ + { 0x640f, "mtp_man_data_in"}, /* Write data for MTP manual write , */\ + { 0x7000, "cf_rst_dsp"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "cf_dmem"}, /* Target memory for access , */\ + { 0x7030, "cf_aif"}, /* Auto increment flag for memory-address , */\ + { 0x7040, "cf_int"}, /* CF Interrupt - auto clear , */\ + { 0x7087, "cf_req"}, /* CF request for accessing the 8 channels , */\ + { 0x710f, "cf_madd"}, /* Memory address , */\ + { 0x720f, "cf_mema"}, /* Activate memory access , */\ + { 0x7307, "cf_err"}, /* CF error flags , */\ + { 0x7387, "cf_ack"}, /* CF acknowledgement of the requests channels , */\ + { 0x8000, "calibration_onetime"}, /* Calibration schedule selection , */\ + { 0x8010, "calibr_ron_done"}, /* Calibration of RON status bit , */\ + { 0x8105, "calibr_vout_offset"}, /* calibr_vout_offset (DCDCoffset) 2's compliment (key1 protected), */\ + { 0x8163, "calibr_delta_gain"}, /* delta gain for vamp (alpha) 2's compliment (key1 protected), */\ + { 0x81a5, "calibr_offs_amp"}, /* offset for vamp (Ampoffset) 2's compliment (key1 protected), */\ + { 0x8207, "calibr_gain_cs"}, /* gain current sense (Imeasalpha) 2's compliment (key1 protected), */\ + { 0x8284, "calibr_temp_offset"}, /* temperature offset 2's compliment (key1 protected), */\ + { 0x82d2, "calibr_temp_gain"}, /* temperature gain 2's compliment (key1 protected) , */\ + { 0x830f, "calibr_ron"}, /* calibration value of the RON resistance of the coil, */\ + { 0x8505, "type_bits_hw"}, /* bit0 = disable function dcdcoff_mode ($09[7]) , */\ + { 0x8601, "type_bits_1_0_sw"}, /* MTP control SW , */\ + { 0x8681, "type_bits_9_8_sw"}, /* MTP control SW , */\ + { 0x870f, "type_bits2_sw"}, /* MTP-control SW2 , */\ + { 0x8806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0x8870, "htol_iic_addr_en"}, /* HTOL I2C_Address_Enable , */\ + { 0x8881, "ctrl_ovp_response"}, /* OVP response control , */\ + { 0x88a0, "disable_ovp_alarm_state"}, /* OVP alarm state control , */\ + { 0x88b0, "enbl_stretch_ovp"}, /* OVP alram strech control , */\ + { 0x88c0, "cf_debug_mode"}, /* Coolflux debug mode , */\ + { 0x8a0f, "production_data1"}, /* production_data1 , */\ + { 0x8b0f, "production_data2"}, /* production_data2 , */\ + { 0x8c0f, "production_data3"}, /* production_data3 , */\ + { 0x8d0f, "production_data4"}, /* production_data4 , */\ + { 0x8e0f, "production_data5"}, /* production_data5 , */\ + { 0x8f0f, "production_data6"}, /* production_data6 , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum TFA9896_irq { + TFA9896_irq_vdds = 0, + TFA9896_irq_plls = 1, + TFA9896_irq_ds = 2, + TFA9896_irq_vds = 3, + TFA9896_irq_uvds = 4, + TFA9896_irq_cds = 5, + TFA9896_irq_clks = 6, + TFA9896_irq_clips = 7, + TFA9896_irq_mtpb = 8, + TFA9896_irq_clk = 9, + TFA9896_irq_spks = 10, + TFA9896_irq_acs = 11, + TFA9896_irq_sws = 12, + TFA9896_irq_wds = 13, + TFA9896_irq_amps = 14, + TFA9896_irq_arefs = 15, + TFA9896_irq_err = 32, + TFA9896_irq_ack = 33, + TFA9896_irq_max = 34, + TFA9896_irq_all = -1 /* all irqs */}; + +#define TFA9896_IRQ_NAMETABLE static tfaIrqName_t TFA9896IrqNames[] = {\ + { 0, "VDDS"},\ + { 1, "PLLS"},\ + { 2, "DS"},\ + { 3, "VDS"},\ + { 4, "UVDS"},\ + { 5, "CDS"},\ + { 6, "CLKS"},\ + { 7, "CLIPS"},\ + { 8, "MTPB"},\ + { 9, "CLK"},\ + { 10, "SPKS"},\ + { 11, "ACS"},\ + { 12, "SWS"},\ + { 13, "WDS"},\ + { 14, "AMPS"},\ + { 15, "AREFS"},\ + { 16, "16"},\ + { 17, "17"},\ + { 18, "18"},\ + { 19, "19"},\ + { 20, "20"},\ + { 21, "21"},\ + { 22, "22"},\ + { 23, "23"},\ + { 24, "24"},\ + { 25, "25"},\ + { 26, "26"},\ + { 27, "27"},\ + { 28, "28"},\ + { 29, "29"},\ + { 30, "30"},\ + { 31, "31"},\ + { 32, "ERR"},\ + { 33, "ACK"},\ + { 34, "34"},\ +}; +#endif /* _TFA9896_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa98xx.c b/sound/soc/codecs/tfa98xx.c new file mode 100644 index 000000000000..03af4cc018b9 --- /dev/null +++ b/sound/soc/codecs/tfa98xx.c @@ -0,0 +1,3278 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ +#define pr_fmt(fmt) "%s(): " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "tfa98xx.h" +#include "tfa.h" + + /* required for enum tfa9912_irq */ +#include "tfa98xx_tfafieldnames.h" + +#define TFA98XX_VERSION TFA98XX_API_REV_STR + +#define I2C_RETRIES 50 +#define I2C_RETRY_DELAY 5 /* ms */ +#define ERR -1 + +/* Change volume selection behavior: + * Uncomment following line to generate a profile change when updating + * a volume control (also changes to the profile of the modified volume + * control) + */ + /*#define TFA98XX_ALSA_CTRL_PROF_CHG_ON_VOL 1 + */ + + /* Supported rates and data formats */ +#define TFA98XX_RATES SNDRV_PCM_RATE_8000_48000 +#define TFA98XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +#define TF98XX_MAX_DSP_START_TRY_COUNT 10 + +/* data accessible by all instances */ +/* Memory pool used for DSP messages */ +static struct kmem_cache *tfa98xx_cache; +/* Mutex protected data */ +static DEFINE_MUTEX(tfa98xx_mutex); +static LIST_HEAD(tfa98xx_device_list); +static int tfa98xx_device_count; +static int tfa98xx_sync_count; +static LIST_HEAD(profile_list); /* list of user selectable profiles */ +static int tfa98xx_mixer_profiles; /* number of user selectable profiles */ +static int tfa98xx_mixer_profile; /* current mixer profile */ +static struct snd_kcontrol_new *tfa98xx_controls; +static nxpTfaContainer_t *tfa98xx_container; + +static int tfa98xx_kmsg_regs; +static int tfa98xx_ftrace_regs; + +static char *fw_name = "tfa98xx.cnt"; +module_param(fw_name, charp, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(fw_name, "TFA98xx DSP firmware (container file) name."); + +static int trace_level; +module_param(trace_level, int, S_IRUGO); +MODULE_PARM_DESC(trace_level, "TFA98xx debug trace level (0=off, bits:1=verbose,2=regdmesg,3=regftrace,4=timing)."); + +static char *dflt_prof_name = ""; +module_param(dflt_prof_name, charp, S_IRUGO); + +static int no_start; +module_param(no_start, int, S_IRUGO); +MODULE_PARM_DESC(no_start, "do not start the work queue; for debugging via user\n"); + +static int no_reset; +module_param(no_reset, int, S_IRUGO); +MODULE_PARM_DESC(no_reset, "do not use the reset line; for debugging via user\n"); + +static int pcm_sample_format; +module_param(pcm_sample_format, int, S_IRUGO); +MODULE_PARM_DESC(pcm_sample_format, "PCM sample format: 0=S16_LE, 1=S24_LE, 2=S32_LE\n"); + +static int pcm_no_constraint; +module_param(pcm_no_constraint, int, S_IRUGO); +MODULE_PARM_DESC(pcm_no_constraint, "do not use constraints for PCM parameters\n"); + +static void tfa98xx_tapdet_check_update(struct tfa98xx *tfa98xx); +static int tfa98xx_get_fssel(unsigned int rate); +static void tfa98xx_interrupt_enable(struct tfa98xx *tfa98xx, bool enable); + +static int get_profile_from_list(char *buf, int id); +static int get_profile_id_for_sr(int id, unsigned int rate); + +struct tfa98xx_rate { + unsigned int rate; + unsigned int fssel; +}; + +static const struct tfa98xx_rate rate_to_fssel[] = { + { 8000, 0 }, + { 11025, 1 }, + { 12000, 2 }, + { 16000, 3 }, + { 22050, 4 }, + { 24000, 5 }, + { 32000, 6 }, + { 44100, 7 }, + { 48000, 8 }, +}; + + +static inline char *tfa_cont_profile_name(struct tfa98xx *tfa98xx, + int prof_idx) +{ + if (tfa98xx->tfa->cnt == NULL) + return NULL; + return tfaContProfileName(tfa98xx->tfa->cnt, + tfa98xx->tfa->dev_idx, prof_idx); +} + +static enum tfa_error tfa98xx_write_re25(struct tfa_device *tfa, int value) +{ + enum tfa_error err; + + /* clear MTPEX */ + err = tfa_dev_mtp_set(tfa, TFA_MTP_EX, 0); + if (err == tfa_error_ok) { + /* set RE25 in shadow regiser */ + err = tfa_dev_mtp_set(tfa, TFA_MTP_RE25_PRIM, value); + } + if (err == tfa_error_ok) { + /* set MTPEX to copy RE25 into MTP */ + err = tfa_dev_mtp_set(tfa, TFA_MTP_EX, 2); + } + + return err; +} + +/* Wrapper for tfa start */ +static enum tfa_error tfa98xx_tfa_start(struct tfa98xx *tfa98xx, + int next_profile, int vstep) +{ + enum tfa_error err; + ktime_t start_time, stop_time; + u64 delta_time; + + if (trace_level & 8) + start_time = ktime_get_boottime(); + + err = tfa_dev_start(tfa98xx->tfa, next_profile, vstep); + + if (trace_level & 8) { + stop_time = ktime_get_boottime(); + delta_time = ktime_to_ns(ktime_sub(stop_time, start_time)); + do_div(delta_time, 1000); + dev_dbg(&tfa98xx->i2c->dev, "tfa_dev_start(%d,%d) time = %lld us\n", + next_profile, vstep, delta_time); + } + + if ((err == tfa_error_ok) && (tfa98xx->set_mtp_cal)) { + enum tfa_error err_cal; + + err_cal = tfa98xx_write_re25(tfa98xx->tfa, tfa98xx->cal_data); + if (err_cal != tfa_error_ok) { + pr_err("Error, setting calibration value in mtp, err=%d\n", + err_cal); + } else { + tfa98xx->set_mtp_cal = false; + pr_info("Calibration value (%d) set in mtp\n", + tfa98xx->cal_data); + } + } + + /* Check and update tap-detection state (in case of profile change) */ + tfa98xx_tapdet_check_update(tfa98xx); + + /* Remove sticky bit by reading it once */ + tfa_get_noclk(tfa98xx->tfa); + + /* A cold start erases the configuration, including interrupts setting. + * Restore it if required + */ + tfa98xx_interrupt_enable(tfa98xx, true); + + return err; +} + +static int tfa98xx_input_open(struct input_dev *dev) +{ + struct tfa98xx *tfa98xx = input_get_drvdata(dev); + + dev_dbg(tfa98xx->codec->dev, "opening device file\n"); + + /* note: open function is called only once by the framework. + * No need to count number of open file instances. + */ + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) { + dev_dbg(&tfa98xx->i2c->dev, + "DSP not loaded, cannot start tap-detection\n"); + return -EIO; + } + + /* enable tap-detection service */ + tfa98xx->tapdet_open = true; + tfa98xx_tapdet_check_update(tfa98xx); + + return 0; +} + +static void tfa98xx_input_close(struct input_dev *dev) +{ + struct tfa98xx *tfa98xx = input_get_drvdata(dev); + + dev_dbg(tfa98xx->codec->dev, "closing device file\n"); + + /* Note: close function is called if the device is unregistered */ + + /* disable tap-detection service */ + tfa98xx->tapdet_open = false; + tfa98xx_tapdet_check_update(tfa98xx); +} + +static int tfa98xx_register_inputdev(struct tfa98xx *tfa98xx) +{ + int err; + struct input_dev *input; + input = input_allocate_device(); + + if (!input) { + dev_err(tfa98xx->codec->dev, "Unable to allocate input device\n"); + return -ENOMEM; + } + + input->evbit[0] = BIT_MASK(EV_KEY); + input->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); + input->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); + input->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); + input->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); + input->keybit[BIT_WORD(BTN_4)] |= BIT_MASK(BTN_4); + input->keybit[BIT_WORD(BTN_5)] |= BIT_MASK(BTN_5); + input->keybit[BIT_WORD(BTN_6)] |= BIT_MASK(BTN_6); + input->keybit[BIT_WORD(BTN_7)] |= BIT_MASK(BTN_7); + input->keybit[BIT_WORD(BTN_8)] |= BIT_MASK(BTN_8); + input->keybit[BIT_WORD(BTN_9)] |= BIT_MASK(BTN_9); + + input->open = tfa98xx_input_open; + input->close = tfa98xx_input_close; + + input->name = "tfa98xx-tapdetect"; + + input->id.bustype = BUS_I2C; + input_set_drvdata(input, tfa98xx); + + err = input_register_device(input); + if (err) { + dev_err(tfa98xx->codec->dev, "Unable to register input device\n"); + goto err_free_dev; + } + + dev_dbg(tfa98xx->codec->dev, "Input device for tap-detection registered: %s\n", + input->name); + tfa98xx->input = input; + return 0; + +err_free_dev: + input_free_device(input); + return err; +} + +/* + * Check if an input device for tap-detection can and shall be registered. + * Register it if appropriate. + * If already registered, check if still relevant and remove it if necessary. + * unregister: true to request inputdev unregistration. + */ +static void __tfa98xx_inputdev_check_register(struct tfa98xx *tfa98xx, bool unregister) +{ + bool tap_profile = false; + unsigned int i; + for (i = 0; i < tfa_cnt_get_dev_nprof(tfa98xx->tfa); i++) { + if (strstr(tfa_cont_profile_name(tfa98xx, i), ".tap")) { + tap_profile = true; + tfa98xx->tapdet_profiles |= 1 << i; + dev_info(tfa98xx->codec->dev, + "found a tap-detection profile (%d - %s)\n", + i, tfa_cont_profile_name(tfa98xx, i)); + } + } + + /* Check for device support: + * - at device level + * - at container (profile) level + */ + if (!(tfa98xx->flags & TFA98XX_FLAG_TAPDET_AVAILABLE) || + !tap_profile || + unregister) { + /* No input device supported or required */ + if (tfa98xx->input) { + input_unregister_device(tfa98xx->input); + tfa98xx->input = NULL; + } + return; + } + + /* input device required */ + if (tfa98xx->input) + dev_info(tfa98xx->codec->dev, "Input device already registered, skipping\n"); + else + tfa98xx_register_inputdev(tfa98xx); +} + +static void tfa98xx_inputdev_check_register(struct tfa98xx *tfa98xx) +{ + __tfa98xx_inputdev_check_register(tfa98xx, false); +} + +static void tfa98xx_inputdev_unregister(struct tfa98xx *tfa98xx) +{ + __tfa98xx_inputdev_check_register(tfa98xx, true); +} + +#ifdef CONFIG_DEBUG_FS +/* OTC reporting + * Returns the MTP0 OTC bit value + */ +static int tfa98xx_dbgfs_otc_get(void *data, u64 *val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + int value; + + mutex_lock(&tfa98xx->dsp_lock); + value = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_OTC); + mutex_unlock(&tfa98xx->dsp_lock); + + if (value < 0) { + pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, value); + return -EIO; + } + + *val = value; + pr_debug("[0x%x] OTC : %d\n", tfa98xx->i2c->addr, value); + + return 0; +} + +static int tfa98xx_dbgfs_otc_set(void *data, u64 val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + enum tfa_error err; + + if (val != 0 && val != 1) { + pr_err("[0x%x] Unexpected value %llu\n", tfa98xx->i2c->addr, val); + return -EINVAL; + } + + mutex_lock(&tfa98xx->dsp_lock); + err = tfa_dev_mtp_set(tfa98xx->tfa, TFA_MTP_OTC, val); + mutex_unlock(&tfa98xx->dsp_lock); + + if (err != tfa_error_ok) { + pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, err); + return -EIO; + } + + pr_debug("[0x%x] OTC < %llu\n", tfa98xx->i2c->addr, val); + + return 0; +} + +static int tfa98xx_dbgfs_mtpex_get(void *data, u64 *val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + int value; + + mutex_lock(&tfa98xx->dsp_lock); + value = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_EX); + mutex_unlock(&tfa98xx->dsp_lock); + + if (value < 0) { + pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, value); + return -EIO; + } + + + *val = value; + pr_debug("[0x%x] MTPEX : %d\n", tfa98xx->i2c->addr, value); + + return 0; +} + +static int tfa98xx_dbgfs_mtpex_set(void *data, u64 val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + enum tfa_error err; + + if (val != 0) { + pr_err("[0x%x] Can only clear MTPEX (0 value expected)\n", tfa98xx->i2c->addr); + return -EINVAL; + } + + mutex_lock(&tfa98xx->dsp_lock); + err = tfa_dev_mtp_set(tfa98xx->tfa, TFA_MTP_EX, val); + mutex_unlock(&tfa98xx->dsp_lock); + + if (err != tfa_error_ok) { + pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, err); + return -EIO; + } + + pr_debug("[0x%x] MTPEX < 0\n", tfa98xx->i2c->addr); + + return 0; +} + +static int tfa98xx_dbgfs_temp_get(void *data, u64 *val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + + mutex_lock(&tfa98xx->dsp_lock); + *val = tfa98xx_get_exttemp(tfa98xx->tfa); + mutex_unlock(&tfa98xx->dsp_lock); + + pr_debug("[0x%x] TEMP : %llu\n", tfa98xx->i2c->addr, *val); + + return 0; +} + +static int tfa98xx_dbgfs_temp_set(void *data, u64 val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + + mutex_lock(&tfa98xx->dsp_lock); + tfa98xx_set_exttemp(tfa98xx->tfa, (short)val); + mutex_unlock(&tfa98xx->dsp_lock); + + pr_debug("[0x%x] TEMP < %llu\n", tfa98xx->i2c->addr, val); + + return 0; +} + +static ssize_t tfa98xx_dbgfs_start_set(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + enum tfa_error ret; + char buf[32]; + const char ref[] = "please calibrate now"; + int buf_size, cal_profile = 0; + + /* check string length, and account for eol */ + if (count > sizeof(ref) + 1 || count < (sizeof(ref) - 1)) + return -EINVAL; + + buf_size = min(count, (size_t)(sizeof(buf) - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + /* Compare string, excluding the trailing \0 and the potentials eol */ + if (strncmp(buf, ref, sizeof(ref) - 1)) + return -EINVAL; + + mutex_lock(&tfa98xx->dsp_lock); + ret = tfa_calibrate(tfa98xx->tfa); + if (ret == tfa_error_ok) { + cal_profile = tfaContGetCalProfile(tfa98xx->tfa); + if (cal_profile < 0) { + pr_warn("[0x%x] Calibration profile not found\n", + tfa98xx->i2c->addr); + } + + ret = tfa98xx_tfa_start(tfa98xx, cal_profile, tfa98xx->vstep); + } + if (ret == tfa_error_ok) + tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE, 0); + mutex_unlock(&tfa98xx->dsp_lock); + + if (ret) { + pr_info("[0x%x] Calibration start failed (%d)\n", tfa98xx->i2c->addr, ret); + return -EIO; + } else { + pr_info("[0x%x] Calibration started\n", tfa98xx->i2c->addr); + } + + return count; +} + +static ssize_t tfa98xx_dbgfs_r_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + char *str; + uint16_t status; + int ret; + + mutex_lock(&tfa98xx->dsp_lock); + + /* Need to ensure DSP is access-able, use mtp read access for this + * purpose + */ + ret = tfa98xx_get_mtp(tfa98xx->tfa, &status); + if (ret) { + ret = -EIO; + pr_err("[0x%x] MTP read failed\n", tfa98xx->i2c->addr); + goto r_c_err; + } + + ret = tfaRunSpeakerCalibration(tfa98xx->tfa); + if (ret) { + ret = -EIO; + pr_err("[0x%x] calibration failed\n", tfa98xx->i2c->addr); + goto r_c_err; + } + + str = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!str) { + ret = -ENOMEM; + pr_err("[0x%x] memory allocation failed\n", tfa98xx->i2c->addr); + goto r_c_err; + } + + if (tfa98xx->tfa->spkr_count > 1) { + ret = snprintf(str, PAGE_SIZE, + "Prim:%d mOhms, Sec:%d mOhms\n", + tfa98xx->tfa->mohm[0], + tfa98xx->tfa->mohm[1]); + } else { + ret = snprintf(str, PAGE_SIZE, + "Prim:%d mOhms\n", + tfa98xx->tfa->mohm[0]); + } + + pr_debug("[0x%x] calib_done: %s", tfa98xx->i2c->addr, str); + + if (ret < 0) + goto r_err; + + ret = simple_read_from_buffer(user_buf, count, ppos, str, ret); + +r_err: + kfree(str); +r_c_err: + mutex_unlock(&tfa98xx->dsp_lock); + return ret; +} + +static ssize_t tfa98xx_dbgfs_version_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + char str[] = TFA98XX_VERSION "\n"; + int ret; + + ret = simple_read_from_buffer(user_buf, count, ppos, str, sizeof(str)); + + return ret; +} + +static ssize_t tfa98xx_dbgfs_dsp_state_get(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + int ret = 0; + char *str; + + switch (tfa98xx->dsp_init) { + case TFA98XX_DSP_INIT_STOPPED: + str = "Stopped\n"; + break; + case TFA98XX_DSP_INIT_RECOVER: + str = "Recover requested\n"; + break; + case TFA98XX_DSP_INIT_FAIL: + str = "Failed init\n"; + break; + case TFA98XX_DSP_INIT_PENDING: + str = "Pending init\n"; + break; + case TFA98XX_DSP_INIT_DONE: + str = "Init complete\n"; + break; + default: + str = "Invalid\n"; + } + + pr_debug("[0x%x] dsp_state : %s\n", tfa98xx->i2c->addr, str); + + ret = simple_read_from_buffer(user_buf, count, ppos, str, strlen(str)); + return ret; +} + +static ssize_t tfa98xx_dbgfs_dsp_state_set(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + enum tfa_error ret; + char buf[32]; + const char start_cmd[] = "start"; + const char stop_cmd[] = "stop"; + const char mon_start_cmd[] = "monitor start"; + const char mon_stop_cmd[] = "monitor stop"; + int buf_size; + + buf_size = min(count, (size_t)(sizeof(buf) - 1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + /* Compare strings, excluding the trailing \0 */ + if (!strncmp(buf, start_cmd, sizeof(start_cmd) - 1)) { + pr_info("[0x%x] Manual triggering of dsp start...\n", tfa98xx->i2c->addr); + mutex_lock(&tfa98xx->dsp_lock); + ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); + mutex_unlock(&tfa98xx->dsp_lock); + pr_debug("[0x%x] tfa_dev_start complete: %d\n", tfa98xx->i2c->addr, ret); + } else if (!strncmp(buf, stop_cmd, sizeof(stop_cmd) - 1)) { + pr_info("[0x%x] Manual triggering of dsp stop...\n", tfa98xx->i2c->addr); + mutex_lock(&tfa98xx->dsp_lock); + ret = tfa_dev_stop(tfa98xx->tfa); + mutex_unlock(&tfa98xx->dsp_lock); + pr_debug("[0x%x] tfa_dev_stop complete: %d\n", tfa98xx->i2c->addr, ret); + } else if (!strncmp(buf, mon_start_cmd, sizeof(mon_start_cmd) - 1)) { + pr_info("[0x%x] Manual start of monitor thread...\n", tfa98xx->i2c->addr); + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->monitor_work, HZ); + } else if (!strncmp(buf, mon_stop_cmd, sizeof(mon_stop_cmd) - 1)) { + pr_info("[0x%x] Manual stop of monitor thread...\n", tfa98xx->i2c->addr); + cancel_delayed_work_sync(&tfa98xx->monitor_work); + } else { + return -EINVAL; + } + + return count; +} + +static ssize_t tfa98xx_dbgfs_fw_state_get(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + char *str; + + switch (tfa98xx->dsp_fw_state) { + case TFA98XX_DSP_FW_NONE: + str = "None\n"; + break; + case TFA98XX_DSP_FW_PENDING: + str = "Pending\n"; + break; + case TFA98XX_DSP_FW_FAIL: + str = "Fail\n"; + break; + case TFA98XX_DSP_FW_OK: + str = "Ok\n"; + break; + default: + str = "Invalid\n"; + } + + pr_debug("[0x%x] fw_state : %s", tfa98xx->i2c->addr, str); + + return simple_read_from_buffer(user_buf, count, ppos, str, strlen(str)); +} + +static ssize_t tfa98xx_dbgfs_rpc_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + int ret = 0; + uint8_t *buffer; + enum Tfa98xx_Error error; + + if (tfa98xx->tfa == NULL) { + pr_debug("[0x%x] dsp is not available\n", tfa98xx->i2c->addr); + return -ENODEV; + } + + if (count == 0) + return 0; + + buffer = kmalloc(count, GFP_KERNEL); + if (buffer == NULL) { + pr_debug("[0x%x] can not allocate memory\n", tfa98xx->i2c->addr); + return -ENOMEM; + } + + mutex_lock(&tfa98xx->dsp_lock); + error = dsp_msg_read(tfa98xx->tfa, count, buffer); + mutex_unlock(&tfa98xx->dsp_lock); + if (error != Tfa98xx_Error_Ok) { + pr_debug("[0x%x] dsp_msg_read error: %d\n", tfa98xx->i2c->addr, error); + kfree(buffer); + return -EFAULT; + } + + ret = copy_to_user(user_buf, buffer, count); + kfree(buffer); + if (ret) + return -EFAULT; + + *ppos += count; + return count; +} + +static ssize_t tfa98xx_dbgfs_rpc_send(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + nxpTfaFileDsc_t *msg_file; + enum Tfa98xx_Error error; + int err = 0; + + if (tfa98xx->tfa == NULL) { + pr_debug("[0x%x] dsp is not available\n", tfa98xx->i2c->addr); + return -ENODEV; + } + + if (count == 0) + return 0; + + /* msg_file.name is not used */ + msg_file = kmalloc(count + sizeof(nxpTfaFileDsc_t), GFP_KERNEL); + if (msg_file == NULL) { + pr_debug("[0x%x] can not allocate memory\n", tfa98xx->i2c->addr); + return -ENOMEM; + } + msg_file->size = count; + + if (copy_from_user(msg_file->data, user_buf, count)) + return -EFAULT; + + mutex_lock(&tfa98xx->dsp_lock); + if ((msg_file->data[0] == 'M') && (msg_file->data[1] == 'G')) { + /* int vstep_idx, int vstep_msg_idx both 0 */ + error = tfaContWriteFile(tfa98xx->tfa, msg_file, 0, 0); + if (error != Tfa98xx_Error_Ok) { + pr_debug("[0x%x] tfaContWriteFile error: %d\n", + tfa98xx->i2c->addr, error); + err = -EIO; + } + } else { + error = dsp_msg(tfa98xx->tfa, msg_file->size, msg_file->data); + if (error != Tfa98xx_Error_Ok) { + pr_debug("[0x%x] dsp_msg error: %d\n", tfa98xx->i2c->addr, error); + err = -EIO; + } + } + mutex_unlock(&tfa98xx->dsp_lock); + + kfree(msg_file); + + if (err) + return err; + return count; +} +/* -- RPC */ + +static int tfa98xx_dbgfs_pga_gain_get(void *data, u64 *val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + unsigned int value; + + value = tfa_get_pga_gain(tfa98xx->tfa); + if (value < 0) + return -EINVAL; + + *val = value; + return 0; +} + +static int tfa98xx_dbgfs_pga_gain_set(void *data, u64 val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + uint16_t value; + int err; + + value = val & 0xffff; + if (value > 7) + return -EINVAL; + + err = tfa_set_pga_gain(tfa98xx->tfa, value); + if (err < 0) + return -EINVAL; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_calib_otc_fops, tfa98xx_dbgfs_otc_get, + tfa98xx_dbgfs_otc_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_calib_mtpex_fops, tfa98xx_dbgfs_mtpex_get, + tfa98xx_dbgfs_mtpex_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_calib_temp_fops, tfa98xx_dbgfs_temp_get, + tfa98xx_dbgfs_temp_set, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_pga_gain_fops, tfa98xx_dbgfs_pga_gain_get, + tfa98xx_dbgfs_pga_gain_set, "%llu\n"); + +static const struct file_operations tfa98xx_dbgfs_calib_start_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = tfa98xx_dbgfs_start_set, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_r_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = tfa98xx_dbgfs_r_read, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_version_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = tfa98xx_dbgfs_version_read, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_dsp_state_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = tfa98xx_dbgfs_dsp_state_get, + .write = tfa98xx_dbgfs_dsp_state_set, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_fw_state_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = tfa98xx_dbgfs_fw_state_get, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_rpc_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = tfa98xx_dbgfs_rpc_read, + .write = tfa98xx_dbgfs_rpc_send, + .llseek = default_llseek, +}; + +static void tfa98xx_debug_init(struct tfa98xx *tfa98xx, + struct i2c_client *i2c) +{ + char name[50]; + + scnprintf(name, MAX_CONTROL_NAME, "%s-%x", i2c->name, i2c->addr); + tfa98xx->dbg_dir = debugfs_create_dir(name, NULL); + debugfs_create_file("OTC", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_calib_otc_fops); + debugfs_create_file("MTPEX", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_calib_mtpex_fops); + debugfs_create_file("TEMP", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_calib_temp_fops); + debugfs_create_file("calibrate", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_calib_start_fops); + debugfs_create_file("R", S_IRUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_r_fops); + debugfs_create_file("version", S_IRUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_version_fops); + debugfs_create_file("dsp-state", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_dsp_state_fops); + debugfs_create_file("fw-state", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_fw_state_fops); + debugfs_create_file("rpc", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_rpc_fops); + + if (tfa98xx->flags & TFA98XX_FLAG_SAAM_AVAILABLE) { + dev_dbg(tfa98xx->dev, "Adding pga_gain debug interface\n"); + debugfs_create_file("pga_gain", S_IRUGO, tfa98xx->dbg_dir, + tfa98xx->i2c, + &tfa98xx_dbgfs_pga_gain_fops); + } +} + +static void tfa98xx_debug_remove(struct tfa98xx *tfa98xx) +{ + if (tfa98xx->dbg_dir) + debugfs_remove_recursive(tfa98xx->dbg_dir); +} +#endif + + +/* copies the profile basename (i.e. part until .) into buf */ +static void get_profile_basename(char *buf, char *profile) +{ + int cp_len = 0, idx = 0; + char *pch; + + pch = strchr(profile, '.'); + idx = pch - profile; + cp_len = (pch != NULL) ? idx : (int)strlen(profile); + memcpy(buf, profile, cp_len); + buf[cp_len] = 0; +} + +/* return the profile name accociated with id from the profile list */ +static int get_profile_from_list(char *buf, int id) +{ + struct tfa98xx_baseprofile *bprof; + + list_for_each_entry(bprof, &profile_list, list) { + if (bprof->item_id == id) { + strcpy(buf, bprof->basename); + return 0; + } + } + + return ERR; +} + +/* search for the profile in the profile list */ +static int is_profile_in_list(char *profile, int len) +{ + struct tfa98xx_baseprofile *bprof; + + list_for_each_entry(bprof, &profile_list, list) { + + if ((len == bprof->len) && (0 == strncmp(bprof->basename, + profile, len))) + return 1; + } + + return 0; +} + +/* + * for the profile with id, look if the requested samplerate is + * supported, if found return the (container)profile for this + * samplerate, on error or if not found return -1 + */ +static int get_profile_id_for_sr(int id, unsigned int rate) +{ + int idx = 0; + struct tfa98xx_baseprofile *bprof; + + list_for_each_entry(bprof, &profile_list, list) { + if (id == bprof->item_id) { + idx = tfa98xx_get_fssel(rate); + if (idx < 0) { + /* samplerate not supported */ + return ERR; + } + + return bprof->sr_rate_sup[idx]; + } + } + + /* profile not found */ + return ERR; +} + +/* check if this profile is a calibration profile */ +static int is_calibration_profile(char *profile) +{ + if (strstr(profile, ".cal") != NULL) + return 1; + return 0; +} + +/* + * adds the (container)profile index of the samplerate found in + * the (container)profile to a fixed samplerate table in the (mixer)profile + */ +static int add_sr_to_profile(struct tfa98xx *tfa98xx, char *basename, + int len, int profile) +{ + struct tfa98xx_baseprofile *bprof; + int idx = 0; + unsigned int sr = 0; + + list_for_each_entry(bprof, &profile_list, list) { + if ((len == bprof->len) && (0 == strncmp(bprof->basename, + basename, len))) { + /* add supported samplerate for this profile */ + sr = tfa98xx_get_profile_sr(tfa98xx->tfa, profile); + if (!sr) { + pr_err("unable to identify supported sample rate for %s\n", + bprof->basename); + return ERR; + } + + /* get the index for this samplerate */ + idx = tfa98xx_get_fssel(sr); + if (idx < 0 || idx >= TFA98XX_NUM_RATES) { + pr_err("invalid index for samplerate %d\n", idx); + return ERR; + } + + /* enter the (container)profile for this samplerate + * at the corresponding index + */ + bprof->sr_rate_sup[idx] = profile; + + pr_debug("added profile:samplerate = [%d:%d]\ + for mixer profile: %s\n", profile, sr, bprof->basename); + } + } + + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) +static struct snd_soc_codec *snd_soc_kcontrol_codec( + struct snd_kcontrol *kcontrol) +{ + return snd_kcontrol_chip(kcontrol); +} +#endif + +static int tfa98xx_get_vstep(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + int mixer_profile = kcontrol->private_value; + int ret = 0; + int profile; + + profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); + if (profile < 0) { + pr_err("tfa98xx: tfa98xx_get_vstep: invalid profile %d\ + (mixer_profile=%d, rate=%d)\n", profile, mixer_profile, tfa98xx->rate); + return -EINVAL; + } + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + int vstep = tfa98xx->prof_vsteps[profile]; + + ucontrol->value.integer.value[tfa98xx->tfa->dev_idx] = + tfacont_get_max_vstep(tfa98xx->tfa, profile) + - vstep - 1; + } + mutex_unlock(&tfa98xx_mutex); + + return ret; +} + +static int tfa98xx_set_vstep(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + int mixer_profile = kcontrol->private_value; + int profile; + int err = 0; + int change = 0; + + if (no_start != 0) + return 0; + + profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); + if (profile < 0) { + pr_err("tfa98xx: tfa98xx_set_vstep: invalid profile %d\ + (mixer_profile=%d, rate=%d)\n", profile, mixer_profile, tfa98xx->rate); + return -EINVAL; + } + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + int vstep, vsteps; + int ready = 0; + int new_vstep; + int value = ucontrol->value.integer.value[tfa98xx->tfa->dev_idx]; + + vstep = tfa98xx->prof_vsteps[profile]; + vsteps = tfacont_get_max_vstep(tfa98xx->tfa, profile); + + if (vstep == vsteps - value - 1) + continue; + + new_vstep = vsteps - value - 1; + + if (new_vstep < 0) + new_vstep = 0; + + tfa98xx->prof_vsteps[profile] = new_vstep; + +#ifndef TFA98XX_ALSA_CTRL_PROF_CHG_ON_VOL + if (profile == tfa98xx->profile) { +#endif + /* this is the active profile, program the new vstep */ + tfa98xx->vstep = new_vstep; + mutex_lock(&tfa98xx->dsp_lock); + tfa98xx_dsp_system_stable(tfa98xx->tfa, &ready); + + if (ready) { + err = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, + tfa98xx->vstep); + if (err) { + pr_err("Write vstep error: %d\n", err); + } else { + pr_debug("Succesfully changed vstep index!\n"); + change = 1; + } + } + + mutex_unlock(&tfa98xx->dsp_lock); +#ifndef TFA98XX_ALSA_CTRL_PROF_CHG_ON_VOL + } +#endif + pr_debug("%d: vstep:%d, (control value: %d) - profile %d\n", + tfa98xx->tfa->dev_idx, new_vstep, value, profile); + } + + if (change) { + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE, 0); + mutex_unlock(&tfa98xx->dsp_lock); + } + } + + mutex_unlock(&tfa98xx_mutex); + + return change; +} + +static int tfa98xx_info_vstep(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + + int mixer_profile = tfa98xx_mixer_profile; + int profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); + if (profile < 0) { + pr_err("tfa98xx: tfa98xx_info_vstep: invalid profile %d\ + (mixer_profile=%d, rate=%d)\n", profile, mixer_profile, tfa98xx->rate); + return -EINVAL; + } + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + mutex_lock(&tfa98xx_mutex); + uinfo->count = tfa98xx_device_count; + mutex_unlock(&tfa98xx_mutex); + uinfo->value.integer.min = 0; + uinfo->value.integer.max = max(0, + tfacont_get_max_vstep(tfa98xx->tfa, profile) - 1); + pr_debug("vsteps count: %d [prof=%d]\n", + tfacont_get_max_vstep(tfa98xx->tfa, profile), + profile); + return 0; +} + +static int tfa98xx_get_profile(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + mutex_lock(&tfa98xx_mutex); + ucontrol->value.integer.value[0] = tfa98xx_mixer_profile; + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static int tfa98xx_set_profile(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + int change = 0; + int new_profile; + int prof_idx; + int profile_count = tfa98xx_mixer_profiles; + int profile = tfa98xx_mixer_profile; + + if (no_start != 0) + return 0; + + new_profile = ucontrol->value.integer.value[0]; + if (new_profile == profile) + return 0; + + if ((new_profile < 0) || (new_profile >= profile_count)) { + pr_err("not existing profile (%d)\n", new_profile); + return -EINVAL; + } + + /* get the container profile for the requested sample rate */ + prof_idx = get_profile_id_for_sr(new_profile, tfa98xx->rate); + if (prof_idx < 0) { + pr_err("tfa98xx: sample rate [%d] not supported for this \ + mixer profile [%d].\n", tfa98xx->rate, new_profile); + return 0; + } + pr_debug("selected container profile [%d]\n", prof_idx); + + /* update mixer profile */ + tfa98xx_mixer_profile = new_profile; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + int err; + int ready = 0; + + /* update 'real' profile (container profile) */ + tfa98xx->profile = prof_idx; + tfa98xx->vstep = tfa98xx->prof_vsteps[prof_idx]; + + /* Don't call tfa_dev_start() if there is no clock. */ + mutex_lock(&tfa98xx->dsp_lock); + tfa98xx_dsp_system_stable(tfa98xx->tfa, &ready); + if (ready) { + /* Also re-enables the interrupts */ + err = tfa98xx_tfa_start(tfa98xx, prof_idx, tfa98xx->vstep); + if (err) { + pr_info("Write profile error: %d\n", err); + } else { + pr_debug("Changed to profile %d (vstep = %d)\n", + prof_idx, tfa98xx->vstep); + change = 1; + } + } + mutex_unlock(&tfa98xx->dsp_lock); + + /* Flag DSP as invalidated as the profile change may invalidate the + * current DSP configuration. That way, further stream start can + * trigger a tfa_dev_start. + */ + tfa98xx->dsp_init = TFA98XX_DSP_INIT_INVALIDATED; + } + + if (change) { + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE, 0); + mutex_unlock(&tfa98xx->dsp_lock); + } + } + + mutex_unlock(&tfa98xx_mutex); + + return change; +} + +static int tfa98xx_info_profile(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + char profile_name[MAX_CONTROL_NAME] = { 0 }; + int count = tfa98xx_mixer_profiles, err = -1; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + err = get_profile_from_list(profile_name, uinfo->value.enumerated.item); + if (err != 0) + return -EINVAL; + + strcpy(uinfo->value.enumerated.name, profile_name); + + return 0; +} + +static int tfa98xx_info_stop_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + mutex_lock(&tfa98xx_mutex); + uinfo->count = tfa98xx_device_count; + mutex_unlock(&tfa98xx_mutex); + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + + return 0; +} + +static int tfa98xx_get_stop_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tfa98xx *tfa98xx; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + ucontrol->value.integer.value[tfa98xx->tfa->dev_idx] = 0; + } + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static int tfa98xx_set_stop_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tfa98xx *tfa98xx; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + int ready = 0; + int i = tfa98xx->tfa->dev_idx; + + pr_debug("%d: %ld\n", i, ucontrol->value.integer.value[i]); + + tfa98xx_dsp_system_stable(tfa98xx->tfa, &ready); + + if ((ucontrol->value.integer.value[i] != 0) && ready) { + cancel_delayed_work_sync(&tfa98xx->monitor_work); + + cancel_delayed_work_sync(&tfa98xx->init_work); + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) + continue; + + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_stop(tfa98xx->tfa); + tfa98xx->dsp_init = TFA98XX_DSP_INIT_STOPPED; + mutex_unlock(&tfa98xx->dsp_lock); + } + + ucontrol->value.integer.value[i] = 0; + } + mutex_unlock(&tfa98xx_mutex); + + return 1; +} + +static int tfa98xx_info_cal_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + mutex_lock(&tfa98xx_mutex); + uinfo->count = tfa98xx_device_count; + mutex_unlock(&tfa98xx_mutex); + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xffff; /* 16 bit value */ + + return 0; +} + +static int tfa98xx_set_cal_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tfa98xx *tfa98xx; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + enum tfa_error err; + int i = tfa98xx->tfa->dev_idx; + + tfa98xx->cal_data = (uint16_t)ucontrol->value.integer.value[i]; + + mutex_lock(&tfa98xx->dsp_lock); + err = tfa98xx_write_re25(tfa98xx->tfa, tfa98xx->cal_data); + tfa98xx->set_mtp_cal = (err != tfa_error_ok); + if (tfa98xx->set_mtp_cal == false) { + pr_info("Calibration value (%d) set in mtp\n", + tfa98xx->cal_data); + } + mutex_unlock(&tfa98xx->dsp_lock); + } + mutex_unlock(&tfa98xx_mutex); + + return 1; +} + +static int tfa98xx_get_cal_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tfa98xx *tfa98xx; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + mutex_lock(&tfa98xx->dsp_lock); + ucontrol->value.integer.value[tfa98xx->tfa->dev_idx] = + tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_RE25_PRIM); + mutex_unlock(&tfa98xx->dsp_lock); + } + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static int tfa98xx_create_controls(struct tfa98xx *tfa98xx) +{ + int prof, nprof, mix_index = 0; + int nr_controls = 0, id = 0; + char *name; + struct tfa98xx_baseprofile *bprofile; + + /* Create the following controls: + * - enum control to select the active profile + * - one volume control for each profile hosting a vstep + * - Stop control on TFA1 devices + */ + + nr_controls = 2; /* Profile and stop control */ + + if (tfa98xx->flags & TFA98XX_FLAG_CALIBRATION_CTL) + nr_controls += 1; /* calibration */ + + /* allocate the tfa98xx_controls base on the nr of profiles */ + nprof = tfa_cnt_get_dev_nprof(tfa98xx->tfa); + for (prof = 0; prof < nprof; prof++) { + if (tfacont_get_max_vstep(tfa98xx->tfa, prof)) + nr_controls++; /* Playback Volume control */ + } + + tfa98xx_controls = devm_kzalloc(tfa98xx->codec->dev, + nr_controls * sizeof(tfa98xx_controls[0]), GFP_KERNEL); + if (!tfa98xx_controls) + return -ENOMEM; + + /* Create a mixer item for selecting the active profile */ + name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + if (!name) + return -ENOMEM; + scnprintf(name, MAX_CONTROL_NAME, "%s Profile", tfa98xx->fw.name); + tfa98xx_controls[mix_index].name = name; + tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tfa98xx_controls[mix_index].info = tfa98xx_info_profile; + tfa98xx_controls[mix_index].get = tfa98xx_get_profile; + tfa98xx_controls[mix_index].put = tfa98xx_set_profile; + /* save number of profiles */ + // tfa98xx_controls[mix_index].private_value = profs; + mix_index++; + + /* create mixer items for each profile that has volume */ + for (prof = 0; prof < nprof; prof++) { + /* create an new empty profile */ + bprofile = devm_kzalloc(tfa98xx->codec->dev, + sizeof(*bprofile), GFP_KERNEL); + if (!bprofile) + return -ENOMEM; + + bprofile->len = 0; + bprofile->item_id = -1; + INIT_LIST_HEAD(&bprofile->list); + + /* copy profile name into basename until the . */ + get_profile_basename(bprofile->basename, + tfa_cont_profile_name(tfa98xx, prof)); + bprofile->len = strlen(bprofile->basename); + + /* + * search the profile list for a profile with basename, if it is not + * found then add it to the list and add a new mixer control + * (if it has vsteps)also, if it is a calibration profile, + * do not add it to the list + */ + if ((is_profile_in_list(bprofile->basename, bprofile->len) == 0) && + is_calibration_profile( + tfa_cont_profile_name(tfa98xx, prof)) == 0) { + /* the profile is not present, add it to the list */ + list_add(&bprofile->list, &profile_list); + bprofile->item_id = id++; + + pr_debug("profile added [%d]: %s\n", + bprofile->item_id, bprofile->basename); + + if (tfacont_get_max_vstep(tfa98xx->tfa, prof)) { + name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, + GFP_KERNEL); + if (!name) + return -ENOMEM; + + scnprintf(name, MAX_CONTROL_NAME, "%s %s Playback Volume", + tfa98xx->fw.name, bprofile->basename); + + tfa98xx_controls[mix_index].name = name; + tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tfa98xx_controls[mix_index].info = tfa98xx_info_vstep; + tfa98xx_controls[mix_index].get = tfa98xx_get_vstep; + tfa98xx_controls[mix_index].put = tfa98xx_set_vstep; + /* save profile index */ + tfa98xx_controls[mix_index].private_value = bprofile->item_id; + mix_index++; + } + } + + /* look for the basename profile in the list of mixer profiles and + * add the container profile index to the supported samplerates + * of this mixer profile */ + add_sr_to_profile(tfa98xx, bprofile->basename, bprofile->len, prof); + } + + /* set the number of user selectable profiles in the mixer */ + tfa98xx_mixer_profiles = id; + + /* Create a mixer item for stop control on TFA1 */ + name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + if (!name) + return -ENOMEM; + + scnprintf(name, MAX_CONTROL_NAME, "%s Stop", tfa98xx->fw.name); + tfa98xx_controls[mix_index].name = name; + tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tfa98xx_controls[mix_index].info = tfa98xx_info_stop_ctl; + tfa98xx_controls[mix_index].get = tfa98xx_get_stop_ctl; + tfa98xx_controls[mix_index].put = tfa98xx_set_stop_ctl; + mix_index++; + + if (tfa98xx->flags & TFA98XX_FLAG_CALIBRATION_CTL) { + name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + if (!name) + return -ENOMEM; + + scnprintf(name, MAX_CONTROL_NAME, "%s Calibration", tfa98xx->fw.name); + tfa98xx_controls[mix_index].name = name; + tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tfa98xx_controls[mix_index].info = tfa98xx_info_cal_ctl; + tfa98xx_controls[mix_index].get = tfa98xx_get_cal_ctl; + tfa98xx_controls[mix_index].put = tfa98xx_set_cal_ctl; + mix_index++; + } + + return snd_soc_add_codec_controls(tfa98xx->codec, + tfa98xx_controls, mix_index); +} + +static void *tfa98xx_devm_kstrdup(struct device *dev, char *buf) +{ + char *str = devm_kzalloc(dev, strlen(buf) + 1, GFP_KERNEL); + if (!str) + return str; + memcpy(str, buf, strlen(buf)); + return str; +} + +static int tfa98xx_append_i2c_address(struct device *dev, + struct i2c_client *i2c, + struct snd_soc_dapm_widget *widgets, + int num_widgets, + struct snd_soc_dai_driver *dai_drv, + int num_dai) +{ + char buf[50]; + int i; + int i2cbus = i2c->adapter->nr; + int addr = i2c->addr; + if (dai_drv && num_dai > 0) + for (i = 0; i < num_dai; i++) { + snprintf(buf, 50, "%s-%x-%x", dai_drv[i].name, i2cbus, + addr); + dai_drv[i].name = tfa98xx_devm_kstrdup(dev, buf); + + snprintf(buf, 50, "%s-%x-%x", + dai_drv[i].playback.stream_name, + i2cbus, addr); + dai_drv[i].playback.stream_name = tfa98xx_devm_kstrdup(dev, buf); + + snprintf(buf, 50, "%s-%x-%x", + dai_drv[i].capture.stream_name, + i2cbus, addr); + dai_drv[i].capture.stream_name = tfa98xx_devm_kstrdup(dev, buf); + } + + /* the idea behind this is convert: + * SND_SOC_DAPM_AIF_IN("AIF IN", "AIF Playback", 0, SND_SOC_NOPM, 0, 0), + * into: + * SND_SOC_DAPM_AIF_IN("AIF IN", "AIF Playback-2-36", + * 0, SND_SOC_NOPM, 0, 0), + */ + if (widgets && num_widgets > 0) + for (i = 0; i < num_widgets; i++) { + if (!widgets[i].sname) + continue; + if ((widgets[i].id == snd_soc_dapm_aif_in) + || (widgets[i].id == snd_soc_dapm_aif_out)) { + snprintf(buf, 50, "%s-%x-%x", widgets[i].sname, + i2cbus, addr); + widgets[i].sname = tfa98xx_devm_kstrdup(dev, buf); + } + } + + return 0; +} + +static struct snd_soc_dapm_widget tfa98xx_dapm_widgets_common[] = { + /* Stream widgets */ + SND_SOC_DAPM_AIF_IN("AIF IN", "AIF Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF OUT", "AIF Capture", 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("OUTL"), + SND_SOC_DAPM_INPUT("AEC Loopback"), +}; + +static struct snd_soc_dapm_widget tfa98xx_dapm_widgets_stereo[] = { + SND_SOC_DAPM_OUTPUT("OUTR"), +}; + +static struct snd_soc_dapm_widget tfa98xx_dapm_widgets_saam[] = { + SND_SOC_DAPM_INPUT("SAAM MIC"), +}; + +static struct snd_soc_dapm_widget tfa9888_dapm_inputs[] = { + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + SND_SOC_DAPM_INPUT("DMIC3"), + SND_SOC_DAPM_INPUT("DMIC4"), +}; + +static const struct snd_soc_dapm_route tfa98xx_dapm_routes_common[] = { + { "OUTL", NULL, "AIF IN" }, + { "AIF OUT", NULL, "AEC Loopback" }, +}; + +static const struct snd_soc_dapm_route tfa98xx_dapm_routes_saam[] = { + { "AIF OUT", NULL, "SAAM MIC" }, +}; + +static const struct snd_soc_dapm_route tfa98xx_dapm_routes_stereo[] = { + { "OUTR", NULL, "AIF IN" }, +}; + +static const struct snd_soc_dapm_route tfa9888_input_dapm_routes[] = { + { "AIF OUT", NULL, "DMIC1" }, + { "AIF OUT", NULL, "DMIC2" }, + { "AIF OUT", NULL, "DMIC3" }, + { "AIF OUT", NULL, "DMIC4" }, +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) +static struct snd_soc_dapm_context *snd_soc_codec_get_dapm( + struct snd_soc_codec *codec) +{ + return &codec->dapm; +} +#endif + +static void tfa98xx_add_widgets(struct tfa98xx *tfa98xx) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(tfa98xx->codec); + struct snd_soc_dapm_widget *widgets; + unsigned int num_dapm_widgets = ARRAY_SIZE(tfa98xx_dapm_widgets_common); + + widgets = devm_kzalloc(&tfa98xx->i2c->dev, + sizeof(struct snd_soc_dapm_widget) * + ARRAY_SIZE(tfa98xx_dapm_widgets_common), + GFP_KERNEL); + if (!widgets) + return; + memcpy(widgets, tfa98xx_dapm_widgets_common, + sizeof(struct snd_soc_dapm_widget) * + ARRAY_SIZE(tfa98xx_dapm_widgets_common)); + + tfa98xx_append_i2c_address(&tfa98xx->i2c->dev, + tfa98xx->i2c, + widgets, + num_dapm_widgets, + NULL, + 0); + + snd_soc_dapm_new_controls(dapm, widgets, + ARRAY_SIZE(tfa98xx_dapm_widgets_common)); + snd_soc_dapm_add_routes(dapm, tfa98xx_dapm_routes_common, + ARRAY_SIZE(tfa98xx_dapm_routes_common)); + + if (tfa98xx->flags & TFA98XX_FLAG_STEREO_DEVICE) { + snd_soc_dapm_new_controls(dapm, tfa98xx_dapm_widgets_stereo, + ARRAY_SIZE(tfa98xx_dapm_widgets_stereo)); + snd_soc_dapm_add_routes(dapm, tfa98xx_dapm_routes_stereo, + ARRAY_SIZE(tfa98xx_dapm_routes_stereo)); + } + + if (tfa98xx->flags & TFA98XX_FLAG_MULTI_MIC_INPUTS) { + snd_soc_dapm_new_controls(dapm, tfa9888_dapm_inputs, + ARRAY_SIZE(tfa9888_dapm_inputs)); + snd_soc_dapm_add_routes(dapm, tfa9888_input_dapm_routes, + ARRAY_SIZE(tfa9888_input_dapm_routes)); + } + + if (tfa98xx->flags & TFA98XX_FLAG_SAAM_AVAILABLE) { + snd_soc_dapm_new_controls(dapm, tfa98xx_dapm_widgets_saam, + ARRAY_SIZE(tfa98xx_dapm_widgets_saam)); + snd_soc_dapm_add_routes(dapm, tfa98xx_dapm_routes_saam, + ARRAY_SIZE(tfa98xx_dapm_routes_saam)); + } +} + +/* I2C wrapper functions */ +enum Tfa98xx_Error tfa98xx_write_register16(struct tfa_device *tfa, + unsigned char subaddress, + unsigned short value) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + struct tfa98xx *tfa98xx; + int ret; + int retries = I2C_RETRIES; + + if (tfa == NULL) { + pr_err("No device available\n"); + return Tfa98xx_Error_Fail; + } + + tfa98xx = (struct tfa98xx *)tfa->data; + if (!tfa98xx || !tfa98xx->regmap) { + pr_err("No tfa98xx regmap available\n"); + return Tfa98xx_Error_Bad_Parameter; + } +retry: + ret = regmap_write(tfa98xx->regmap, subaddress, value); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + return Tfa98xx_Error_Fail; + } + if (tfa98xx_kmsg_regs) + dev_dbg(&tfa98xx->i2c->dev, " WR reg=0x%02x, val=0x%04x %s\n", + subaddress, value, + ret < 0 ? "Error!!" : ""); + + if (tfa98xx_ftrace_regs) + tfa98xx_trace_printk("\tWR reg=0x%02x, val=0x%04x %s\n", + subaddress, value, + ret < 0 ? "Error!!" : ""); + return error; +} + +enum Tfa98xx_Error tfa98xx_read_register16(struct tfa_device *tfa, + unsigned char subaddress, + unsigned short *val) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + struct tfa98xx *tfa98xx; + unsigned int value; + int retries = I2C_RETRIES; + int ret; + + if (tfa == NULL) { + pr_err("No device available\n"); + return Tfa98xx_Error_Fail; + } + + tfa98xx = (struct tfa98xx *)tfa->data; + if (!tfa98xx || !tfa98xx->regmap) { + pr_err("No tfa98xx regmap available\n"); + return Tfa98xx_Error_Bad_Parameter; + } +retry: + ret = regmap_read(tfa98xx->regmap, subaddress, &value); + if (ret < 0) { + pr_warn("i2c error at subaddress 0x%x, retries left: %d\n", + subaddress, retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + return Tfa98xx_Error_Fail; + } + *val = value & 0xffff; + + if (tfa98xx_kmsg_regs) + dev_dbg(&tfa98xx->i2c->dev, "RD reg=0x%02x, val=0x%04x %s\n", + subaddress, *val, + ret < 0 ? "Error!!" : ""); + if (tfa98xx_ftrace_regs) + tfa98xx_trace_printk("\tRD reg=0x%02x, val=0x%04x %s\n", + subaddress, *val, + ret < 0 ? "Error!!" : ""); + + return error; +} + + +/* + * init external dsp + */ +enum Tfa98xx_Error + tfa98xx_init_dsp(struct tfa_device *tfa) +{ + return Tfa98xx_Error_Not_Supported; +} + +int tfa98xx_get_dsp_status(struct tfa_device *tfa) +{ + return 0; +} + +/* + * write external dsp message + */ +enum Tfa98xx_Error + tfa98xx_write_dsp(struct tfa_device *tfa, int num_bytes, + const char *command_buffer) +{ + return Tfa98xx_Error_Not_Supported; +} + +/* + * read external dsp message + */ +enum Tfa98xx_Error + tfa98xx_read_dsp(struct tfa_device *tfa, int num_bytes, + unsigned char *result_buffer) +{ + return Tfa98xx_Error_Not_Supported; +} +/* + * write/read external dsp message + */ +enum Tfa98xx_Error + tfa98xx_writeread_dsp(struct tfa_device *tfa, int command_length, + void *command_buffer, int result_length, void *result_buffer) +{ + return Tfa98xx_Error_Not_Supported; +} + +enum Tfa98xx_Error tfa98xx_read_data(struct tfa_device *tfa, + unsigned char reg, + int len, unsigned char value[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + struct tfa98xx *tfa98xx; + struct i2c_client *tfa98xx_client; + int err; + int tries = 0; + unsigned char *reg_buf = NULL; + struct i2c_msg msgs[] = { + { + .flags = 0, + .len = 1, + .buf = NULL, + }, { + .flags = I2C_M_RD, + .len = len, + .buf = value, + }, + }; + //GRP_KERNEL also works, + reg_buf = (unsigned char *)kmalloc(sizeof(reg), GFP_DMA); + if (!reg_buf) { + return -ENOMEM;; + } + + *reg_buf = reg; + msgs[0].buf = reg_buf; + + if (tfa == NULL) { + pr_err("No device available\n"); + return Tfa98xx_Error_Fail; + } + + tfa98xx = (struct tfa98xx *)tfa->data; + if (tfa98xx->i2c) { + tfa98xx_client = tfa98xx->i2c; + msgs[0].addr = tfa98xx_client->addr; + msgs[1].addr = tfa98xx_client->addr; + + do { + err = i2c_transfer(tfa98xx_client->adapter, msgs, + ARRAY_SIZE(msgs)); + if (err != ARRAY_SIZE(msgs)) + msleep_interruptible(I2C_RETRY_DELAY); + } while ((err != ARRAY_SIZE(msgs)) && (++tries < I2C_RETRIES)); + + if (err != ARRAY_SIZE(msgs)) { + dev_err(&tfa98xx_client->dev, "read transfer error %d\n", + err); + error = Tfa98xx_Error_Fail; + } + + if (tfa98xx_kmsg_regs) + dev_dbg(&tfa98xx_client->dev, "RD-DAT reg=0x%02x, len=%d\n", + reg, len); + if (tfa98xx_ftrace_regs) + tfa98xx_trace_printk("\t\tRD-DAT reg=0x%02x, len=%d\n", + reg, len); + } else { + pr_err("No device available\n"); + error = Tfa98xx_Error_Fail; + } + kfree(reg_buf); + return error; +} + +enum Tfa98xx_Error tfa98xx_write_raw(struct tfa_device *tfa, + int len, + const unsigned char data[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + struct tfa98xx *tfa98xx; + int ret; + int retries = I2C_RETRIES; + + + if (tfa == NULL) { + pr_err("No device available\n"); + return Tfa98xx_Error_Fail; + } + + tfa98xx = (struct tfa98xx *)tfa->data; + +retry: + ret = i2c_master_send(tfa98xx->i2c, data, len); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + } + + if (ret == len) { + if (tfa98xx_kmsg_regs) + dev_dbg(&tfa98xx->i2c->dev, " WR-RAW len=%d\n", len); + if (tfa98xx_ftrace_regs) + tfa98xx_trace_printk("\t\tWR-RAW len=%d\n", len); + return Tfa98xx_Error_Ok; + } + pr_err(" WR-RAW (len=%d) Error I2C send size mismatch %d\n", len, ret); + error = Tfa98xx_Error_Fail; + + return error; +} + +/* Interrupts management */ + +static void tfa98xx_interrupt_enable_tfa2(struct tfa98xx *tfa98xx, bool enable) +{ + /* Only for 0x72 we need to enable NOCLK interrupts */ + if (tfa98xx->flags & TFA98XX_FLAG_REMOVE_PLOP_NOISE) + tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_stnoclk, enable); + + if (tfa98xx->flags & TFA98XX_FLAG_LP_MODES) { + /* FIXME: IELP0 does not excist for 9912 */ + tfa_irq_ena(tfa98xx->tfa, 36, enable); + tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_stclpr, enable); + } +} + +/* Check if tap-detection can and shall be enabled. + * Configure SPK interrupt accordingly or setup polling mode + * Tap-detection shall be active if: + * - the service is enabled (tapdet_open), AND + * - the current profile is a tap-detection profile + * On TFA1 familiy of devices, activating tap-detection means enabling the SPK + * interrupt if available. + * We also update the tapdet_enabled and tapdet_poll variables. + */ +static void tfa98xx_tapdet_check_update(struct tfa98xx *tfa98xx) +{ + unsigned int enable = false; + + /* Support tap-detection on TFA1 family of devices */ + if ((tfa98xx->flags & TFA98XX_FLAG_TAPDET_AVAILABLE) == 0) + return; + + if (tfa98xx->tapdet_open && + (tfa98xx->tapdet_profiles & (1 << tfa98xx->profile))) + enable = true; + + if (!gpio_is_valid(tfa98xx->irq_gpio)) { + /* interrupt not available, setup polling mode */ + tfa98xx->tapdet_poll = true; + if (enable) + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->tapdet_work, HZ / 10); + else + cancel_delayed_work_sync(&tfa98xx->tapdet_work); + dev_dbg(tfa98xx->codec->dev, + "Polling for tap-detection: %s (%d; 0x%x, %d)\n", + enable ? "enabled" : "disabled", + tfa98xx->tapdet_open, tfa98xx->tapdet_profiles, + tfa98xx->profile); + + } else { + dev_dbg(tfa98xx->codec->dev, + "Interrupt for tap-detection: %s (%d; 0x%x, %d)\n", + enable ? "enabled" : "disabled", + tfa98xx->tapdet_open, tfa98xx->tapdet_profiles, + tfa98xx->profile); + /* enabled interrupt */ + tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_sttapdet, enable); + } + + /* check disabled => enabled transition to clear pending events */ + if (!tfa98xx->tapdet_enabled && enable) { + /* clear pending event if any */ + tfa_irq_clear(tfa98xx->tfa, tfa9912_irq_sttapdet); + } + + if (!tfa98xx->tapdet_poll) + tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_sttapdet, 1); /* enable again */ +} + +/* global enable / disable interrupts */ +static void tfa98xx_interrupt_enable(struct tfa98xx *tfa98xx, bool enable) +{ + if (tfa98xx->flags & TFA98XX_FLAG_SKIP_INTERRUPTS) + return; + + if (tfa98xx->tfa->tfa_family == 2) + tfa98xx_interrupt_enable_tfa2(tfa98xx, enable); +} + +/* Firmware management */ +static void tfa98xx_container_loaded(const struct firmware *cont, + void *context) +{ + nxpTfaContainer_t *container; + struct tfa98xx *tfa98xx = context; + enum tfa_error tfa_err; + int container_size; + int ret; + + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; + + if (!cont) { + pr_err("Failed to read %s\n", fw_name); + return; + } + + pr_debug("loaded %s - size: %zu\n", fw_name, cont->size); + + mutex_lock(&tfa98xx_mutex); + if (tfa98xx_container == NULL) { + container = kzalloc(cont->size, GFP_KERNEL); + if (container == NULL) { + mutex_unlock(&tfa98xx_mutex); + release_firmware(cont); + pr_err("Error allocating memory\n"); + return; + } + + container_size = cont->size; + memcpy(container, cont->data, container_size); + release_firmware(cont); + + pr_debug("%.2s%.2s\n", container->version, container->subversion); + pr_debug("%.8s\n", container->customer); + pr_debug("%.8s\n", container->application); + pr_debug("%.8s\n", container->type); + pr_debug("%d ndev\n", container->ndev); + pr_debug("%d nprof\n", container->nprof); + + tfa_err = tfa_load_cnt(container, container_size); + if (tfa_err != tfa_error_ok) { + mutex_unlock(&tfa98xx_mutex); + kfree(container); + dev_err(tfa98xx->dev, "Cannot load container file, aborting\n"); + return; + } + + tfa98xx_container = container; + } else { + pr_debug("container file already loaded...\n"); + container = tfa98xx_container; + release_firmware(cont); + } + mutex_unlock(&tfa98xx_mutex); + + tfa98xx->tfa->cnt = container; + + /* + i2c transaction limited to 64k + (Documentation/i2c/writing-clients) + */ + tfa98xx->tfa->buffer_size = 65536; + + /* DSP messages via i2c */ + tfa98xx->tfa->has_msg = 0; + + if (tfa_dev_probe(tfa98xx->i2c->addr, tfa98xx->tfa) != 0) { + dev_err(tfa98xx->dev, "Failed to probe TFA98xx @ 0x%.2x\n", + tfa98xx->i2c->addr); + return; + } + + tfa98xx->tfa->dev_idx = tfa_cont_get_idx(tfa98xx->tfa); + if (tfa98xx->tfa->dev_idx < 0) { + dev_err(tfa98xx->dev, "Failed to find TFA98xx @ 0x%.2x in \ + container file\n", tfa98xx->i2c->addr); + return; + } + + /* Enable debug traces */ + tfa98xx->tfa->verbose = trace_level & 1; + + /* prefix is the application name from the cnt */ + tfa_cnt_get_app_name(tfa98xx->tfa, tfa98xx->fw.name); + + /* set default profile/vstep */ + tfa98xx->profile = 0; + tfa98xx->vstep = 0; + + /* Override default profile if requested */ + if (strcmp(dflt_prof_name, "")) { + unsigned int i; + int nprof = tfa_cnt_get_dev_nprof(tfa98xx->tfa); + for (i = 0; i < nprof; i++) { + if (strcmp(tfa_cont_profile_name(tfa98xx, i), + dflt_prof_name) == 0) { + tfa98xx->profile = i; + dev_info(tfa98xx->dev, + "changing default profile to %s (%d)\n", + dflt_prof_name, tfa98xx->profile); + break; + } + } + if (i >= nprof) + dev_info(tfa98xx->dev, + "Default profile override failed (%s profile not found)\n", + dflt_prof_name); + } + + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_OK; + pr_debug("Firmware init complete\n"); + + if (no_start != 0) + return; + + /* Only controls for master device */ + if (tfa98xx->tfa->dev_idx == 0) + tfa98xx_create_controls(tfa98xx); + + tfa98xx_inputdev_check_register(tfa98xx); + + if (tfa_is_cold(tfa98xx->tfa) == 0) { + pr_debug("Warning: device 0x%.2x is still warm\n", tfa98xx->i2c->addr); + tfa_reset(tfa98xx->tfa); + } + + /* Preload settings using internal clock on TFA2 */ + if (tfa98xx->tfa->tfa_family == 2) { + mutex_lock(&tfa98xx->dsp_lock); + ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); + if (ret == Tfa98xx_Error_Not_Supported) + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; + mutex_unlock(&tfa98xx->dsp_lock); + } + + tfa98xx_interrupt_enable(tfa98xx, true); +} + +static int tfa98xx_load_container(struct tfa98xx *tfa98xx) +{ + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_PENDING; + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + fw_name, tfa98xx->dev, GFP_KERNEL, + tfa98xx, tfa98xx_container_loaded); +} + + +static void tfa98xx_tapdet(struct tfa98xx *tfa98xx) +{ + unsigned int tap_pattern; + int btn; + + /* check tap pattern (BTN_0 is "error" wrong tap indication */ + tap_pattern = tfa_get_tap_pattern(tfa98xx->tfa); + switch (tap_pattern) { + case 0xffffffff: + pr_info("More than 4 taps detected! (flagTapPattern = -1)\n"); + btn = BTN_0; + break; + case 0xfffffffe: + case 0xfe: + pr_info("Illegal tap detected!\n"); + btn = BTN_0; + break; + case 0: + pr_info("Unrecognized pattern! (flagTapPattern = 0)\n"); + btn = BTN_0; + break; + default: + pr_info("Detected pattern: %d\n", tap_pattern); + btn = BTN_0 + tap_pattern; + break; + } + + input_report_key(tfa98xx->input, btn, 1); + input_report_key(tfa98xx->input, btn, 0); + input_sync(tfa98xx->input); + + /* acknowledge event done by clearing interrupt */ + +} + +static void tfa98xx_tapdet_work(struct work_struct *work) +{ + struct tfa98xx *tfa98xx; + + //TODO check is this is still needed for tap polling + tfa98xx = container_of(work, struct tfa98xx, tapdet_work.work); + + if (tfa_irq_get(tfa98xx->tfa, tfa9912_irq_sttapdet)) + tfa98xx_tapdet(tfa98xx); + + queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->tapdet_work, HZ / 10); +} + +static void tfa98xx_monitor(struct work_struct *work) +{ + struct tfa98xx *tfa98xx; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + tfa98xx = container_of(work, struct tfa98xx, monitor_work.work); + + /* Check for tap-detection - bypass monitor if it is active */ + if (!tfa98xx->input) { + mutex_lock(&tfa98xx->dsp_lock); + error = tfa_status(tfa98xx->tfa); + mutex_unlock(&tfa98xx->dsp_lock); + if (error == Tfa98xx_Error_DSP_not_running) { + if (tfa98xx->dsp_init == TFA98XX_DSP_INIT_DONE) { + tfa98xx->dsp_init = TFA98XX_DSP_INIT_RECOVER; + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->init_work, 0); + } + } + } + + /* reschedule */ + queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->monitor_work, 5 * HZ); +} + +static void tfa98xx_dsp_init(struct tfa98xx *tfa98xx) +{ + int ret; + bool failed = false; + bool reschedule = false; + bool sync = false; + + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) { + pr_debug("Skipping tfa_dev_start (no FW: %d)\n", tfa98xx->dsp_fw_state); + return; + } + + if (tfa98xx->dsp_init == TFA98XX_DSP_INIT_DONE) { + pr_debug("Stream already started, skipping DSP power-on\n"); + return; + } + mutex_lock(&tfa98xx->dsp_lock); + + tfa98xx->dsp_init = TFA98XX_DSP_INIT_PENDING; + + if (tfa98xx->init_count < TF98XX_MAX_DSP_START_TRY_COUNT) { + /* directly try to start DSP */ + ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); + if (ret == Tfa98xx_Error_Not_Supported) { + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; + dev_err(&tfa98xx->i2c->dev, "Failed starting device\n"); + failed = true; + } else if (ret != Tfa98xx_Error_Ok) { + /* It may fail as we may not have a valid clock at that + * time, so re-schedule and re-try later. + */ + dev_err(&tfa98xx->i2c->dev, + "tfa_dev_start failed! (err %d) - %d\n", + ret, tfa98xx->init_count); + reschedule = true; + } else { + sync = true; + + /* Subsystem ready, tfa init complete */ + tfa98xx->dsp_init = TFA98XX_DSP_INIT_DONE; + dev_dbg(&tfa98xx->i2c->dev, + "tfa_dev_start success (%d)\n", + tfa98xx->init_count); + /* cancel other pending init works */ + cancel_delayed_work(&tfa98xx->init_work); + tfa98xx->init_count = 0; + } + } else { + /* exceeded max number ot start tentatives, cancel start */ + dev_err(&tfa98xx->i2c->dev, + "Failed starting device (%d)\n", + tfa98xx->init_count); + failed = true; + } + + if (reschedule) { + /* reschedule this init work for later */ + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->init_work, + msecs_to_jiffies(5)); + tfa98xx->init_count++; + } + if (failed) { + tfa98xx->dsp_init = TFA98XX_DSP_INIT_FAIL; + /* cancel other pending init works */ + cancel_delayed_work(&tfa98xx->init_work); + tfa98xx->init_count = 0; + } + mutex_unlock(&tfa98xx->dsp_lock); + + if (sync) { + /* check if all devices have started */ + bool do_sync; + mutex_lock(&tfa98xx_mutex); + + if (tfa98xx_sync_count < tfa98xx_device_count) + tfa98xx_sync_count++; + + do_sync = (tfa98xx_sync_count >= tfa98xx_device_count); + mutex_unlock(&tfa98xx_mutex); + + /* when all devices have started then unmute */ + if (do_sync) { + tfa98xx_sync_count = 0; + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE, 0); + + /* + * start monitor thread to check IC status bit + * periodically, and re-init IC to recover if + * needed. + */ + if (tfa98xx->tfa->tfa_family == 1) + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->monitor_work, + 1 * HZ); + mutex_unlock(&tfa98xx->dsp_lock); + } + + } + } +} + + +static void tfa98xx_dsp_init_work(struct work_struct *work) +{ + struct tfa98xx *tfa98xx = container_of(work, struct tfa98xx, + init_work.work); + + tfa98xx_dsp_init(tfa98xx); +} + +static void tfa98xx_interrupt(struct work_struct *work) +{ + struct tfa98xx *tfa98xx = container_of(work, struct tfa98xx, + interrupt_work.work); + + pr_info("\n"); + + if (tfa98xx->flags & TFA98XX_FLAG_TAPDET_AVAILABLE) { + /* check for tap interrupt */ + if (tfa_irq_get(tfa98xx->tfa, tfa9912_irq_sttapdet)) { + tfa98xx_tapdet(tfa98xx); + + /* clear interrupt */ + tfa_irq_clear(tfa98xx->tfa, tfa9912_irq_sttapdet); + } + } /* TFA98XX_FLAG_TAPDET_AVAILABLE */ + + if (tfa98xx->flags & TFA98XX_FLAG_REMOVE_PLOP_NOISE) { + int start_triggered; + + mutex_lock(&tfa98xx->dsp_lock); + start_triggered = tfa_plop_noise_interrupt(tfa98xx->tfa, + tfa98xx->profile, tfa98xx->vstep); + /* Only enable when the return value is 1, + * otherwise the interrupt is triggered twice + */ + if (start_triggered) + tfa98xx_interrupt_enable(tfa98xx, true); + mutex_unlock(&tfa98xx->dsp_lock); + } /* TFA98XX_FLAG_REMOVE_PLOP_NOISE */ + + if (tfa98xx->flags & TFA98XX_FLAG_LP_MODES) + tfa_lp_mode_interrupt(tfa98xx->tfa); + /* TFA98XX_FLAG_LP_MODES */ + + /* unmask interrupts masked in IRQ handler */ + tfa_irq_unmask(tfa98xx->tfa); +} + +static int tfa98xx_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + unsigned int sr; + int len, prof, nprof, idx = 0; + char *basename; + u64 formats; + int err; + + /* + * Support CODEC to CODEC links, + * these are called with a NULL runtime pointer. + */ + if (!substream->runtime) + return 0; + + if (pcm_no_constraint != 0) + return 0; + + switch (pcm_sample_format) { + case 1: + formats = SNDRV_PCM_FMTBIT_S24_LE; + break; + case 2: + formats = SNDRV_PCM_FMTBIT_S32_LE; + break; + default: + formats = SNDRV_PCM_FMTBIT_S16_LE; + break; + } + + err = snd_pcm_hw_constraint_mask64(substream->runtime, + SNDRV_PCM_HW_PARAM_FORMAT, formats); + if (err < 0) + return err; + + if (no_start != 0) + return 0; + + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) { + dev_info(codec->dev, "Container file not loaded\n"); + return -EINVAL; + } + + basename = kzalloc(MAX_CONTROL_NAME, GFP_KERNEL); + if (!basename) + return -ENOMEM; + + /* copy profile name into basename until the . */ + get_profile_basename(basename, + tfa_cont_profile_name(tfa98xx, tfa98xx->profile)); + len = strlen(basename); + + /* loop over all profiles and get the supported samples rate(s) from + * the profiles with the same basename + */ + nprof = tfa_cnt_get_dev_nprof(tfa98xx->tfa); + tfa98xx->rate_constraint.list = &tfa98xx->rate_constraint_list[0]; + tfa98xx->rate_constraint.count = 0; + for (prof = 0; prof < nprof; prof++) { + if (0 == strncmp(basename, tfa_cont_profile_name(tfa98xx, prof), + len)) { + /* Check which sample rate is supported with current profile, + * and enforce this. + */ + sr = tfa98xx_get_profile_sr(tfa98xx->tfa, prof); + if (!sr) + dev_info(codec->dev, "Unable to identify \ + supported sample rate\n"); + + if (tfa98xx->rate_constraint.count >= TFA98XX_NUM_RATES) { + dev_err(codec->dev, "too many sample rates\n"); + } else { + tfa98xx->rate_constraint_list[idx++] = sr; + tfa98xx->rate_constraint.count += 1; + } + } + } + + kfree(basename); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &tfa98xx->rate_constraint); +} + +static int tfa98xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec_dai->codec); + + tfa98xx->sysclk = freq; + return 0; +} + +static int tfa98xx_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + pr_debug("\n"); + return 0; +} + +static int tfa98xx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(dai->codec); + struct snd_soc_codec *codec = dai->codec; + + pr_debug("fmt=0x%x\n", fmt); + + /* Supported mode: regular I2S, slave, or PDM */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + dev_err(codec->dev, "Invalid Codec master mode\n"); + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_PDM: + break; + default: + dev_err(codec->dev, "Unsupported DAI format %d\n", + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + + tfa98xx->audio_mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + + return 0; +} + +static int tfa98xx_get_fssel(unsigned int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rate_to_fssel); i++) { + if (rate_to_fssel[i].rate == rate) + return rate_to_fssel[i].fssel; + } + return -EINVAL; +} + +static int tfa98xx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + unsigned int rate; + int prof_idx; + + /* Supported */ + rate = params_rate(params); + pr_debug("Requested rate: %d, sample size: %d, physical size: %d\n", + rate, snd_pcm_format_width(params_format(params)), + snd_pcm_format_physical_width(params_format(params))); + + if (no_start != 0) + return 0; + + /* check if samplerate is supported for this mixer profile */ + prof_idx = get_profile_id_for_sr(tfa98xx_mixer_profile, rate); + if (prof_idx < 0) { + pr_err("tfa98xx: invalid sample rate %d.\n", rate); + return -EINVAL; + } + pr_debug("mixer profile:container profile = [%d:%d]\n", + tfa98xx_mixer_profile, prof_idx); + + + /* update 'real' profile (container profile) */ + tfa98xx->profile = prof_idx; + + /* update to new rate */ + tfa98xx->rate = rate; + + return 0; +} + +static int tfa98xx_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_codec *codec = dai->codec; + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + + dev_dbg(&tfa98xx->i2c->dev, "%s: state: %d\n", __func__, mute); + + if (no_start) { + pr_debug("no_start parameter set no tfa_dev_start or tfa_dev_stop, returning\n"); + return 0; + } + + if (mute) { + /* stop DSP only when both playback and capture streams + * are deactivated + */ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + tfa98xx->pstream = 0; + else + tfa98xx->cstream = 0; + if (tfa98xx->pstream != 0 || tfa98xx->cstream != 0) + return 0; + + mutex_lock(&tfa98xx_mutex); + tfa98xx_sync_count = 0; + mutex_unlock(&tfa98xx_mutex); + + cancel_delayed_work_sync(&tfa98xx->monitor_work); + + cancel_delayed_work_sync(&tfa98xx->init_work); + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) + return 0; + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_stop(tfa98xx->tfa); + tfa98xx->dsp_init = TFA98XX_DSP_INIT_STOPPED; + mutex_unlock(&tfa98xx->dsp_lock); + } else { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + tfa98xx->pstream = 1; + else + tfa98xx->cstream = 1; + + /* Start DSP */ +#if 1 + if (tfa98xx->dsp_init != TFA98XX_DSP_INIT_PENDING) + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->init_work, 0); +#else + tfa98xx_dsp_init(tfa98xx); +#endif// + } + + return 0; +} + +static const struct snd_soc_dai_ops tfa98xx_dai_ops = { + .startup = tfa98xx_startup, + .set_fmt = tfa98xx_set_fmt, + .set_sysclk = tfa98xx_set_dai_sysclk, + .set_tdm_slot = tfa98xx_set_tdm_slot, + .hw_params = tfa98xx_hw_params, + .mute_stream = tfa98xx_mute, +}; + +static struct snd_soc_dai_driver tfa98xx_dai[] = { + { + .name = "tfa98xx-aif", + .id = 1, + .playback = { + .stream_name = "AIF Playback", + .channels_min = 1, + .channels_max = 4, + .rates = TFA98XX_RATES, + .formats = TFA98XX_FORMATS, + }, + .capture = { + .stream_name = "AIF Capture", + .channels_min = 1, + .channels_max = 4, + .rates = TFA98XX_RATES, + .formats = TFA98XX_FORMATS, + }, + .ops = &tfa98xx_dai_ops, + .symmetric_rates = 1, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) + .symmetric_channels = 1, + .symmetric_samplebits = 1, +#endif + }, +}; + +static int tfa98xx_probe(struct snd_soc_codec *codec) +{ + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + int ret; + + pr_debug("\n"); + + /* setup work queue, will be used to initial DSP on first boot up */ + tfa98xx->tfa98xx_wq = create_singlethread_workqueue("tfa98xx"); + if (!tfa98xx->tfa98xx_wq) + return -ENOMEM; + + INIT_DELAYED_WORK(&tfa98xx->init_work, tfa98xx_dsp_init_work); + INIT_DELAYED_WORK(&tfa98xx->monitor_work, tfa98xx_monitor); + INIT_DELAYED_WORK(&tfa98xx->interrupt_work, tfa98xx_interrupt); + INIT_DELAYED_WORK(&tfa98xx->tapdet_work, tfa98xx_tapdet_work); + + tfa98xx->codec = codec; + + ret = tfa98xx_load_container(tfa98xx); + pr_debug("Container loading requested: %d\n", ret); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) + codec->control_data = tfa98xx->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } +#endif + tfa98xx_add_widgets(tfa98xx); + + dev_info(codec->dev, "tfa98xx codec registered (%s)", + tfa98xx->fw.name); + + return ret; +} + +static int tfa98xx_remove(struct snd_soc_codec *codec) +{ + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + pr_debug("\n"); + + tfa98xx_interrupt_enable(tfa98xx, false); + + tfa98xx_inputdev_unregister(tfa98xx); + + cancel_delayed_work_sync(&tfa98xx->interrupt_work); + cancel_delayed_work_sync(&tfa98xx->monitor_work); + cancel_delayed_work_sync(&tfa98xx->init_work); + cancel_delayed_work_sync(&tfa98xx->tapdet_work); + + if (tfa98xx->tfa98xx_wq) + destroy_workqueue(tfa98xx->tfa98xx_wq); + + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) +static struct regmap *tfa98xx_get_regmap(struct device *dev) +{ + struct tfa98xx *tfa98xx = dev_get_drvdata(dev); + + return tfa98xx->regmap; +} +#endif +static struct snd_soc_codec_driver soc_codec_dev_tfa98xx = { + .probe = tfa98xx_probe, + .remove = tfa98xx_remove, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) + .get_regmap = tfa98xx_get_regmap, +#endif +}; + + +static bool tfa98xx_writeable_register(struct device *dev, unsigned int reg) +{ + /* enable read access for all registers */ + return 1; +} + +static bool tfa98xx_readable_register(struct device *dev, unsigned int reg) +{ + /* enable read access for all registers */ + return 1; +} + +static bool tfa98xx_volatile_register(struct device *dev, unsigned int reg) +{ + /* enable read access for all registers */ + return 1; +} + +static const struct regmap_config tfa98xx_regmap = { + .reg_bits = 8, + .val_bits = 16, + + .max_register = TFA98XX_MAX_REGISTER, + .writeable_reg = tfa98xx_writeable_register, + .readable_reg = tfa98xx_readable_register, + .volatile_reg = tfa98xx_volatile_register, + .cache_type = REGCACHE_NONE, +}; + +static void tfa98xx_irq_tfa2(struct tfa98xx *tfa98xx) +{ + pr_info("\n"); + + /* + * mask interrupts + * will be unmasked after handling interrupts in workqueue + */ + tfa_irq_mask(tfa98xx->tfa); + queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->interrupt_work, 0); +} + + +static irqreturn_t tfa98xx_irq(int irq, void *data) +{ + struct tfa98xx *tfa98xx = data; + + if (tfa98xx->tfa->tfa_family == 2) + tfa98xx_irq_tfa2(tfa98xx); + + return IRQ_HANDLED; +} + +static int tfa98xx_ext_reset(struct tfa98xx *tfa98xx) +{ + if (tfa98xx && gpio_is_valid(tfa98xx->reset_gpio)) { + int reset = tfa98xx->reset_polarity; + + gpio_set_value_cansleep(tfa98xx->reset_gpio, reset); + mdelay(1); + gpio_set_value_cansleep(tfa98xx->reset_gpio, !reset); + mdelay(1); + } + return 0; +} + +static int tfa98xx_parse_dt(struct device *dev, struct tfa98xx *tfa98xx, + struct device_node *np) { + u32 value; + int ret; + + tfa98xx->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (tfa98xx->reset_gpio < 0) + dev_dbg(dev, "No reset GPIO provided, will not HW reset device\n"); + + tfa98xx->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + if (tfa98xx->irq_gpio < 0) + dev_dbg(dev, "No IRQ GPIO provided.\n"); + ret = of_property_read_u32(np, "reset-polarity", &value); + if (ret < 0) + tfa98xx->reset_polarity = HIGH; + else + tfa98xx->reset_polarity = (value == 0) ? LOW : HIGH; + + dev_dbg(dev, "reset-polarity:%d\n", tfa98xx->reset_polarity); + return 0; +} + +static ssize_t tfa98xx_reg_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tfa98xx *tfa98xx = dev_get_drvdata(dev); + + if (count != 1) { + pr_debug("invalid register address"); + return -EINVAL; + } + + tfa98xx->reg = buf[0]; + + return 1; +} + +static ssize_t tfa98xx_rw_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tfa98xx *tfa98xx = dev_get_drvdata(dev); + u8 *data; + int ret; + int retries = I2C_RETRIES; + + data = kmalloc(count + 1, GFP_KERNEL); + if (!data) { + pr_debug("can not allocate memory\n"); + return -ENOMEM; + } + + data[0] = tfa98xx->reg; + memcpy(&data[1], buf, count); + +retry: + ret = i2c_master_send(tfa98xx->i2c, data, count + 1); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + } + + kfree(data); + + /* the number of data bytes written without the register address */ + return ((ret > 1) ? count : -EIO); +} + +static ssize_t tfa98xx_rw_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tfa98xx *tfa98xx = dev_get_drvdata(dev); + struct i2c_msg msgs[] = { + { + .addr = tfa98xx->i2c->addr, + .flags = 0, + .len = 1, + .buf = &tfa98xx->reg, + }, + { + .addr = tfa98xx->i2c->addr, + .flags = I2C_M_RD, + .len = count, + .buf = buf, + }, + }; + int ret; + int retries = I2C_RETRIES; +retry: + ret = i2c_transfer(tfa98xx->i2c->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + return ret; + } + /* ret contains the number of i2c transaction */ + /* return the number of bytes read */ + return ((ret > 1) ? count : -EIO); +} + +static struct bin_attribute dev_attr_rw = { + .attr = { + .name = "rw", + .mode = S_IRUSR | S_IWUSR, + }, + .size = 0, + .read = tfa98xx_rw_read, + .write = tfa98xx_rw_write, +}; + +static struct bin_attribute dev_attr_reg = { + .attr = { + .name = "reg", + .mode = S_IWUSR, + }, + .size = 0, + .read = NULL, + .write = tfa98xx_reg_write, +}; + +static int tfa98xx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct snd_soc_dai_driver *dai; + struct tfa98xx *tfa98xx; + struct device_node *np = i2c->dev.of_node; + int irq_flags; + unsigned int reg; + int ret; + + pr_info("addr=0x%x\n", i2c->addr); + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + dev_err(&i2c->dev, "check_functionality failed\n"); + return -EIO; + } + + tfa98xx = devm_kzalloc(&i2c->dev, sizeof(struct tfa98xx), GFP_KERNEL); + if (tfa98xx == NULL) + return -ENOMEM; + + tfa98xx->dev = &i2c->dev; + tfa98xx->i2c = i2c; + tfa98xx->dsp_init = TFA98XX_DSP_INIT_STOPPED; + tfa98xx->rate = 48000; /* init to the default sample rate (48kHz) */ + tfa98xx->tfa = NULL; + + tfa98xx->regmap = devm_regmap_init_i2c(i2c, &tfa98xx_regmap); + if (IS_ERR(tfa98xx->regmap)) { + ret = PTR_ERR(tfa98xx->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + i2c_set_clientdata(i2c, tfa98xx); + mutex_init(&tfa98xx->dsp_lock); + init_waitqueue_head(&tfa98xx->wq); + + if (np) { + ret = tfa98xx_parse_dt(&i2c->dev, tfa98xx, np); + if (ret) { + dev_err(&i2c->dev, "Failed to parse DT node\n"); + return ret; + } + if (no_start) + tfa98xx->irq_gpio = -1; + if (no_reset) + tfa98xx->reset_gpio = -1; + } else { + tfa98xx->reset_gpio = -1; + tfa98xx->irq_gpio = -1; + } + + if (gpio_is_valid(tfa98xx->reset_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, tfa98xx->reset_gpio, + GPIOF_OUT_INIT_LOW, "TFA98XX_RST"); + if (ret) + return ret; + } + + if (gpio_is_valid(tfa98xx->irq_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, tfa98xx->irq_gpio, + GPIOF_DIR_IN, "TFA98XX_INT"); + if (ret) + return ret; + } + + /* Power up! */ + tfa98xx_ext_reset(tfa98xx); + + if ((no_start == 0) && (no_reset == 0)) { + ret = regmap_read(tfa98xx->regmap, 0x03, ®); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to read Revision register: %d\n", + ret); + return -EIO; + } + switch (reg & 0xff) { + case 0x72: /* tfa9872 */ + pr_info("TFA9872 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_CALIBRATION_CTL; + tfa98xx->flags |= TFA98XX_FLAG_REMOVE_PLOP_NOISE; + /* tfa98xx->flags |= TFA98XX_FLAG_LP_MODES; */ + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + case 0x74: /* tfa9874 */ + pr_info("TFA9874 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_CALIBRATION_CTL; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + case 0x78: /* tfa9878 */ + pr_info("TFA9878 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_CALIBRATION_CTL; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + case 0x88: /* tfa9888 */ + pr_info("TFA9888 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_STEREO_DEVICE; + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + case 0x13: /* tfa9912 */ + pr_info("TFA9912 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + /* tfa98xx->flags |= TFA98XX_FLAG_TAPDET_AVAILABLE; */ + break; + case 0x94: /* tfa9894 */ + pr_info("TFA9894 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + case 0x80: /* tfa9890 */ + case 0x81: /* tfa9890 */ + pr_info("TFA9890 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + break; + case 0x92: /* tfa9891 */ + pr_info("TFA9891 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SAAM_AVAILABLE; + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + break; + case 0x12: /* tfa9895 */ + pr_info("TFA9895 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + break; + case 0x97: + pr_info("TFA9897 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + case 0x96: + pr_info("TFA9896 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + break; + default: + pr_info("Unsupported device revision (0x%x)\n", reg & 0xff); + return -EINVAL; + } + } + + tfa98xx->tfa = devm_kzalloc(&i2c->dev, sizeof(struct tfa_device), + GFP_KERNEL); + if (tfa98xx->tfa == NULL) + return -ENOMEM; + + tfa98xx->tfa->data = (void *)tfa98xx; + tfa98xx->tfa->cachep = tfa98xx_cache; + + /* Modify the stream names, by appending the i2c device address. + * This is used with multicodec, in order to discriminate the devices. + * Stream names appear in the dai definition and in the stream. + * We create copies of original structures because each device will + * have its own instance of this structure, with its own address. + */ + dai = devm_kzalloc(&i2c->dev, sizeof(tfa98xx_dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + memcpy(dai, tfa98xx_dai, sizeof(tfa98xx_dai)); + + tfa98xx_append_i2c_address(&i2c->dev, + i2c, + NULL, + 0, + dai, + ARRAY_SIZE(tfa98xx_dai)); + + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_tfa98xx, dai, + ARRAY_SIZE(tfa98xx_dai)); + + if (ret < 0) { + dev_err(&i2c->dev, "Failed to register TFA98xx: %d\n", ret); + return ret; + } + + if (gpio_is_valid(tfa98xx->irq_gpio) && + !(tfa98xx->flags & TFA98XX_FLAG_SKIP_INTERRUPTS)) { + /* register irq handler */ + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + ret = devm_request_threaded_irq(&i2c->dev, + gpio_to_irq(tfa98xx->irq_gpio), + NULL, tfa98xx_irq, irq_flags, + "tfa98xx", tfa98xx); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", + gpio_to_irq(tfa98xx->irq_gpio), ret); + return ret; + } + } else { + dev_info(&i2c->dev, "Skipping IRQ registration\n"); + /* disable feature support if gpio was invalid */ + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + } + +#ifdef CONFIG_DEBUG_FS + if (no_start == 0) + tfa98xx_debug_init(tfa98xx, i2c); +#endif + /* Register the sysfs files for climax backdoor access */ + ret = device_create_bin_file(&i2c->dev, &dev_attr_rw); + if (ret) + dev_info(&i2c->dev, "error creating sysfs files\n"); + ret = device_create_bin_file(&i2c->dev, &dev_attr_reg); + if (ret) + dev_info(&i2c->dev, "error creating sysfs files\n"); + + pr_info("%s Probe completed successfully!\n", __func__); + + INIT_LIST_HEAD(&tfa98xx->list); + + mutex_lock(&tfa98xx_mutex); + tfa98xx_device_count++; + list_add(&tfa98xx->list, &tfa98xx_device_list); + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static int tfa98xx_i2c_remove(struct i2c_client *i2c) +{ + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + + pr_debug("addr=0x%x\n", i2c->addr); + + tfa98xx_interrupt_enable(tfa98xx, false); + + cancel_delayed_work_sync(&tfa98xx->interrupt_work); + cancel_delayed_work_sync(&tfa98xx->monitor_work); + cancel_delayed_work_sync(&tfa98xx->init_work); + cancel_delayed_work_sync(&tfa98xx->tapdet_work); + + device_remove_bin_file(&i2c->dev, &dev_attr_reg); + device_remove_bin_file(&i2c->dev, &dev_attr_rw); +#ifdef CONFIG_DEBUG_FS + tfa98xx_debug_remove(tfa98xx); +#endif + + snd_soc_unregister_codec(&i2c->dev); + + if (gpio_is_valid(tfa98xx->irq_gpio)) + devm_gpio_free(&i2c->dev, tfa98xx->irq_gpio); + if (gpio_is_valid(tfa98xx->reset_gpio)) + devm_gpio_free(&i2c->dev, tfa98xx->reset_gpio); + + mutex_lock(&tfa98xx_mutex); + list_del(&tfa98xx->list); + tfa98xx_device_count--; + if (tfa98xx_device_count == 0) { + kfree(tfa98xx_container); + tfa98xx_container = NULL; + } + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static const struct i2c_device_id tfa98xx_i2c_id[] = { + { "tfa98xx", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tfa98xx_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id tfa98xx_dt_match[] = { + {.compatible = "nxp,tfa98xx" }, + {.compatible = "nxp,tfa9872" }, + {.compatible = "nxp,tfa9874" }, + {.compatible = "nxp,tfa9878" }, + {.compatible = "nxp,tfa9888" }, + {.compatible = "nxp,tfa9890" }, + {.compatible = "nxp,tfa9891" }, + {.compatible = "nxp,tfa9894" }, + {.compatible = "nxp,tfa9895" }, + {.compatible = "nxp,tfa9896" }, + {.compatible = "nxp,tfa9897" }, + {.compatible = "nxp,tfa9912" }, + { }, +}; +#endif + +static struct i2c_driver tfa98xx_i2c_driver = { + .driver = { + .name = "tfa98xx", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tfa98xx_dt_match), + }, + .probe = tfa98xx_i2c_probe, + .remove = tfa98xx_i2c_remove, + .id_table = tfa98xx_i2c_id, +}; + +static int __init tfa98xx_i2c_init(void) +{ + int ret = 0; + + pr_info("TFA98XX driver version %s\n", TFA98XX_VERSION); + + /* Enable debug traces */ + tfa98xx_kmsg_regs = trace_level & 2; + tfa98xx_ftrace_regs = trace_level & 4; + + /* Initialize kmem_cache */ + /* Cache name /proc/slabinfo */ + tfa98xx_cache = kmem_cache_create("tfa98xx_cache", + PAGE_SIZE, /* Structure size, we should fit in single page */ + 0, /* Structure alignment */ + (SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT | + SLAB_MEM_SPREAD), /* Cache property */ + NULL); /* Object constructor */ + if (!tfa98xx_cache) { + pr_err("tfa98xx can't create memory pool\n"); + ret = -ENOMEM; + } + + ret = i2c_add_driver(&tfa98xx_i2c_driver); + + return ret; +} +module_init(tfa98xx_i2c_init); + +static void __exit tfa98xx_i2c_exit(void) +{ + i2c_del_driver(&tfa98xx_i2c_driver); + kmem_cache_destroy(tfa98xx_cache); +} +module_exit(tfa98xx_i2c_exit); + +MODULE_DESCRIPTION("ASoC TFA98XX driver"); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/codecs/tfa98xx.h b/sound/soc/codecs/tfa98xx.h new file mode 100644 index 000000000000..3ba367ad8679 --- /dev/null +++ b/sound/soc/codecs/tfa98xx.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef __TFA98XX_INC__ +#define __TFA98XX_INC__ + +#include +#include +#include + +#include "tfa_device.h" +#include "tfa_container.h" +#include "config.h" + +/* max. length of a alsa mixer control name */ +#define MAX_CONTROL_NAME 48 + +#define TFA98XX_MAX_REGISTER 0xff + +#define TFA98XX_FLAG_SKIP_INTERRUPTS (1 << 0) +#define TFA98XX_FLAG_SAAM_AVAILABLE (1 << 1) +#define TFA98XX_FLAG_STEREO_DEVICE (1 << 2) +#define TFA98XX_FLAG_MULTI_MIC_INPUTS (1 << 3) +#define TFA98XX_FLAG_TAPDET_AVAILABLE (1 << 4) +#define TFA98XX_FLAG_CALIBRATION_CTL (1 << 5) +#define TFA98XX_FLAG_REMOVE_PLOP_NOISE (1 << 6) +#define TFA98XX_FLAG_LP_MODES (1 << 7) +#define TFA98XX_FLAG_TDM_DEVICE (1 << 8) + +#define TFA98XX_NUM_RATES 9 + +/* DSP init status */ +enum tfa98xx_dsp_init_state { + TFA98XX_DSP_INIT_STOPPED, /* DSP not running */ + TFA98XX_DSP_INIT_RECOVER, /* DSP error detected at runtime */ + TFA98XX_DSP_INIT_FAIL, /* DSP init failed */ + TFA98XX_DSP_INIT_PENDING, /* DSP start requested */ + TFA98XX_DSP_INIT_DONE, /* DSP running */ + TFA98XX_DSP_INIT_INVALIDATED, /* DSP was running, requires re-init */ +}; + +enum tfa98xx_dsp_fw_state { + TFA98XX_DSP_FW_NONE = 0, + TFA98XX_DSP_FW_PENDING, + TFA98XX_DSP_FW_FAIL, + TFA98XX_DSP_FW_OK, +}; + +struct tfa98xx_firmware { + void *base; + struct tfa98xx_device *dev; + char name[9]; //TODO get length from tfa parameter defs +}; + +struct tfa98xx_baseprofile { + char basename[MAX_CONTROL_NAME]; /* profile basename */ + int len; /* profile length */ + int item_id; /* profile id */ + int sr_rate_sup[TFA98XX_NUM_RATES]; /* sample rates supported by this profile */ + struct list_head list; /* list of all profiles */ +}; +enum tfa_reset_polarity{ + LOW = 0, + HIGH = 1 +}; +struct tfa98xx { + struct regmap *regmap; + struct i2c_client *i2c; + struct regulator *vdd; + struct snd_soc_codec *codec; + struct workqueue_struct *tfa98xx_wq; + struct delayed_work init_work; + struct delayed_work monitor_work; + struct delayed_work interrupt_work; + struct delayed_work tapdet_work; + struct mutex dsp_lock; + int dsp_init; + int dsp_fw_state; + int sysclk; + int rst_gpio; + u16 rev; + int audio_mode; + struct tfa98xx_firmware fw; + char *fw_name; + int rate; + wait_queue_head_t wq; + struct device *dev; + unsigned int init_count; + int pstream; + int cstream; + struct input_dev *input; + bool tapdet_enabled; /* service enabled */ + bool tapdet_open; /* device file opened */ + unsigned int tapdet_profiles; /* tapdet profile bitfield */ + bool tapdet_poll; /* tapdet running on polling mode */ + + unsigned int rate_constraint_list[TFA98XX_NUM_RATES]; + struct snd_pcm_hw_constraint_list rate_constraint; + + int reset_gpio; + int power_gpio; + int irq_gpio; + enum tfa_reset_polarity reset_polarity; + struct list_head list; + struct tfa_device *tfa; + int vstep; + int profile; + int prof_vsteps[TFACONT_MAXPROFS]; /* store vstep per profile (single device) */ + +#ifdef CONFIG_DEBUG_FS + struct dentry *dbg_dir; +#endif + u8 reg; + unsigned int flags; + bool set_mtp_cal; + uint16_t cal_data; +}; + + +#endif /* __TFA98XX_INC__ */ + diff --git a/sound/soc/codecs/tfa98xx_genregs_N1C.h b/sound/soc/codecs/tfa98xx_genregs_N1C.h new file mode 100644 index 000000000000..eb1e1ad581b4 --- /dev/null +++ b/sound/soc/codecs/tfa98xx_genregs_N1C.h @@ -0,0 +1,3857 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA2_GENREGS_H +#define TFA2_GENREGS_H + + +#define TFA98XX_SYS_CONTROL0 0x00 +#define TFA98XX_SYS_CONTROL1 0x01 +#define TFA98XX_SYS_CONTROL2 0x02 +#define TFA98XX_DEVICE_REVISION 0x03 +#define TFA98XX_CLOCK_CONTROL 0x04 +#define TFA98XX_CLOCK_GATING_CONTROL 0x05 +#define TFA98XX_SIDE_TONE_CONFIG 0x0d +#define TFA98XX_CTRL_DIGTOANA_REG 0x0e +#define TFA98XX_STATUS_FLAGS0 0x10 +#define TFA98XX_STATUS_FLAGS1 0x11 +#define TFA98XX_STATUS_FLAGS2 0x12 +#define TFA98XX_STATUS_FLAGS3 0x13 +#define TFA98XX_STATUS_FLAGS4 0x14 +#define TFA98XX_BATTERY_VOLTAGE 0x15 +#define TFA98XX_TEMPERATURE 0x16 +#define TFA98XX_TDM_CONFIG0 0x20 +#define TFA98XX_TDM_CONFIG1 0x21 +#define TFA98XX_TDM_CONFIG2 0x22 +#define TFA98XX_TDM_CONFIG3 0x23 +#define TFA98XX_TDM_CONFIG4 0x24 +#define TFA98XX_TDM_CONFIG5 0x25 +#define TFA98XX_TDM_CONFIG6 0x26 +#define TFA98XX_TDM_CONFIG7 0x27 +#define TFA98XX_TDM_CONFIG8 0x28 +#define TFA98XX_TDM_CONFIG9 0x29 +#define TFA98XX_PDM_CONFIG0 0x31 +#define TFA98XX_PDM_CONFIG1 0x32 +#define TFA98XX_HAPTIC_DRIVER_CONFIG 0x33 +#define TFA98XX_GPIO_DATAIN_REG 0x34 +#define TFA98XX_GPIO_CONFIG 0x35 +#define TFA98XX_INTERRUPT_OUT_REG1 0x40 +#define TFA98XX_INTERRUPT_OUT_REG2 0x41 +#define TFA98XX_INTERRUPT_OUT_REG3 0x42 +#define TFA98XX_INTERRUPT_IN_REG1 0x44 +#define TFA98XX_INTERRUPT_IN_REG2 0x45 +#define TFA98XX_INTERRUPT_IN_REG3 0x46 +#define TFA98XX_INTERRUPT_ENABLE_REG1 0x48 +#define TFA98XX_INTERRUPT_ENABLE_REG2 0x49 +#define TFA98XX_INTERRUPT_ENABLE_REG3 0x4a +#define TFA98XX_STATUS_POLARITY_REG1 0x4c +#define TFA98XX_STATUS_POLARITY_REG2 0x4d +#define TFA98XX_STATUS_POLARITY_REG3 0x4e +#define TFA98XX_BAT_PROT_CONFIG 0x50 +#define TFA98XX_AUDIO_CONTROL 0x51 +#define TFA98XX_AMPLIFIER_CONFIG 0x52 +#define TFA98XX_AUDIO_CONTROL2 0x5a +#define TFA98XX_DCDC_CONTROL0 0x70 +#define TFA98XX_CF_CONTROLS 0x90 +#define TFA98XX_CF_MAD 0x91 +#define TFA98XX_CF_MEM 0x92 +#define TFA98XX_CF_STATUS 0x93 +#define TFA98XX_MTPKEY2_REG 0xa1 +#define TFA98XX_MTP_STATUS 0xa2 +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL 0xa3 +#define TFA98XX_MTP_DATA_OUT_MSB 0xa5 +#define TFA98XX_MTP_DATA_OUT_LSB 0xa6 +#define TFA98XX_TEMP_SENSOR_CONFIG 0xb1 +#define TFA98XX_KEY2_PROTECTED_MTP0 0xf0 +#define TFA98XX_KEY1_PROTECTED_MTP4 0xf4 +#define TFA98XX_KEY1_PROTECTED_MTP5 0xf5 + +/* + * (0x00)-sys_control0 + */ + +/* + * powerdown + */ +#define TFA98XX_SYS_CONTROL0_PWDN (0x1<<0) +#define TFA98XX_SYS_CONTROL0_PWDN_POS 0 +#define TFA98XX_SYS_CONTROL0_PWDN_LEN 1 +#define TFA98XX_SYS_CONTROL0_PWDN_MAX 1 +#define TFA98XX_SYS_CONTROL0_PWDN_MSK 0x1 + +/* + * reset + */ +#define TFA98XX_SYS_CONTROL0_I2CR (0x1<<1) +#define TFA98XX_SYS_CONTROL0_I2CR_POS 1 +#define TFA98XX_SYS_CONTROL0_I2CR_LEN 1 +#define TFA98XX_SYS_CONTROL0_I2CR_MAX 1 +#define TFA98XX_SYS_CONTROL0_I2CR_MSK 0x2 + +/* + * enbl_coolflux + */ +#define TFA98XX_SYS_CONTROL0_CFE (0x1<<2) +#define TFA98XX_SYS_CONTROL0_CFE_POS 2 +#define TFA98XX_SYS_CONTROL0_CFE_LEN 1 +#define TFA98XX_SYS_CONTROL0_CFE_MAX 1 +#define TFA98XX_SYS_CONTROL0_CFE_MSK 0x4 + +/* + * enbl_amplifier + */ +#define TFA98XX_SYS_CONTROL0_AMPE (0x1<<3) +#define TFA98XX_SYS_CONTROL0_AMPE_POS 3 +#define TFA98XX_SYS_CONTROL0_AMPE_LEN 1 +#define TFA98XX_SYS_CONTROL0_AMPE_MAX 1 +#define TFA98XX_SYS_CONTROL0_AMPE_MSK 0x8 + +/* + * enbl_boost + */ +#define TFA98XX_SYS_CONTROL0_DCA (0x1<<4) +#define TFA98XX_SYS_CONTROL0_DCA_POS 4 +#define TFA98XX_SYS_CONTROL0_DCA_LEN 1 +#define TFA98XX_SYS_CONTROL0_DCA_MAX 1 +#define TFA98XX_SYS_CONTROL0_DCA_MSK 0x10 + +/* + * coolflux_configured + */ +#define TFA98XX_SYS_CONTROL0_SBSL (0x1<<5) +#define TFA98XX_SYS_CONTROL0_SBSL_POS 5 +#define TFA98XX_SYS_CONTROL0_SBSL_LEN 1 +#define TFA98XX_SYS_CONTROL0_SBSL_MAX 1 +#define TFA98XX_SYS_CONTROL0_SBSL_MSK 0x20 + +/* + * sel_enbl_amplifier + */ +#define TFA98XX_SYS_CONTROL0_AMPC (0x1<<6) +#define TFA98XX_SYS_CONTROL0_AMPC_POS 6 +#define TFA98XX_SYS_CONTROL0_AMPC_LEN 1 +#define TFA98XX_SYS_CONTROL0_AMPC_MAX 1 +#define TFA98XX_SYS_CONTROL0_AMPC_MSK 0x40 + +/* + * int_pad_io + */ +#define TFA98XX_SYS_CONTROL0_INTP (0x3<<7) +#define TFA98XX_SYS_CONTROL0_INTP_POS 7 +#define TFA98XX_SYS_CONTROL0_INTP_LEN 2 +#define TFA98XX_SYS_CONTROL0_INTP_MAX 3 +#define TFA98XX_SYS_CONTROL0_INTP_MSK 0x180 + +/* + * fs_pulse_sel + */ +#define TFA98XX_SYS_CONTROL0_FSSSEL (0x3<<9) +#define TFA98XX_SYS_CONTROL0_FSSSEL_POS 9 +#define TFA98XX_SYS_CONTROL0_FSSSEL_LEN 2 +#define TFA98XX_SYS_CONTROL0_FSSSEL_MAX 3 +#define TFA98XX_SYS_CONTROL0_FSSSEL_MSK 0x600 + +/* + * bypass_ocp + */ +#define TFA98XX_SYS_CONTROL0_BYPOCP (0x1<<11) +#define TFA98XX_SYS_CONTROL0_BYPOCP_POS 11 +#define TFA98XX_SYS_CONTROL0_BYPOCP_LEN 1 +#define TFA98XX_SYS_CONTROL0_BYPOCP_MAX 1 +#define TFA98XX_SYS_CONTROL0_BYPOCP_MSK 0x800 + +/* + * test_ocp + */ +#define TFA98XX_SYS_CONTROL0_TSTOCP (0x1<<12) +#define TFA98XX_SYS_CONTROL0_TSTOCP_POS 12 +#define TFA98XX_SYS_CONTROL0_TSTOCP_LEN 1 +#define TFA98XX_SYS_CONTROL0_TSTOCP_MAX 1 +#define TFA98XX_SYS_CONTROL0_TSTOCP_MSK 0x1000 + + +/* + * (0x01)-sys_control1 + */ + +/* + * vamp_sel + */ +#define TFA98XX_SYS_CONTROL1_AMPINSEL (0x3<<0) +#define TFA98XX_SYS_CONTROL1_AMPINSEL_POS 0 +#define TFA98XX_SYS_CONTROL1_AMPINSEL_LEN 2 +#define TFA98XX_SYS_CONTROL1_AMPINSEL_MAX 3 +#define TFA98XX_SYS_CONTROL1_AMPINSEL_MSK 0x3 + +/* + * src_set_configured + */ +#define TFA98XX_SYS_CONTROL1_MANSCONF (0x1<<2) +#define TFA98XX_SYS_CONTROL1_MANSCONF_POS 2 +#define TFA98XX_SYS_CONTROL1_MANSCONF_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANSCONF_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANSCONF_MSK 0x4 + +/* + * execute_cold_start + */ +#define TFA98XX_SYS_CONTROL1_MANCOLD (0x1<<3) +#define TFA98XX_SYS_CONTROL1_MANCOLD_POS 3 +#define TFA98XX_SYS_CONTROL1_MANCOLD_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANCOLD_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANCOLD_MSK 0x8 + +/* + * enbl_osc1m_auto_off + */ +#define TFA98XX_SYS_CONTROL1_MANAOOSC (0x1<<4) +#define TFA98XX_SYS_CONTROL1_MANAOOSC_POS 4 +#define TFA98XX_SYS_CONTROL1_MANAOOSC_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANAOOSC_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANAOOSC_MSK 0x10 + +/* + * man_enbl_brown_out + */ +#define TFA98XX_SYS_CONTROL1_MANROBOD (0x1<<5) +#define TFA98XX_SYS_CONTROL1_MANROBOD_POS 5 +#define TFA98XX_SYS_CONTROL1_MANROBOD_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANROBOD_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANROBOD_MSK 0x20 + +/* + * enbl_bod + */ +#define TFA98XX_SYS_CONTROL1_BODE (0x1<<6) +#define TFA98XX_SYS_CONTROL1_BODE_POS 6 +#define TFA98XX_SYS_CONTROL1_BODE_LEN 1 +#define TFA98XX_SYS_CONTROL1_BODE_MAX 1 +#define TFA98XX_SYS_CONTROL1_BODE_MSK 0x40 + +/* + * enbl_bod_hyst + */ +#define TFA98XX_SYS_CONTROL1_BODHYS (0x1<<7) +#define TFA98XX_SYS_CONTROL1_BODHYS_POS 7 +#define TFA98XX_SYS_CONTROL1_BODHYS_LEN 1 +#define TFA98XX_SYS_CONTROL1_BODHYS_MAX 1 +#define TFA98XX_SYS_CONTROL1_BODHYS_MSK 0x80 + +/* + * bod_delay + */ +#define TFA98XX_SYS_CONTROL1_BODFILT (0x3<<8) +#define TFA98XX_SYS_CONTROL1_BODFILT_POS 8 +#define TFA98XX_SYS_CONTROL1_BODFILT_LEN 2 +#define TFA98XX_SYS_CONTROL1_BODFILT_MAX 3 +#define TFA98XX_SYS_CONTROL1_BODFILT_MSK 0x300 + +/* + * bod_lvlsel + */ +#define TFA98XX_SYS_CONTROL1_BODTHLVL (0x3<<10) +#define TFA98XX_SYS_CONTROL1_BODTHLVL_POS 10 +#define TFA98XX_SYS_CONTROL1_BODTHLVL_LEN 2 +#define TFA98XX_SYS_CONTROL1_BODTHLVL_MAX 3 +#define TFA98XX_SYS_CONTROL1_BODTHLVL_MSK 0xc00 + +/* + * disable_mute_time_out + */ +#define TFA98XX_SYS_CONTROL1_MUTETO (0x1<<13) +#define TFA98XX_SYS_CONTROL1_MUTETO_POS 13 +#define TFA98XX_SYS_CONTROL1_MUTETO_LEN 1 +#define TFA98XX_SYS_CONTROL1_MUTETO_MAX 1 +#define TFA98XX_SYS_CONTROL1_MUTETO_MSK 0x2000 + +/* + * pwm_sel_rcv_ns + */ +#define TFA98XX_SYS_CONTROL1_RCVNS (0x1<<14) +#define TFA98XX_SYS_CONTROL1_RCVNS_POS 14 +#define TFA98XX_SYS_CONTROL1_RCVNS_LEN 1 +#define TFA98XX_SYS_CONTROL1_RCVNS_MAX 1 +#define TFA98XX_SYS_CONTROL1_RCVNS_MSK 0x4000 + +/* + * man_enbl_watchdog + */ +#define TFA98XX_SYS_CONTROL1_MANWDE (0x1<<15) +#define TFA98XX_SYS_CONTROL1_MANWDE_POS 15 +#define TFA98XX_SYS_CONTROL1_MANWDE_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANWDE_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANWDE_MSK 0x8000 + + +/* + * (0x02)-sys_control2 + */ + +/* + * audio_fs + */ +#define TFA98XX_SYS_CONTROL2_AUDFS (0xf<<0) +#define TFA98XX_SYS_CONTROL2_AUDFS_POS 0 +#define TFA98XX_SYS_CONTROL2_AUDFS_LEN 4 +#define TFA98XX_SYS_CONTROL2_AUDFS_MAX 15 +#define TFA98XX_SYS_CONTROL2_AUDFS_MSK 0xf + +/* + * input_level + */ +#define TFA98XX_SYS_CONTROL2_INPLEV (0x1<<4) +#define TFA98XX_SYS_CONTROL2_INPLEV_POS 4 +#define TFA98XX_SYS_CONTROL2_INPLEV_LEN 1 +#define TFA98XX_SYS_CONTROL2_INPLEV_MAX 1 +#define TFA98XX_SYS_CONTROL2_INPLEV_MSK 0x10 + +/* + * cs_frac_delay + */ +#define TFA98XX_SYS_CONTROL2_FRACTDEL (0x3f<<5) +#define TFA98XX_SYS_CONTROL2_FRACTDEL_POS 5 +#define TFA98XX_SYS_CONTROL2_FRACTDEL_LEN 6 +#define TFA98XX_SYS_CONTROL2_FRACTDEL_MAX 63 +#define TFA98XX_SYS_CONTROL2_FRACTDEL_MSK 0x7e0 + +/* + * bypass_hvbat_filter + */ +#define TFA98XX_SYS_CONTROL2_BYPHVBF (0x1<<11) +#define TFA98XX_SYS_CONTROL2_BYPHVBF_POS 11 +#define TFA98XX_SYS_CONTROL2_BYPHVBF_LEN 1 +#define TFA98XX_SYS_CONTROL2_BYPHVBF_MAX 1 +#define TFA98XX_SYS_CONTROL2_BYPHVBF_MSK 0x800 + +/* + * ctrl_rcvldop_bypass + */ +#define TFA98XX_SYS_CONTROL2_LDOBYP (0x1<<12) +#define TFA98XX_SYS_CONTROL2_LDOBYP_POS 12 +#define TFA98XX_SYS_CONTROL2_LDOBYP_LEN 1 +#define TFA98XX_SYS_CONTROL2_LDOBYP_MAX 1 +#define TFA98XX_SYS_CONTROL2_LDOBYP_MSK 0x1000 + + +/* + * (0x03)-device_revision + */ + +/* + * device_rev + */ +#define TFA98XX_DEVICE_REVISION_REV (0xffff<<0) +#define TFA98XX_DEVICE_REVISION_REV_POS 0 +#define TFA98XX_DEVICE_REVISION_REV_LEN 16 +#define TFA98XX_DEVICE_REVISION_REV_MAX 65535 +#define TFA98XX_DEVICE_REVISION_REV_MSK 0xffff + + +/* + * (0x04)-clock_control + */ + +/* + * pll_clkin_sel + */ +#define TFA98XX_CLOCK_CONTROL_REFCKEXT (0x3<<0) +#define TFA98XX_CLOCK_CONTROL_REFCKEXT_POS 0 +#define TFA98XX_CLOCK_CONTROL_REFCKEXT_LEN 2 +#define TFA98XX_CLOCK_CONTROL_REFCKEXT_MAX 3 +#define TFA98XX_CLOCK_CONTROL_REFCKEXT_MSK 0x3 + +/* + * pll_clkin_sel_osc + */ +#define TFA98XX_CLOCK_CONTROL_REFCKSEL (0x1<<2) +#define TFA98XX_CLOCK_CONTROL_REFCKSEL_POS 2 +#define TFA98XX_CLOCK_CONTROL_REFCKSEL_LEN 1 +#define TFA98XX_CLOCK_CONTROL_REFCKSEL_MAX 1 +#define TFA98XX_CLOCK_CONTROL_REFCKSEL_MSK 0x4 + + +/* + * (0x05)-clock_gating_control + */ + +/* + * enbl_spkr_ss_left + */ +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE (0x1<<0) +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE_POS 0 +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE_MSK 0x1 + +/* + * enbl_spkr_ss_right + */ +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE (0x1<<1) +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE_POS 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE_MSK 0x2 + +/* + * enbl_volsense_left + */ +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE (0x1<<2) +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE_POS 2 +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE_MSK 0x4 + +/* + * enbl_volsense_right + */ +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE (0x1<<3) +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE_POS 3 +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE_MSK 0x8 + +/* + * enbl_cursense_left + */ +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE (0x1<<4) +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE_POS 4 +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE_MSK 0x10 + +/* + * enbl_cursense_right + */ +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE (0x1<<5) +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE_POS 5 +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE_MSK 0x20 + +/* + * enbl_pdm_ss + */ +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME (0x1<<6) +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME_POS 6 +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME_MSK 0x40 + + +/* + * (0x0d)-side_tone_config + */ + +/* + * side_tone_gain + */ +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN (0x1ff<<1) +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN_POS 1 +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN_LEN 9 +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN_MAX 511 +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN_MSK 0x3fe + +/* + * mute_side_tone + */ +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE (0x1<<10) +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE_POS 10 +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE_LEN 1 +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE_MAX 1 +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE_MSK 0x400 + + +/* + * (0x0e)-ctrl_digtoana_reg + */ + +/* + * ctrl_digtoana + */ +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP (0x7f<<0) +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP_POS 0 +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP_LEN 7 +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP_MAX 127 +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP_MSK 0x7f + + +/* + * (0x10)-status_flags0 + */ + +/* + * flag_por + */ +#define TFA98XX_STATUS_FLAGS0_VDDS (0x1<<0) +#define TFA98XX_STATUS_FLAGS0_VDDS_POS 0 +#define TFA98XX_STATUS_FLAGS0_VDDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_VDDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_VDDS_MSK 0x1 + +/* + * flag_pll_lock + */ +#define TFA98XX_STATUS_FLAGS0_PLLS (0x1<<1) +#define TFA98XX_STATUS_FLAGS0_PLLS_POS 1 +#define TFA98XX_STATUS_FLAGS0_PLLS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_PLLS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_PLLS_MSK 0x2 + +/* + * flag_otpok + */ +#define TFA98XX_STATUS_FLAGS0_OTDS (0x1<<2) +#define TFA98XX_STATUS_FLAGS0_OTDS_POS 2 +#define TFA98XX_STATUS_FLAGS0_OTDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_OTDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_OTDS_MSK 0x4 + +/* + * flag_ovpok + */ +#define TFA98XX_STATUS_FLAGS0_OVDS (0x1<<3) +#define TFA98XX_STATUS_FLAGS0_OVDS_POS 3 +#define TFA98XX_STATUS_FLAGS0_OVDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_OVDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_OVDS_MSK 0x8 + +/* + * flag_uvpok + */ +#define TFA98XX_STATUS_FLAGS0_UVDS (0x1<<4) +#define TFA98XX_STATUS_FLAGS0_UVDS_POS 4 +#define TFA98XX_STATUS_FLAGS0_UVDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_UVDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_UVDS_MSK 0x10 + +/* + * flag_clocks_stable + */ +#define TFA98XX_STATUS_FLAGS0_CLKS (0x1<<6) +#define TFA98XX_STATUS_FLAGS0_CLKS_POS 5 +#define TFA98XX_STATUS_FLAGS0_CLKS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_CLKS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_CLKS_MSK 0x20 + +/* + * flag_mtp_busy + */ +#define TFA98XX_STATUS_FLAGS0_MTPB (0x1<<6) +#define TFA98XX_STATUS_FLAGS0_MTPB_POS 6 +#define TFA98XX_STATUS_FLAGS0_MTPB_LEN 1 +#define TFA98XX_STATUS_FLAGS0_MTPB_MAX 1 +#define TFA98XX_STATUS_FLAGS0_MTPB_MSK 0x40 + +/* + * flag_lost_clk + */ +#define TFA98XX_STATUS_FLAGS0_NOCLK (0x1<<7) +#define TFA98XX_STATUS_FLAGS0_NOCLK_POS 7 +#define TFA98XX_STATUS_FLAGS0_NOCLK_LEN 1 +#define TFA98XX_STATUS_FLAGS0_NOCLK_MAX 1 +#define TFA98XX_STATUS_FLAGS0_NOCLK_MSK 0x80 + +/* + * flag_cf_speakererror + */ +#define TFA98XX_STATUS_FLAGS0_SPKS (0x1<<8) +#define TFA98XX_STATUS_FLAGS0_SPKS_POS 8 +#define TFA98XX_STATUS_FLAGS0_SPKS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_SPKS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_SPKS_MSK 0x100 + +/* + * flag_cold_started + */ +#define TFA98XX_STATUS_FLAGS0_ACS (0x1<<9) +#define TFA98XX_STATUS_FLAGS0_ACS_POS 9 +#define TFA98XX_STATUS_FLAGS0_ACS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_ACS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_ACS_MSK 0x200 + +/* + * flag_engage + */ +#define TFA98XX_STATUS_FLAGS0_SWS (0x1<<10) +#define TFA98XX_STATUS_FLAGS0_SWS_POS 10 +#define TFA98XX_STATUS_FLAGS0_SWS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_SWS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_SWS_MSK 0x400 + +/* + * flag_watchdog_reset + */ +#define TFA98XX_STATUS_FLAGS0_WDS (0x1<<11) +#define TFA98XX_STATUS_FLAGS0_WDS_POS 11 +#define TFA98XX_STATUS_FLAGS0_WDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_WDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_WDS_MSK 0x800 + +/* + * flag_enbl_amp + */ +#define TFA98XX_STATUS_FLAGS0_AMPS (0x1<<12) +#define TFA98XX_STATUS_FLAGS0_AMPS_POS 12 +#define TFA98XX_STATUS_FLAGS0_AMPS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_AMPS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_AMPS_MSK 0x1000 + +/* + * flag_enbl_ref + */ +#define TFA98XX_STATUS_FLAGS0_AREFS (0x1<<13) +#define TFA98XX_STATUS_FLAGS0_AREFS_POS 13 +#define TFA98XX_STATUS_FLAGS0_AREFS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_AREFS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_AREFS_MSK 0x2000 + +/* + * flag_adc10_ready + */ +#define TFA98XX_STATUS_FLAGS0_ADCCR (0x1<<14) +#define TFA98XX_STATUS_FLAGS0_ADCCR_POS 14 +#define TFA98XX_STATUS_FLAGS0_ADCCR_LEN 1 +#define TFA98XX_STATUS_FLAGS0_ADCCR_MAX 1 +#define TFA98XX_STATUS_FLAGS0_ADCCR_MSK 0x4000 + +/* + * flag_bod_vddd_nok + */ +#define TFA98XX_STATUS_FLAGS0_BODNOK (0x1<<15) +#define TFA98XX_STATUS_FLAGS0_BODNOK_POS 15 +#define TFA98XX_STATUS_FLAGS0_BODNOK_LEN 1 +#define TFA98XX_STATUS_FLAGS0_BODNOK_MAX 1 +#define TFA98XX_STATUS_FLAGS0_BODNOK_MSK 0x8000 + + +/* + * (0x11)-status_flags1 + */ + +/* + * flag_bst_bstcur + */ +#define TFA98XX_STATUS_FLAGS1_DCIL (0x1<<0) +#define TFA98XX_STATUS_FLAGS1_DCIL_POS 0 +#define TFA98XX_STATUS_FLAGS1_DCIL_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCIL_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCIL_MSK 0x1 + +/* + * flag_bst_hiz + */ +#define TFA98XX_STATUS_FLAGS1_DCDCA (0x1<<1) +#define TFA98XX_STATUS_FLAGS1_DCDCA_POS 1 +#define TFA98XX_STATUS_FLAGS1_DCDCA_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCDCA_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCDCA_MSK 0x2 + +/* + * flag_bst_ocpok + */ +#define TFA98XX_STATUS_FLAGS1_DCOCPOK (0x1<<2) +#define TFA98XX_STATUS_FLAGS1_DCOCPOK_POS 2 +#define TFA98XX_STATUS_FLAGS1_DCOCPOK_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCOCPOK_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCOCPOK_MSK 0x4 + +/* + * flag_bst_voutcomp + */ +#define TFA98XX_STATUS_FLAGS1_DCHVBAT (0x1<<4) +#define TFA98XX_STATUS_FLAGS1_DCHVBAT_POS 4 +#define TFA98XX_STATUS_FLAGS1_DCHVBAT_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCHVBAT_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCHVBAT_MSK 0x10 + +/* + * flag_bst_voutcomp86 + */ +#define TFA98XX_STATUS_FLAGS1_DCH114 (0x1<<5) +#define TFA98XX_STATUS_FLAGS1_DCH114_POS 5 +#define TFA98XX_STATUS_FLAGS1_DCH114_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCH114_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCH114_MSK 0x20 + +/* + * flag_bst_voutcomp93 + */ +#define TFA98XX_STATUS_FLAGS1_DCH107 (0x1<<6) +#define TFA98XX_STATUS_FLAGS1_DCH107_POS 6 +#define TFA98XX_STATUS_FLAGS1_DCH107_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCH107_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCH107_MSK 0x40 + +/* + * flag_soft_mute_busy + */ +#define TFA98XX_STATUS_FLAGS1_STMUTEB (0x1<<7) +#define TFA98XX_STATUS_FLAGS1_STMUTEB_POS 7 +#define TFA98XX_STATUS_FLAGS1_STMUTEB_LEN 1 +#define TFA98XX_STATUS_FLAGS1_STMUTEB_MAX 1 +#define TFA98XX_STATUS_FLAGS1_STMUTEB_MSK 0x80 + +/* + * flag_soft_mute_state + */ +#define TFA98XX_STATUS_FLAGS1_STMUTE (0x1<<8) +#define TFA98XX_STATUS_FLAGS1_STMUTE_POS 8 +#define TFA98XX_STATUS_FLAGS1_STMUTE_LEN 1 +#define TFA98XX_STATUS_FLAGS1_STMUTE_MAX 1 +#define TFA98XX_STATUS_FLAGS1_STMUTE_MSK 0x100 + +/* + * flag_tdm_lut_error + */ +#define TFA98XX_STATUS_FLAGS1_TDMLUTER (0x1<<9) +#define TFA98XX_STATUS_FLAGS1_TDMLUTER_POS 9 +#define TFA98XX_STATUS_FLAGS1_TDMLUTER_LEN 1 +#define TFA98XX_STATUS_FLAGS1_TDMLUTER_MAX 1 +#define TFA98XX_STATUS_FLAGS1_TDMLUTER_MSK 0x200 + +/* + * flag_tdm_status + */ +#define TFA98XX_STATUS_FLAGS1_TDMSTAT (0x7<<10) +#define TFA98XX_STATUS_FLAGS1_TDMSTAT_POS 10 +#define TFA98XX_STATUS_FLAGS1_TDMSTAT_LEN 3 +#define TFA98XX_STATUS_FLAGS1_TDMSTAT_MAX 7 +#define TFA98XX_STATUS_FLAGS1_TDMSTAT_MSK 0x1c00 + +/* + * flag_tdm_error + */ +#define TFA98XX_STATUS_FLAGS1_TDMERR (0x1<<13) +#define TFA98XX_STATUS_FLAGS1_TDMERR_POS 13 +#define TFA98XX_STATUS_FLAGS1_TDMERR_LEN 1 +#define TFA98XX_STATUS_FLAGS1_TDMERR_MAX 1 +#define TFA98XX_STATUS_FLAGS1_TDMERR_MSK 0x2000 + +/* + * flag_haptic_busy + */ +#define TFA98XX_STATUS_FLAGS1_HAPTIC (0x1<<14) +#define TFA98XX_STATUS_FLAGS1_HAPTIC_POS 14 +#define TFA98XX_STATUS_FLAGS1_HAPTIC_LEN 1 +#define TFA98XX_STATUS_FLAGS1_HAPTIC_MAX 1 +#define TFA98XX_STATUS_FLAGS1_HAPTIC_MSK 0x4000 + + +/* + * (0x12)-status_flags2 + */ + +/* + * flag_ocpokap_left + */ +#define TFA98XX_STATUS_FLAGS2_OCPOAPL (0x1<<0) +#define TFA98XX_STATUS_FLAGS2_OCPOAPL_POS 0 +#define TFA98XX_STATUS_FLAGS2_OCPOAPL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOAPL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOAPL_MSK 0x1 + +/* + * flag_ocpokan_left + */ +#define TFA98XX_STATUS_FLAGS2_OCPOANL (0x1<<1) +#define TFA98XX_STATUS_FLAGS2_OCPOANL_POS 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANL_MSK 0x2 + +/* + * flag_ocpokbp_left + */ +#define TFA98XX_STATUS_FLAGS2_OCPOBPL (0x1<<2) +#define TFA98XX_STATUS_FLAGS2_OCPOBPL_POS 2 +#define TFA98XX_STATUS_FLAGS2_OCPOBPL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBPL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBPL_MSK 0x4 + +/* + * flag_ocpokbn_left + */ +#define TFA98XX_STATUS_FLAGS2_OCPOBNL (0x1<<3) +#define TFA98XX_STATUS_FLAGS2_OCPOBNL_POS 3 +#define TFA98XX_STATUS_FLAGS2_OCPOBNL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBNL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBNL_MSK 0x8 + +/* + * flag_clipa_high_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPAHL (0x1<<4) +#define TFA98XX_STATUS_FLAGS2_CLIPAHL_POS 4 +#define TFA98XX_STATUS_FLAGS2_CLIPAHL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPAHL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPAHL_MSK 0x10 + +/* + * flag_clipa_low_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPALL (0x1<<5) +#define TFA98XX_STATUS_FLAGS2_CLIPALL_POS 5 +#define TFA98XX_STATUS_FLAGS2_CLIPALL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPALL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPALL_MSK 0x20 + +/* + * flag_clipb_high_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPBHL (0x1<<6) +#define TFA98XX_STATUS_FLAGS2_CLIPBHL_POS 6 +#define TFA98XX_STATUS_FLAGS2_CLIPBHL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPBHL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPBHL_MSK 0x40 + +/* + * flag_clipb_low_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPBLL (0x1<<7) +#define TFA98XX_STATUS_FLAGS2_CLIPBLL_POS 7 +#define TFA98XX_STATUS_FLAGS2_CLIPBLL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPBLL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPBLL_MSK 0x80 + +/* + * flag_ocpokap_rcv + */ +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC (0x1<<8) +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC_POS 8 +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC_MSK 0x100 + +/* + * flag_ocpokan_rcv + */ +#define TFA98XX_STATUS_FLAGS2_OCPOANRC (0x1<<9) +#define TFA98XX_STATUS_FLAGS2_OCPOANRC_POS 9 +#define TFA98XX_STATUS_FLAGS2_OCPOANRC_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANRC_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANRC_MSK 0x200 + +/* + * flag_ocpokbp_rcv + */ +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC (0x1<<10) +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC_POS 10 +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC_MSK 0x400 + +/* + * flag_ocpokbn_rcv + */ +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC (0x1<<11) +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC_POS 11 +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC_MSK 0x800 + +/* + * flag_rcvldop_ready + */ +#define TFA98XX_STATUS_FLAGS2_RCVLDOR (0x1<<12) +#define TFA98XX_STATUS_FLAGS2_RCVLDOR_POS 12 +#define TFA98XX_STATUS_FLAGS2_RCVLDOR_LEN 1 +#define TFA98XX_STATUS_FLAGS2_RCVLDOR_MAX 1 +#define TFA98XX_STATUS_FLAGS2_RCVLDOR_MSK 0x1000 + +/* + * flag_rcvldop_bypassready + */ +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR (0x1<<13) +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR_POS 13 +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR_LEN 1 +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR_MAX 1 +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR_MSK 0x2000 + +/* + * flag_ocp_alarm_left + */ +#define TFA98XX_STATUS_FLAGS2_OCDSL (0x1<<14) +#define TFA98XX_STATUS_FLAGS2_OCDSL_POS 14 +#define TFA98XX_STATUS_FLAGS2_OCDSL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCDSL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCDSL_MSK 0x4000 + +/* + * flag_clip_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPSL (0x1<<15) +#define TFA98XX_STATUS_FLAGS2_CLIPSL_POS 15 +#define TFA98XX_STATUS_FLAGS2_CLIPSL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPSL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPSL_MSK 0x8000 + + +/* + * (0x13)-status_flags3 + */ + +/* + * flag_ocpokap_right + */ +#define TFA98XX_STATUS_FLAGS3_OCPOAPR (0x1<<0) +#define TFA98XX_STATUS_FLAGS3_OCPOAPR_POS 0 +#define TFA98XX_STATUS_FLAGS3_OCPOAPR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOAPR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOAPR_MSK 0x1 + +/* + * flag_ocpokan_right + */ +#define TFA98XX_STATUS_FLAGS3_OCPOANR (0x1<<1) +#define TFA98XX_STATUS_FLAGS3_OCPOANR_POS 1 +#define TFA98XX_STATUS_FLAGS3_OCPOANR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOANR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOANR_MSK 0x2 + +/* + * flag_ocpokbp_right + */ +#define TFA98XX_STATUS_FLAGS3_OCPOBPR (0x1<<2) +#define TFA98XX_STATUS_FLAGS3_OCPOBPR_POS 2 +#define TFA98XX_STATUS_FLAGS3_OCPOBPR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOBPR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOBPR_MSK 0x4 + +/* + * flag_ocpokbn_right + */ +#define TFA98XX_STATUS_FLAGS3_OCPOBNR (0x1<<3) +#define TFA98XX_STATUS_FLAGS3_OCPOBNR_POS 3 +#define TFA98XX_STATUS_FLAGS3_OCPOBNR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOBNR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOBNR_MSK 0x8 + +/* + * flag_clipa_high_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPAHR (0x1<<4) +#define TFA98XX_STATUS_FLAGS3_CLIPAHR_POS 4 +#define TFA98XX_STATUS_FLAGS3_CLIPAHR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPAHR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPAHR_MSK 0x10 + +/* + * flag_clipa_low_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPALR (0x1<<5) +#define TFA98XX_STATUS_FLAGS3_CLIPALR_POS 5 +#define TFA98XX_STATUS_FLAGS3_CLIPALR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPALR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPALR_MSK 0x20 + +/* + * flag_clipb_high_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPBHR (0x1<<6) +#define TFA98XX_STATUS_FLAGS3_CLIPBHR_POS 6 +#define TFA98XX_STATUS_FLAGS3_CLIPBHR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPBHR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPBHR_MSK 0x40 + +/* + * flag_clipb_low_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPBLR (0x1<<7) +#define TFA98XX_STATUS_FLAGS3_CLIPBLR_POS 7 +#define TFA98XX_STATUS_FLAGS3_CLIPBLR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPBLR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPBLR_MSK 0x80 + +/* + * flag_ocp_alarm_right + */ +#define TFA98XX_STATUS_FLAGS3_OCDSR (0x1<<8) +#define TFA98XX_STATUS_FLAGS3_OCDSR_POS 8 +#define TFA98XX_STATUS_FLAGS3_OCDSR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCDSR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCDSR_MSK 0x100 + +/* + * flag_clip_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPSR (0x1<<9) +#define TFA98XX_STATUS_FLAGS3_CLIPSR_POS 9 +#define TFA98XX_STATUS_FLAGS3_CLIPSR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPSR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPSR_MSK 0x200 + +/* + * flag_mic_ocpok + */ +#define TFA98XX_STATUS_FLAGS3_OCPOKMC (0x1<<10) +#define TFA98XX_STATUS_FLAGS3_OCPOKMC_POS 10 +#define TFA98XX_STATUS_FLAGS3_OCPOKMC_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOKMC_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOKMC_MSK 0x400 + +/* + * flag_man_alarm_state + */ +#define TFA98XX_STATUS_FLAGS3_MANALARM (0x1<<11) +#define TFA98XX_STATUS_FLAGS3_MANALARM_POS 11 +#define TFA98XX_STATUS_FLAGS3_MANALARM_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANALARM_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANALARM_MSK 0x800 + +/* + * flag_man_wait_src_settings + */ +#define TFA98XX_STATUS_FLAGS3_MANWAIT1 (0x1<<12) +#define TFA98XX_STATUS_FLAGS3_MANWAIT1_POS 12 +#define TFA98XX_STATUS_FLAGS3_MANWAIT1_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANWAIT1_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANWAIT1_MSK 0x1000 + +/* + * flag_man_wait_cf_config + */ +#define TFA98XX_STATUS_FLAGS3_MANWAIT2 (0x1<<13) +#define TFA98XX_STATUS_FLAGS3_MANWAIT2_POS 13 +#define TFA98XX_STATUS_FLAGS3_MANWAIT2_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANWAIT2_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANWAIT2_MSK 0x2000 + +/* + * flag_man_start_mute_audio + */ +#define TFA98XX_STATUS_FLAGS3_MANMUTE (0x1<<14) +#define TFA98XX_STATUS_FLAGS3_MANMUTE_POS 14 +#define TFA98XX_STATUS_FLAGS3_MANMUTE_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANMUTE_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANMUTE_MSK 0x4000 + +/* + * flag_man_operating_state + */ +#define TFA98XX_STATUS_FLAGS3_MANOPER (0x1<<15) +#define TFA98XX_STATUS_FLAGS3_MANOPER_POS 15 +#define TFA98XX_STATUS_FLAGS3_MANOPER_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANOPER_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANOPER_MSK 0x8000 + + +/* + * (0x14)-status_flags4 + */ + +/* + * flag_cf_speakererror_left + */ +#define TFA98XX_STATUS_FLAGS4_SPKSL (0x1<<0) +#define TFA98XX_STATUS_FLAGS4_SPKSL_POS 0 +#define TFA98XX_STATUS_FLAGS4_SPKSL_LEN 1 +#define TFA98XX_STATUS_FLAGS4_SPKSL_MAX 1 +#define TFA98XX_STATUS_FLAGS4_SPKSL_MSK 0x1 + +/* + * flag_cf_speakererror_right + */ +#define TFA98XX_STATUS_FLAGS4_SPKSR (0x1<<1) +#define TFA98XX_STATUS_FLAGS4_SPKSR_POS 1 +#define TFA98XX_STATUS_FLAGS4_SPKSR_LEN 1 +#define TFA98XX_STATUS_FLAGS4_SPKSR_MAX 1 +#define TFA98XX_STATUS_FLAGS4_SPKSR_MSK 0x2 + +/* + * flag_clk_out_of_range + */ +#define TFA98XX_STATUS_FLAGS4_CLKOOR (0x1<<2) +#define TFA98XX_STATUS_FLAGS4_CLKOOR_POS 2 +#define TFA98XX_STATUS_FLAGS4_CLKOOR_LEN 1 +#define TFA98XX_STATUS_FLAGS4_CLKOOR_MAX 1 +#define TFA98XX_STATUS_FLAGS4_CLKOOR_MSK 0x4 + +/* + * man_state + */ +#define TFA98XX_STATUS_FLAGS4_MANSTATE (0xf<<3) +#define TFA98XX_STATUS_FLAGS4_MANSTATE_POS 3 +#define TFA98XX_STATUS_FLAGS4_MANSTATE_LEN 4 +#define TFA98XX_STATUS_FLAGS4_MANSTATE_MAX 15 +#define TFA98XX_STATUS_FLAGS4_MANSTATE_MSK 0x78 + + +/* + * (0x15)-battery_voltage + */ + +/* + * bat_adc + */ +#define TFA98XX_BATTERY_VOLTAGE_BATS (0x3ff<<0) +#define TFA98XX_BATTERY_VOLTAGE_BATS_POS 0 +#define TFA98XX_BATTERY_VOLTAGE_BATS_LEN 10 +#define TFA98XX_BATTERY_VOLTAGE_BATS_MAX 1023 +#define TFA98XX_BATTERY_VOLTAGE_BATS_MSK 0x3ff + + +/* + * (0x16)-temperature + */ + +/* + * temp_adc + */ +#define TFA98XX_TEMPERATURE_TEMPS (0x1ff<<0) +#define TFA98XX_TEMPERATURE_TEMPS_POS 0 +#define TFA98XX_TEMPERATURE_TEMPS_LEN 9 +#define TFA98XX_TEMPERATURE_TEMPS_MAX 511 +#define TFA98XX_TEMPERATURE_TEMPS_MSK 0x1ff + + +/* + * (0x20)-tdm_config0 + */ + +/* + * tdm_usecase + */ +#define TFA98XX_TDM_CONFIG0_TDMUC (0xf<<0) +#define TFA98XX_TDM_CONFIG0_TDMUC_POS 0 +#define TFA98XX_TDM_CONFIG0_TDMUC_LEN 4 +#define TFA98XX_TDM_CONFIG0_TDMUC_MAX 15 +#define TFA98XX_TDM_CONFIG0_TDMUC_MSK 0xf + +/* + * tdm_enable + */ +#define TFA98XX_TDM_CONFIG0_TDME (0x1<<4) +#define TFA98XX_TDM_CONFIG0_TDME_POS 4 +#define TFA98XX_TDM_CONFIG0_TDME_LEN 1 +#define TFA98XX_TDM_CONFIG0_TDME_MAX 1 +#define TFA98XX_TDM_CONFIG0_TDME_MSK 0x10 + +/* + * tdm_mode + */ +#define TFA98XX_TDM_CONFIG0_TDMMODE (0x1<<5) +#define TFA98XX_TDM_CONFIG0_TDMMODE_POS 5 +#define TFA98XX_TDM_CONFIG0_TDMMODE_LEN 1 +#define TFA98XX_TDM_CONFIG0_TDMMODE_MAX 1 +#define TFA98XX_TDM_CONFIG0_TDMMODE_MSK 0x20 + +/* + * tdm_clk_inversion + */ +#define TFA98XX_TDM_CONFIG0_TDMCLINV (0x1<<6) +#define TFA98XX_TDM_CONFIG0_TDMCLINV_POS 6 +#define TFA98XX_TDM_CONFIG0_TDMCLINV_LEN 1 +#define TFA98XX_TDM_CONFIG0_TDMCLINV_MAX 1 +#define TFA98XX_TDM_CONFIG0_TDMCLINV_MSK 0x40 + +/* + * tdm_fs_ws_length + */ +#define TFA98XX_TDM_CONFIG0_TDMFSLN (0xf<<7) +#define TFA98XX_TDM_CONFIG0_TDMFSLN_POS 7 +#define TFA98XX_TDM_CONFIG0_TDMFSLN_LEN 4 +#define TFA98XX_TDM_CONFIG0_TDMFSLN_MAX 15 +#define TFA98XX_TDM_CONFIG0_TDMFSLN_MSK 0x780 + +/* + * tdm_fs_ws_polarity + */ +#define TFA98XX_TDM_CONFIG0_TDMFSPOL (0x1<<11) +#define TFA98XX_TDM_CONFIG0_TDMFSPOL_POS 11 +#define TFA98XX_TDM_CONFIG0_TDMFSPOL_LEN 1 +#define TFA98XX_TDM_CONFIG0_TDMFSPOL_MAX 1 +#define TFA98XX_TDM_CONFIG0_TDMFSPOL_MSK 0x800 + +/* + * tdm_nbck + */ +#define TFA98XX_TDM_CONFIG0_TDMNBCK (0xf<<12) +#define TFA98XX_TDM_CONFIG0_TDMNBCK_POS 12 +#define TFA98XX_TDM_CONFIG0_TDMNBCK_LEN 4 +#define TFA98XX_TDM_CONFIG0_TDMNBCK_MAX 15 +#define TFA98XX_TDM_CONFIG0_TDMNBCK_MSK 0xf000 + + +/* + * (0x21)-tdm_config1 + */ + +/* + * tdm_nb_of_slots + */ +#define TFA98XX_TDM_CONFIG1_TDMSLOTS (0xf<<0) +#define TFA98XX_TDM_CONFIG1_TDMSLOTS_POS 0 +#define TFA98XX_TDM_CONFIG1_TDMSLOTS_LEN 4 +#define TFA98XX_TDM_CONFIG1_TDMSLOTS_MAX 15 +#define TFA98XX_TDM_CONFIG1_TDMSLOTS_MSK 0xf + +/* + * tdm_slot_length + */ +#define TFA98XX_TDM_CONFIG1_TDMSLLN (0x1f<<4) +#define TFA98XX_TDM_CONFIG1_TDMSLLN_POS 4 +#define TFA98XX_TDM_CONFIG1_TDMSLLN_LEN 5 +#define TFA98XX_TDM_CONFIG1_TDMSLLN_MAX 31 +#define TFA98XX_TDM_CONFIG1_TDMSLLN_MSK 0x1f0 + +/* + * tdm_bits_remaining + */ +#define TFA98XX_TDM_CONFIG1_TDMBRMG (0x1f<<9) +#define TFA98XX_TDM_CONFIG1_TDMBRMG_POS 9 +#define TFA98XX_TDM_CONFIG1_TDMBRMG_LEN 5 +#define TFA98XX_TDM_CONFIG1_TDMBRMG_MAX 31 +#define TFA98XX_TDM_CONFIG1_TDMBRMG_MSK 0x3e00 + +/* + * tdm_data_delay + */ +#define TFA98XX_TDM_CONFIG1_TDMDEL (0x1<<14) +#define TFA98XX_TDM_CONFIG1_TDMDEL_POS 14 +#define TFA98XX_TDM_CONFIG1_TDMDEL_LEN 1 +#define TFA98XX_TDM_CONFIG1_TDMDEL_MAX 1 +#define TFA98XX_TDM_CONFIG1_TDMDEL_MSK 0x4000 + +/* + * tdm_data_adjustment + */ +#define TFA98XX_TDM_CONFIG1_TDMADJ (0x1<<15) +#define TFA98XX_TDM_CONFIG1_TDMADJ_POS 15 +#define TFA98XX_TDM_CONFIG1_TDMADJ_LEN 1 +#define TFA98XX_TDM_CONFIG1_TDMADJ_MAX 1 +#define TFA98XX_TDM_CONFIG1_TDMADJ_MSK 0x8000 + + +/* + * (0x22)-tdm_config2 + */ + +/* + * tdm_audio_sample_compression + */ +#define TFA98XX_TDM_CONFIG2_TDMOOMP (0x3<<0) +#define TFA98XX_TDM_CONFIG2_TDMOOMP_POS 0 +#define TFA98XX_TDM_CONFIG2_TDMOOMP_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMOOMP_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMOOMP_MSK 0x3 + +/* + * tdm_sample_size + */ +#define TFA98XX_TDM_CONFIG2_TDMSSIZE (0x1f<<2) +#define TFA98XX_TDM_CONFIG2_TDMSSIZE_POS 2 +#define TFA98XX_TDM_CONFIG2_TDMSSIZE_LEN 5 +#define TFA98XX_TDM_CONFIG2_TDMSSIZE_MAX 31 +#define TFA98XX_TDM_CONFIG2_TDMSSIZE_MSK 0x7c + +/* + * tdm_txdata_format + */ +#define TFA98XX_TDM_CONFIG2_TDMTXDFO (0x3<<7) +#define TFA98XX_TDM_CONFIG2_TDMTXDFO_POS 7 +#define TFA98XX_TDM_CONFIG2_TDMTXDFO_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMTXDFO_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMTXDFO_MSK 0x180 + +/* + * tdm_txdata_format_unused_slot_sd0 + */ +#define TFA98XX_TDM_CONFIG2_TDMTXUS0 (0x3<<9) +#define TFA98XX_TDM_CONFIG2_TDMTXUS0_POS 9 +#define TFA98XX_TDM_CONFIG2_TDMTXUS0_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMTXUS0_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMTXUS0_MSK 0x600 + +/* + * tdm_txdata_format_unused_slot_sd1 + */ +#define TFA98XX_TDM_CONFIG2_TDMTXUS1 (0x3<<11) +#define TFA98XX_TDM_CONFIG2_TDMTXUS1_POS 11 +#define TFA98XX_TDM_CONFIG2_TDMTXUS1_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMTXUS1_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMTXUS1_MSK 0x1800 + +/* + * tdm_txdata_format_unused_slot_sd2 + */ +#define TFA98XX_TDM_CONFIG2_TDMTXUS2 (0x3<<13) +#define TFA98XX_TDM_CONFIG2_TDMTXUS2_POS 13 +#define TFA98XX_TDM_CONFIG2_TDMTXUS2_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMTXUS2_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMTXUS2_MSK 0x6000 + + +/* + * (0x23)-tdm_config3 + */ + +/* + * tdm_sink1_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMLE (0x1<<1) +#define TFA98XX_TDM_CONFIG3_TDMLE_POS 1 +#define TFA98XX_TDM_CONFIG3_TDMLE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMLE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMLE_MSK 0x2 + +/* + * tdm_sink2_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMRE (0x1<<2) +#define TFA98XX_TDM_CONFIG3_TDMRE_POS 2 +#define TFA98XX_TDM_CONFIG3_TDMRE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMRE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMRE_MSK 0x4 + +/* + * tdm_source1_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMVSRE (0x1<<4) +#define TFA98XX_TDM_CONFIG3_TDMVSRE_POS 4 +#define TFA98XX_TDM_CONFIG3_TDMVSRE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMVSRE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMVSRE_MSK 0x10 + +/* + * tdm_source2_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCSRE (0x1<<5) +#define TFA98XX_TDM_CONFIG3_TDMCSRE_POS 5 +#define TFA98XX_TDM_CONFIG3_TDMCSRE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCSRE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCSRE_MSK 0x20 + +/* + * tdm_source3_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMVSLE (0x1<<6) +#define TFA98XX_TDM_CONFIG3_TDMVSLE_POS 6 +#define TFA98XX_TDM_CONFIG3_TDMVSLE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMVSLE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMVSLE_MSK 0x40 + +/* + * tdm_source4_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCSLE (0x1<<7) +#define TFA98XX_TDM_CONFIG3_TDMCSLE_POS 7 +#define TFA98XX_TDM_CONFIG3_TDMCSLE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCSLE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCSLE_MSK 0x80 + +/* + * tdm_source5_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCFRE (0x1<<8) +#define TFA98XX_TDM_CONFIG3_TDMCFRE_POS 8 +#define TFA98XX_TDM_CONFIG3_TDMCFRE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCFRE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCFRE_MSK 0x100 + +/* + * tdm_source6_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCFLE (0x1<<9) +#define TFA98XX_TDM_CONFIG3_TDMCFLE_POS 9 +#define TFA98XX_TDM_CONFIG3_TDMCFLE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCFLE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCFLE_MSK 0x200 + +/* + * tdm_source7_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCF3E (0x1<<10) +#define TFA98XX_TDM_CONFIG3_TDMCF3E_POS 10 +#define TFA98XX_TDM_CONFIG3_TDMCF3E_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCF3E_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCF3E_MSK 0x400 + +/* + * tdm_source8_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCF4E (0x1<<11) +#define TFA98XX_TDM_CONFIG3_TDMCF4E_POS 11 +#define TFA98XX_TDM_CONFIG3_TDMCF4E_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCF4E_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCF4E_MSK 0x800 + +/* + * tdm_source9_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMPD1E (0x1<<12) +#define TFA98XX_TDM_CONFIG3_TDMPD1E_POS 12 +#define TFA98XX_TDM_CONFIG3_TDMPD1E_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMPD1E_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMPD1E_MSK 0x1000 + +/* + * tdm_source10_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMPD2E (0x1<<13) +#define TFA98XX_TDM_CONFIG3_TDMPD2E_POS 13 +#define TFA98XX_TDM_CONFIG3_TDMPD2E_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMPD2E_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMPD2E_MSK 0x2000 + + +/* + * (0x24)-tdm_config4 + */ + +/* + * tdm_sink1_io + */ +#define TFA98XX_TDM_CONFIG4_TDMLIO (0x3<<2) +#define TFA98XX_TDM_CONFIG4_TDMLIO_POS 2 +#define TFA98XX_TDM_CONFIG4_TDMLIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMLIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMLIO_MSK 0xc + +/* + * tdm_sink2_io + */ +#define TFA98XX_TDM_CONFIG4_TDMRIO (0x3<<4) +#define TFA98XX_TDM_CONFIG4_TDMRIO_POS 4 +#define TFA98XX_TDM_CONFIG4_TDMRIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMRIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMRIO_MSK 0x30 + +/* + * tdm_source1_io + */ +#define TFA98XX_TDM_CONFIG4_TDMVSRIO (0x3<<8) +#define TFA98XX_TDM_CONFIG4_TDMVSRIO_POS 8 +#define TFA98XX_TDM_CONFIG4_TDMVSRIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMVSRIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMVSRIO_MSK 0x300 + +/* + * tdm_source2_io + */ +#define TFA98XX_TDM_CONFIG4_TDMCSRIO (0x3<<10) +#define TFA98XX_TDM_CONFIG4_TDMCSRIO_POS 10 +#define TFA98XX_TDM_CONFIG4_TDMCSRIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMCSRIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMCSRIO_MSK 0xc00 + +/* + * tdm_source3_io + */ +#define TFA98XX_TDM_CONFIG4_TDMVSLIO (0x3<<12) +#define TFA98XX_TDM_CONFIG4_TDMVSLIO_POS 12 +#define TFA98XX_TDM_CONFIG4_TDMVSLIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMVSLIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMVSLIO_MSK 0x3000 + +/* + * tdm_source4_io + */ +#define TFA98XX_TDM_CONFIG4_TDMCSLIO (0x3<<14) +#define TFA98XX_TDM_CONFIG4_TDMCSLIO_POS 14 +#define TFA98XX_TDM_CONFIG4_TDMCSLIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMCSLIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMCSLIO_MSK 0xc000 + + +/* + * (0x25)-tdm_config5 + */ + +/* + * tdm_source5_io + */ +#define TFA98XX_TDM_CONFIG5_TDMCFRIO (0x3<<0) +#define TFA98XX_TDM_CONFIG5_TDMCFRIO_POS 0 +#define TFA98XX_TDM_CONFIG5_TDMCFRIO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMCFRIO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMCFRIO_MSK 0x3 + +/* + * tdm_source6_io + */ +#define TFA98XX_TDM_CONFIG5_TDMCFLIO (0x3<<2) +#define TFA98XX_TDM_CONFIG5_TDMCFLIO_POS 2 +#define TFA98XX_TDM_CONFIG5_TDMCFLIO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMCFLIO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMCFLIO_MSK 0xc + +/* + * tdm_source7_io + */ +#define TFA98XX_TDM_CONFIG5_TDMCF3IO (0x3<<4) +#define TFA98XX_TDM_CONFIG5_TDMCF3IO_POS 4 +#define TFA98XX_TDM_CONFIG5_TDMCF3IO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMCF3IO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMCF3IO_MSK 0x30 + +/* + * tdm_source8_io + */ +#define TFA98XX_TDM_CONFIG5_TDMCF4IO (0x3<<6) +#define TFA98XX_TDM_CONFIG5_TDMCF4IO_POS 6 +#define TFA98XX_TDM_CONFIG5_TDMCF4IO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMCF4IO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMCF4IO_MSK 0xc0 + +/* + * tdm_source9_io + */ +#define TFA98XX_TDM_CONFIG5_TDMPD1IO (0x3<<8) +#define TFA98XX_TDM_CONFIG5_TDMPD1IO_POS 8 +#define TFA98XX_TDM_CONFIG5_TDMPD1IO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMPD1IO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMPD1IO_MSK 0x300 + +/* + * tdm_source10_io + */ +#define TFA98XX_TDM_CONFIG5_TDMPD2IO (0x3<<10) +#define TFA98XX_TDM_CONFIG5_TDMPD2IO_POS 10 +#define TFA98XX_TDM_CONFIG5_TDMPD2IO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMPD2IO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMPD2IO_MSK 0xc00 + + +/* + * (0x26)-tdm_config6 + */ + +/* + * tdm_sink1_slot + */ +#define TFA98XX_TDM_CONFIG6_TDMLS (0xf<<4) +#define TFA98XX_TDM_CONFIG6_TDMLS_POS 4 +#define TFA98XX_TDM_CONFIG6_TDMLS_LEN 4 +#define TFA98XX_TDM_CONFIG6_TDMLS_MAX 15 +#define TFA98XX_TDM_CONFIG6_TDMLS_MSK 0xf0 + +/* + * tdm_sink2_slot + */ +#define TFA98XX_TDM_CONFIG6_TDMRS (0xf<<8) +#define TFA98XX_TDM_CONFIG6_TDMRS_POS 8 +#define TFA98XX_TDM_CONFIG6_TDMRS_LEN 4 +#define TFA98XX_TDM_CONFIG6_TDMRS_MAX 15 +#define TFA98XX_TDM_CONFIG6_TDMRS_MSK 0xf00 + + +/* + * (0x27)-tdm_config7 + */ + +/* + * tdm_source1_slot + */ +#define TFA98XX_TDM_CONFIG7_TDMVSRS (0xf<<0) +#define TFA98XX_TDM_CONFIG7_TDMVSRS_POS 0 +#define TFA98XX_TDM_CONFIG7_TDMVSRS_LEN 4 +#define TFA98XX_TDM_CONFIG7_TDMVSRS_MAX 15 +#define TFA98XX_TDM_CONFIG7_TDMVSRS_MSK 0xf + +/* + * tdm_source2_slot + */ +#define TFA98XX_TDM_CONFIG7_TDMCSRS (0xf<<4) +#define TFA98XX_TDM_CONFIG7_TDMCSRS_POS 4 +#define TFA98XX_TDM_CONFIG7_TDMCSRS_LEN 4 +#define TFA98XX_TDM_CONFIG7_TDMCSRS_MAX 15 +#define TFA98XX_TDM_CONFIG7_TDMCSRS_MSK 0xf0 + +/* + * tdm_source3_slot + */ +#define TFA98XX_TDM_CONFIG7_TDMVSLS (0xf<<8) +#define TFA98XX_TDM_CONFIG7_TDMVSLS_POS 8 +#define TFA98XX_TDM_CONFIG7_TDMVSLS_LEN 4 +#define TFA98XX_TDM_CONFIG7_TDMVSLS_MAX 15 +#define TFA98XX_TDM_CONFIG7_TDMVSLS_MSK 0xf00 + +/* + * tdm_source4_slot + */ +#define TFA98XX_TDM_CONFIG7_TDMCSLS (0xf<<12) +#define TFA98XX_TDM_CONFIG7_TDMCSLS_POS 12 +#define TFA98XX_TDM_CONFIG7_TDMCSLS_LEN 4 +#define TFA98XX_TDM_CONFIG7_TDMCSLS_MAX 15 +#define TFA98XX_TDM_CONFIG7_TDMCSLS_MSK 0xf000 + + +/* + * (0x28)-tdm_config8 + */ + +/* + * tdm_source5_slot + */ +#define TFA98XX_TDM_CONFIG8_TDMCFRS (0xf<<0) +#define TFA98XX_TDM_CONFIG8_TDMCFRS_POS 0 +#define TFA98XX_TDM_CONFIG8_TDMCFRS_LEN 4 +#define TFA98XX_TDM_CONFIG8_TDMCFRS_MAX 15 +#define TFA98XX_TDM_CONFIG8_TDMCFRS_MSK 0xf + +/* + * tdm_source6_slot + */ +#define TFA98XX_TDM_CONFIG8_TDMCFLS (0xf<<4) +#define TFA98XX_TDM_CONFIG8_TDMCFLS_POS 4 +#define TFA98XX_TDM_CONFIG8_TDMCFLS_LEN 4 +#define TFA98XX_TDM_CONFIG8_TDMCFLS_MAX 15 +#define TFA98XX_TDM_CONFIG8_TDMCFLS_MSK 0xf0 + +/* + * tdm_source7_slot + */ +#define TFA98XX_TDM_CONFIG8_TDMCF3S (0xf<<8) +#define TFA98XX_TDM_CONFIG8_TDMCF3S_POS 8 +#define TFA98XX_TDM_CONFIG8_TDMCF3S_LEN 4 +#define TFA98XX_TDM_CONFIG8_TDMCF3S_MAX 15 +#define TFA98XX_TDM_CONFIG8_TDMCF3S_MSK 0xf00 + +/* + * tdm_source8_slot + */ +#define TFA98XX_TDM_CONFIG8_TDMCF4S (0xf<<12) +#define TFA98XX_TDM_CONFIG8_TDMCF4S_POS 12 +#define TFA98XX_TDM_CONFIG8_TDMCF4S_LEN 4 +#define TFA98XX_TDM_CONFIG8_TDMCF4S_MAX 15 +#define TFA98XX_TDM_CONFIG8_TDMCF4S_MSK 0xf000 + + +/* + * (0x29)-tdm_config9 + */ + +/* + * tdm_source9_slot + */ +#define TFA98XX_TDM_CONFIG9_TDMPD1S (0xf<<0) +#define TFA98XX_TDM_CONFIG9_TDMPD1S_POS 0 +#define TFA98XX_TDM_CONFIG9_TDMPD1S_LEN 4 +#define TFA98XX_TDM_CONFIG9_TDMPD1S_MAX 15 +#define TFA98XX_TDM_CONFIG9_TDMPD1S_MSK 0xf + +/* + * tdm_source10_slot + */ +#define TFA98XX_TDM_CONFIG9_TDMPD2S (0xf<<4) +#define TFA98XX_TDM_CONFIG9_TDMPD2S_POS 4 +#define TFA98XX_TDM_CONFIG9_TDMPD2S_LEN 4 +#define TFA98XX_TDM_CONFIG9_TDMPD2S_MAX 15 +#define TFA98XX_TDM_CONFIG9_TDMPD2S_MSK 0xf0 + + +/* + * (0x31)-pdm_config0 + */ + +/* + * pdm_mode + */ +#define TFA98XX_PDM_CONFIG0_PDMSM (0x1<<0) +#define TFA98XX_PDM_CONFIG0_PDMSM_POS 0 +#define TFA98XX_PDM_CONFIG0_PDMSM_LEN 1 +#define TFA98XX_PDM_CONFIG0_PDMSM_MAX 1 +#define TFA98XX_PDM_CONFIG0_PDMSM_MSK 0x1 + +/* + * pdm_side_tone_sel + */ +#define TFA98XX_PDM_CONFIG0_PDMSTSEL (0x3<<1) +#define TFA98XX_PDM_CONFIG0_PDMSTSEL_POS 1 +#define TFA98XX_PDM_CONFIG0_PDMSTSEL_LEN 2 +#define TFA98XX_PDM_CONFIG0_PDMSTSEL_MAX 3 +#define TFA98XX_PDM_CONFIG0_PDMSTSEL_MSK 0x6 + +/* + * pdm_left_sel + */ +#define TFA98XX_PDM_CONFIG0_PDMLSEL (0x1<<3) +#define TFA98XX_PDM_CONFIG0_PDMLSEL_POS 3 +#define TFA98XX_PDM_CONFIG0_PDMLSEL_LEN 1 +#define TFA98XX_PDM_CONFIG0_PDMLSEL_MAX 1 +#define TFA98XX_PDM_CONFIG0_PDMLSEL_MSK 0x8 + +/* + * pdm_right_sel + */ +#define TFA98XX_PDM_CONFIG0_PDMRSEL (0x1<<4) +#define TFA98XX_PDM_CONFIG0_PDMRSEL_POS 4 +#define TFA98XX_PDM_CONFIG0_PDMRSEL_LEN 1 +#define TFA98XX_PDM_CONFIG0_PDMRSEL_MAX 1 +#define TFA98XX_PDM_CONFIG0_PDMRSEL_MSK 0x10 + +/* + * enbl_micvdd + */ +#define TFA98XX_PDM_CONFIG0_MICVDDE (0x1<<5) +#define TFA98XX_PDM_CONFIG0_MICVDDE_POS 5 +#define TFA98XX_PDM_CONFIG0_MICVDDE_LEN 1 +#define TFA98XX_PDM_CONFIG0_MICVDDE_MAX 1 +#define TFA98XX_PDM_CONFIG0_MICVDDE_MSK 0x20 + + +/* + * (0x32)-pdm_config1 + */ + +/* + * pdm_nbck + */ +#define TFA98XX_PDM_CONFIG1_PDMCLRAT (0x3<<0) +#define TFA98XX_PDM_CONFIG1_PDMCLRAT_POS 0 +#define TFA98XX_PDM_CONFIG1_PDMCLRAT_LEN 2 +#define TFA98XX_PDM_CONFIG1_PDMCLRAT_MAX 3 +#define TFA98XX_PDM_CONFIG1_PDMCLRAT_MSK 0x3 + +/* + * pdm_gain + */ +#define TFA98XX_PDM_CONFIG1_PDMGAIN (0xf<<2) +#define TFA98XX_PDM_CONFIG1_PDMGAIN_POS 2 +#define TFA98XX_PDM_CONFIG1_PDMGAIN_LEN 4 +#define TFA98XX_PDM_CONFIG1_PDMGAIN_MAX 15 +#define TFA98XX_PDM_CONFIG1_PDMGAIN_MSK 0x3c + +/* + * sel_pdm_out_data + */ +#define TFA98XX_PDM_CONFIG1_PDMOSEL (0xf<<6) +#define TFA98XX_PDM_CONFIG1_PDMOSEL_POS 6 +#define TFA98XX_PDM_CONFIG1_PDMOSEL_LEN 4 +#define TFA98XX_PDM_CONFIG1_PDMOSEL_MAX 15 +#define TFA98XX_PDM_CONFIG1_PDMOSEL_MSK 0x3c0 + +/* + * sel_cf_haptic_data + */ +#define TFA98XX_PDM_CONFIG1_SELCFHAPD (0x1<<10) +#define TFA98XX_PDM_CONFIG1_SELCFHAPD_POS 10 +#define TFA98XX_PDM_CONFIG1_SELCFHAPD_LEN 1 +#define TFA98XX_PDM_CONFIG1_SELCFHAPD_MAX 1 +#define TFA98XX_PDM_CONFIG1_SELCFHAPD_MSK 0x400 + + +/* + * (0x33)-haptic_driver_config + */ + +/* + * haptic_duration + */ +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME (0xff<<0) +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME_POS 0 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME_LEN 8 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME_MAX 255 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME_MSK 0xff + +/* + * haptic_data + */ +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL (0xff<<8) +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL_POS 8 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL_LEN 8 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL_MAX 255 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL_MSK 0xff00 + + +/* + * (0x34)-gpio_datain_reg + */ + +/* + * gpio_datain + */ +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN (0xf<<0) +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN_POS 0 +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN_LEN 4 +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN_MAX 15 +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN_MSK 0xf + + +/* + * (0x35)-gpio_config + */ + +/* + * gpio_ctrl + */ +#define TFA98XX_GPIO_CONFIG_GPIOCTRL (0x1<<0) +#define TFA98XX_GPIO_CONFIG_GPIOCTRL_POS 0 +#define TFA98XX_GPIO_CONFIG_GPIOCTRL_LEN 1 +#define TFA98XX_GPIO_CONFIG_GPIOCTRL_MAX 1 +#define TFA98XX_GPIO_CONFIG_GPIOCTRL_MSK 0x1 + +/* + * gpio_dir + */ +#define TFA98XX_GPIO_CONFIG_GPIOCONF (0xf<<1) +#define TFA98XX_GPIO_CONFIG_GPIOCONF_POS 1 +#define TFA98XX_GPIO_CONFIG_GPIOCONF_LEN 4 +#define TFA98XX_GPIO_CONFIG_GPIOCONF_MAX 15 +#define TFA98XX_GPIO_CONFIG_GPIOCONF_MSK 0x1e + +/* + * gpio_dataout + */ +#define TFA98XX_GPIO_CONFIG_GPIODOUT (0xf<<5) +#define TFA98XX_GPIO_CONFIG_GPIODOUT_POS 5 +#define TFA98XX_GPIO_CONFIG_GPIODOUT_LEN 4 +#define TFA98XX_GPIO_CONFIG_GPIODOUT_MAX 15 +#define TFA98XX_GPIO_CONFIG_GPIODOUT_MSK 0x1e0 + + +/* + * (0x40)-interrupt_out_reg1 + */ + +/* + * int_out_flag_por + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS (0x1<<0) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS_POS 0 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS_MSK 0x1 + +/* + * int_out_flag_pll_lock + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS (0x1<<1) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS_POS 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS_MSK 0x2 + +/* + * int_out_flag_otpok + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS (0x1<<2) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS_POS 2 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS_MSK 0x4 + +/* + * int_out_flag_ovpok + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS (0x1<<3) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS_POS 3 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS_MSK 0x8 + +/* + * int_out_flag_uvpok + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS (0x1<<4) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS_POS 4 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS_MSK 0x10 + +/* + * int_out_flag_clocks_stable + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS (0x1<<5) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS_POS 5 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS_MSK 0x20 + +/* + * int_out_flag_mtp_busy + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB (0x1<<6) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB_POS 6 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB_MSK 0x40 + +/* + * int_out_flag_lost_clk + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK (0x1<<7) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK_POS 7 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK_MSK 0x80 + +/* + * int_out_flag_cf_speakererror + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS (0x1<<8) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS_POS 8 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS_MSK 0x100 + +/* + * int_out_flag_cold_started + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS (0x1<<9) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS_POS 9 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS_MSK 0x200 + +/* + * int_out_flag_engage + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS (0x1<<10) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS_POS 10 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS_MSK 0x400 + +/* + * int_out_flag_watchdog_reset + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS (0x1<<11) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS_POS 11 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS_MSK 0x800 + +/* + * int_out_flag_enbl_amp + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS (0x1<<12) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS_POS 12 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS_MSK 0x1000 + +/* + * int_out_flag_enbl_ref + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS (0x1<<13) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS_POS 13 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS_MSK 0x2000 + +/* + * int_out_flag_adc10_ready + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR (0x1<<14) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR_POS 14 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR_MSK 0x4000 + +/* + * int_out_flag_bod_vddd_nok + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK (0x1<<15) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK_POS 15 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK_MSK 0x8000 + + +/* + * (0x41)-interrupt_out_reg2 + */ + +/* + * int_out_flag_bst_bstcur + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU (0x1<<0) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU_POS 0 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU_MSK 0x1 + +/* + * int_out_flag_bst_hiz + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI (0x1<<1) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI_POS 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI_MSK 0x2 + +/* + * int_out_flag_bst_ocpok + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC (0x1<<2) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC_POS 2 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC_MSK 0x4 + +/* + * int_out_flag_bst_peakcur + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR (0x1<<3) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR_POS 3 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR_MSK 0x8 + +/* + * int_out_flag_bst_voutcomp + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC (0x1<<4) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC_POS 4 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC_MSK 0x10 + +/* + * int_out_flag_bst_voutcomp86 + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86 (0x1<<5) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86_POS 5 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86_MSK 0x20 + +/* + * int_out_flag_bst_voutcomp93 + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93 (0x1<<6) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93_POS 6 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93_MSK 0x40 + +/* + * int_out_flag_rcvldop_ready + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD (0x1<<7) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD_POS 7 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD_MSK 0x80 + +/* + * int_out_flag_ocp_alarm_left + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL (0x1<<8) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL_POS 8 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL_MSK 0x100 + +/* + * int_out_flag_ocp_alarm_right + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR (0x1<<9) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR_POS 9 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR_MSK 0x200 + +/* + * int_out_flag_man_wait_src_settings + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC (0x1<<10) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC_POS 10 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC_MSK 0x400 + +/* + * int_out_flag_man_wait_cf_config + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC (0x1<<11) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC_POS 11 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC_MSK 0x800 + +/* + * int_out_flag_man_start_mute_audio + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU (0x1<<12) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU_POS 12 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU_MSK 0x1000 + +/* + * int_out_flag_cfma_err + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER (0x1<<13) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER_POS 13 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER_MSK 0x2000 + +/* + * int_out_flag_cfma_ack + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC (0x1<<14) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC_POS 14 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC_MSK 0x4000 + +/* + * int_out_flag_clk_out_of_range + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR (0x1<<15) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR_POS 15 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR_MSK 0x8000 + + +/* + * (0x42)-interrupt_out_reg3 + */ + +/* + * int_out_flag_tdm_error + */ +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER (0x1<<0) +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER_POS 0 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER_MSK 0x1 + +/* + * int_out_flag_clip_left + */ +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL (0x1<<1) +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL_POS 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL_MSK 0x2 + +/* + * int_out_flag_clip_right + */ +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR (0x1<<2) +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR_POS 2 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR_MSK 0x4 + +/* + * int_out_flag_mic_ocpok + */ +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM (0x1<<3) +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM_POS 3 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM_MSK 0x8 + + +/* + * (0x44)-interrupt_in_reg1 + */ + +/* + * int_in_flag_por + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS (0x1<<0) +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS_POS 0 +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS_MSK 0x1 + +/* + * int_in_flag_pll_lock + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS (0x1<<1) +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS_POS 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS_MSK 0x2 + +/* + * int_in_flag_otpok + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS (0x1<<2) +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS_POS 2 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS_MSK 0x4 + +/* + * int_in_flag_ovpok + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS (0x1<<3) +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS_POS 3 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS_MSK 0x8 + +/* + * int_in_flag_uvpok + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS (0x1<<4) +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS_POS 4 +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS_MSK 0x10 + +/* + * int_in_flag_clocks_stable + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS (0x1<<5) +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS_POS 5 +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS_MSK 0x20 + +/* + * int_in_flag_mtp_busy + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB (0x1<<6) +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB_POS 6 +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB_MSK 0x40 + +/* + * int_in_flag_lost_clk + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK (0x1<<7) +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK_POS 7 +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK_MSK 0x80 + +/* + * int_in_flag_cf_speakererror + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS (0x1<<8) +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS_POS 8 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS_MSK 0x100 + +/* + * int_in_flag_cold_started + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS (0x1<<9) +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS_POS 9 +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS_MSK 0x200 + +/* + * int_in_flag_engage + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS (0x1<<10) +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS_POS 10 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS_MSK 0x400 + +/* + * int_in_flag_watchdog_reset + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS (0x1<<11) +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS_POS 11 +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS_MSK 0x800 + +/* + * int_in_flag_enbl_amp + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS (0x1<<12) +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS_POS 12 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS_MSK 0x1000 + +/* + * int_in_flag_enbl_ref + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS (0x1<<13) +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS_POS 13 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS_MSK 0x2000 + +/* + * int_in_flag_adc10_ready + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR (0x1<<14) +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR_POS 14 +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR_MSK 0x4000 + +/* + * int_in_flag_bod_vddd_nok + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK (0x1<<15) +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK_POS 15 +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK_MSK 0x8000 + + +/* + * (0x45)-interrupt_in_reg2 + */ + +/* + * int_in_flag_bst_bstcur + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU (0x1<<0) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU_POS 0 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU_MSK 0x1 + +/* + * int_in_flag_bst_hiz + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI (0x1<<1) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI_POS 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI_MSK 0x2 + +/* + * int_in_flag_bst_ocpok + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC (0x1<<2) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC_POS 2 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC_MSK 0x4 + +/* + * int_in_flag_bst_peakcur + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC (0x1<<3) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC_POS 3 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC_MSK 0x8 + +/* + * int_in_flag_bst_voutcomp + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC (0x1<<4) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC_POS 4 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC_MSK 0x10 + +/* + * int_in_flag_bst_voutcomp86 + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86 (0x1<<5) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86_POS 5 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86_MSK 0x20 + +/* + * int_in_flag_bst_voutcomp93 + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93 (0x1<<6) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93_POS 6 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93_MSK 0x40 + +/* + * int_in_flag_rcvldop_ready + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD (0x1<<7) +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD_POS 7 +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD_MSK 0x80 + +/* + * int_in_flag_ocp_alarm_left + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL (0x1<<8) +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL_POS 8 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL_MSK 0x100 + +/* + * int_in_flag_ocp_alarm_right + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR (0x1<<9) +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR_POS 9 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR_MSK 0x200 + +/* + * int_in_flag_man_wait_src_settings + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC (0x1<<10) +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC_POS 10 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC_MSK 0x400 + +/* + * int_in_flag_man_wait_cf_config + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC (0x1<<11) +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC_POS 11 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC_MSK 0x800 + +/* + * int_in_flag_man_start_mute_audio + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU (0x1<<12) +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU_POS 12 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU_MSK 0x1000 + +/* + * int_in_flag_cfma_err + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER (0x1<<13) +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER_POS 13 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER_MSK 0x2000 + +/* + * int_in_flag_cfma_ack + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC (0x1<<14) +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC_POS 14 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC_MSK 0x4000 + +/* + * int_in_flag_clk_out_of_range + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR (0x1<<15) +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR_POS 15 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR_MSK 0x8000 + + +/* + * (0x46)-interrupt_in_reg3 + */ + +/* + * int_in_flag_tdm_error + */ +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER (0x1<<0) +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER_POS 0 +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER_MSK 0x1 + +/* + * int_in_flag_clip_left + */ +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL (0x1<<1) +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL_POS 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL_MSK 0x2 + +/* + * int_in_flag_clip_right + */ +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR (0x1<<2) +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR_POS 2 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR_MSK 0x4 + +/* + * int_in_flag_mic_ocpok + */ +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM (0x1<<3) +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM_POS 3 +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM_MSK 0x8 + + +/* + * (0x48)-interrupt_enable_reg1 + */ + +/* + * int_enable_flag_por + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS (0x1<<0) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS_POS 0 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS_MSK 0x1 + +/* + * int_enable_flag_pll_lock + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS (0x1<<1) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS_POS 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS_MSK 0x2 + +/* + * int_enable_flag_otpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS (0x1<<2) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS_POS 2 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS_MSK 0x4 + +/* + * int_enable_flag_ovpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS (0x1<<3) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS_POS 3 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS_MSK 0x8 + +/* + * int_enable_flag_uvpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS (0x1<<4) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS_POS 4 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS_MSK 0x10 + +/* + * int_enable_flag_clocks_stable + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS (0x1<<5) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS_POS 5 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS_MSK 0x20 + +/* + * int_enable_flag_mtp_busy + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB (0x1<<6) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB_POS 6 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB_MSK 0x40 + +/* + * int_enable_flag_lost_clk + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK (0x1<<7) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK_POS 7 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK_MSK 0x80 + +/* + * int_enable_flag_cf_speakererror + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS (0x1<<8) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS_POS 8 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS_MSK 0x100 + +/* + * int_enable_flag_cold_started + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS (0x1<<9) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS_POS 9 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS_MSK 0x200 + +/* + * int_enable_flag_engage + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS (0x1<<10) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS_POS 10 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS_MSK 0x400 + +/* + * int_enable_flag_watchdog_reset + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS (0x1<<11) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS_POS 11 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS_MSK 0x800 + +/* + * int_enable_flag_enbl_amp + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS (0x1<<12) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS_POS 12 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS_MSK 0x1000 + +/* + * int_enable_flag_enbl_ref + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS (0x1<<13) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS_POS 13 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS_MSK 0x2000 + +/* + * int_enable_flag_adc10_ready + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR (0x1<<14) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR_POS 14 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR_MSK 0x4000 + +/* + * int_enable_flag_bod_vddd_nok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK (0x1<<15) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK_POS 15 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK_MSK 0x8000 + + +/* + * (0x49)-interrupt_enable_reg2 + */ + +/* + * int_enable_flag_bst_bstcur + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU (0x1<<0) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU_POS 0 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU_MSK 0x1 + +/* + * int_enable_flag_bst_hiz + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI (0x1<<1) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI_POS 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI_MSK 0x2 + +/* + * int_enable_flag_bst_ocpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC (0x1<<2) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC_POS 2 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC_MSK 0x4 + +/* + * int_enable_flag_bst_peakcur + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC (0x1<<3) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC_POS 3 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC_MSK 0x8 + +/* + * int_enable_flag_bst_voutcomp + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC (0x1<<4) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC_POS 4 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC_MSK 0x10 + +/* + * int_enable_flag_bst_voutcomp86 + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86 (0x1<<5) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86_POS 5 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86_MSK 0x20 + +/* + * int_enable_flag_bst_voutcomp93 + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93 (0x1<<6) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93_POS 6 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93_MSK 0x40 + +/* + * int_enable_flag_rcvldop_ready + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD (0x1<<7) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD_POS 7 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD_MSK 0x80 + +/* + * int_enable_flag_ocp_alarm_left + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL (0x1<<8) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL_POS 8 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL_MSK 0x100 + +/* + * int_enable_flag_ocp_alarm_right + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR (0x1<<9) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR_POS 9 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR_MSK 0x200 + +/* + * int_enable_flag_man_wait_src_settings + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC (0x1<<10) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC_POS 10 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC_MSK 0x400 + +/* + * int_enable_flag_man_wait_cf_config + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC (0x1<<11) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC_POS 11 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC_MSK 0x800 + +/* + * int_enable_flag_man_start_mute_audio + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU (0x1<<12) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU_POS 12 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU_MSK 0x1000 + +/* + * int_enable_flag_cfma_err + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER (0x1<<13) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER_POS 13 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER_MSK 0x2000 + +/* + * int_enable_flag_cfma_ack + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC (0x1<<14) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC_POS 14 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC_MSK 0x4000 + +/* + * int_enable_flag_clk_out_of_range + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR (0x1<<15) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR_POS 15 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR_MSK 0x8000 + + +/* + * (0x4a)-interrupt_enable_reg3 + */ + +/* + * int_enable_flag_tdm_error + */ +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER (0x1<<0) +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER_POS 0 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER_MSK 0x1 + +/* + * int_enable_flag_clip_left + */ +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL (0x1<<1) +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL_POS 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL_MSK 0x2 + +/* + * int_enable_flag_clip_right + */ +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR (0x1<<2) +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR_POS 2 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR_MSK 0x4 + +/* + * int_enable_flag_mic_ocpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1 (0x1<<3) +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1_POS 3 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1_MSK 0x8 + + +/* + * (0x4c)-status_polarity_reg1 + */ + +/* + * int_polarity_flag_por + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS (0x1<<0) +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS_POS 0 +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS_MSK 0x1 + +/* + * int_polarity_flag_pll_lock + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS (0x1<<1) +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS_POS 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS_MSK 0x2 + +/* + * int_polarity_flag_otpok + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS (0x1<<2) +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS_POS 2 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS_MSK 0x4 + +/* + * int_polarity_flag_ovpok + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS (0x1<<3) +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS_POS 3 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS_MSK 0x8 + +/* + * int_polarity_flag_uvpok + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS (0x1<<4) +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS_POS 4 +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS_MSK 0x10 + +/* + * int_polarity_flag_clocks_stable + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS (0x1<<5) +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS_POS 5 +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS_MSK 0x20 + +/* + * int_polarity_flag_mtp_busy + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB (0x1<<6) +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB_POS 6 +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB_MSK 0x40 + +/* + * int_polarity_flag_lost_clk + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK (0x1<<7) +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK_POS 7 +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK_MSK 0x80 + +/* + * int_polarity_flag_cf_speakererror + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS (0x1<<8) +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS_POS 8 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS_MSK 0x100 + +/* + * int_polarity_flag_cold_started + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS (0x1<<9) +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS_POS 9 +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS_MSK 0x200 + +/* + * int_polarity_flag_engage + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS (0x1<<10) +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS_POS 10 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS_MSK 0x400 + +/* + * int_polarity_flag_watchdog_reset + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS (0x1<<11) +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS_POS 11 +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS_MSK 0x800 + +/* + * int_polarity_flag_enbl_amp + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS (0x1<<12) +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS_POS 12 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS_MSK 0x1000 + +/* + * int_polarity_flag_enbl_ref + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS (0x1<<13) +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS_POS 13 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS_MSK 0x2000 + +/* + * int_polarity_flag_adc10_ready + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR (0x1<<14) +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR_POS 14 +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR_MSK 0x4000 + +/* + * int_polarity_flag_bod_vddd_nok + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK (0x1<<15) +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK_POS 15 +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK_MSK 0x8000 + + +/* + * (0x4d)-status_polarity_reg2 + */ + +/* + * int_polarity_flag_bst_bstcur + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU (0x1<<0) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU_POS 0 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU_MSK 0x1 + +/* + * int_polarity_flag_bst_hiz + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI (0x1<<1) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI_POS 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI_MSK 0x2 + +/* + * int_polarity_flag_bst_ocpok + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC (0x1<<2) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC_POS 2 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC_MSK 0x4 + +/* + * int_polarity_flag_bst_peakcur + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC (0x1<<3) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC_POS 3 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC_MSK 0x8 + +/* + * int_polarity_flag_bst_voutcomp + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC (0x1<<4) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC_POS 4 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC_MSK 0x10 + +/* + * int_polarity_flag_bst_voutcomp86 + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86 (0x1<<5) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86_POS 5 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86_MSK 0x20 + +/* + * int_polarity_flag_bst_voutcomp93 + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93 (0x1<<6) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93_POS 6 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93_MSK 0x40 + +/* + * int_polarity_flag_rcvldop_ready + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD (0x1<<7) +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD_POS 7 +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD_MSK 0x80 + +/* + * int_polarity_flag_ocp_alarm_left + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL (0x1<<8) +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL_POS 8 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL_MSK 0x100 + +/* + * int_polarity_flag_ocp_alarm_right + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR (0x1<<9) +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR_POS 9 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR_MSK 0x200 + +/* + * int_polarity_flag_man_wait_src_settings + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC (0x1<<10) +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC_POS 10 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC_MSK 0x400 + +/* + * int_polarity_flag_man_wait_cf_config + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC (0x1<<11) +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC_POS 11 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC_MSK 0x800 + +/* + * int_polarity_flag_man_start_mute_audio + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU (0x1<<12) +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU_POS 12 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU_MSK 0x1000 + +/* + * int_polarity_flag_cfma_err + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER (0x1<<13) +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER_POS 13 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER_MSK 0x2000 + +/* + * int_polarity_flag_cfma_ack + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC (0x1<<14) +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC_POS 14 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC_MSK 0x4000 + +/* + * int_polarity_flag_clk_out_of_range + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR (0x1<<15) +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR_POS 15 +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR_MSK 0x8000 + + +/* + * (0x4e)-status_polarity_reg3 + */ + +/* + * int_polarity_flag_tdm_error + */ +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER (0x1<<0) +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER_POS 0 +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER_MSK 0x1 + +/* + * int_polarity_flag_clip_left + */ +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL (0x1<<1) +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL_POS 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL_MSK 0x2 + +/* + * int_polarity_flag_clip_right + */ +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR (0x1<<2) +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR_POS 2 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR_MSK 0x4 + +/* + * int_polarity_flag_mic_ocpok + */ +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM (0x1<<3) +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM_POS 3 +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM_MSK 0x8 + + +/* + * (0x50)-bat_prot_config + */ + +/* + * vbat_prot_attack_time + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSCR (0x3<<0) +#define TFA98XX_BAT_PROT_CONFIG_BSSCR_POS 0 +#define TFA98XX_BAT_PROT_CONFIG_BSSCR_LEN 2 +#define TFA98XX_BAT_PROT_CONFIG_BSSCR_MAX 3 +#define TFA98XX_BAT_PROT_CONFIG_BSSCR_MSK 0x3 + +/* + * vbat_prot_thlevel + */ +#define TFA98XX_BAT_PROT_CONFIG_BSST (0xf<<2) +#define TFA98XX_BAT_PROT_CONFIG_BSST_POS 2 +#define TFA98XX_BAT_PROT_CONFIG_BSST_LEN 4 +#define TFA98XX_BAT_PROT_CONFIG_BSST_MAX 15 +#define TFA98XX_BAT_PROT_CONFIG_BSST_MSK 0x3c + +/* + * vbat_prot_max_reduct + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSRL (0x3<<6) +#define TFA98XX_BAT_PROT_CONFIG_BSSRL_POS 6 +#define TFA98XX_BAT_PROT_CONFIG_BSSRL_LEN 2 +#define TFA98XX_BAT_PROT_CONFIG_BSSRL_MAX 3 +#define TFA98XX_BAT_PROT_CONFIG_BSSRL_MSK 0xc0 + +/* + * vbat_prot_release_time + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSRR (0x7<<8) +#define TFA98XX_BAT_PROT_CONFIG_BSSRR_POS 8 +#define TFA98XX_BAT_PROT_CONFIG_BSSRR_LEN 3 +#define TFA98XX_BAT_PROT_CONFIG_BSSRR_MAX 7 +#define TFA98XX_BAT_PROT_CONFIG_BSSRR_MSK 0x700 + +/* + * vbat_prot_hysterese + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSHY (0x3<<11) +#define TFA98XX_BAT_PROT_CONFIG_BSSHY_POS 11 +#define TFA98XX_BAT_PROT_CONFIG_BSSHY_LEN 2 +#define TFA98XX_BAT_PROT_CONFIG_BSSHY_MAX 3 +#define TFA98XX_BAT_PROT_CONFIG_BSSHY_MSK 0x1800 + +/* + * sel_vbat + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSR (0x1<<14) +#define TFA98XX_BAT_PROT_CONFIG_BSSR_POS 14 +#define TFA98XX_BAT_PROT_CONFIG_BSSR_LEN 1 +#define TFA98XX_BAT_PROT_CONFIG_BSSR_MAX 1 +#define TFA98XX_BAT_PROT_CONFIG_BSSR_MSK 0x4000 + +/* + * bypass_clipper + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSBY (0x1<<15) +#define TFA98XX_BAT_PROT_CONFIG_BSSBY_POS 15 +#define TFA98XX_BAT_PROT_CONFIG_BSSBY_LEN 1 +#define TFA98XX_BAT_PROT_CONFIG_BSSBY_MAX 1 +#define TFA98XX_BAT_PROT_CONFIG_BSSBY_MSK 0x8000 + + +/* + * (0x51)-audio_control + */ + +/* + * batsense_steepness + */ +#define TFA98XX_AUDIO_CONTROL_BSSS (0x1<<0) +#define TFA98XX_AUDIO_CONTROL_BSSS_POS 0 +#define TFA98XX_AUDIO_CONTROL_BSSS_LEN 1 +#define TFA98XX_AUDIO_CONTROL_BSSS_MAX 1 +#define TFA98XX_AUDIO_CONTROL_BSSS_MSK 0x1 + +/* + * soft_mute + */ +#define TFA98XX_AUDIO_CONTROL_INTSMUTE (0x1<<1) +#define TFA98XX_AUDIO_CONTROL_INTSMUTE_POS 1 +#define TFA98XX_AUDIO_CONTROL_INTSMUTE_LEN 1 +#define TFA98XX_AUDIO_CONTROL_INTSMUTE_MAX 1 +#define TFA98XX_AUDIO_CONTROL_INTSMUTE_MSK 0x2 + +/* + * cf_mute_left + */ +#define TFA98XX_AUDIO_CONTROL_CFSML (0x1<<2) +#define TFA98XX_AUDIO_CONTROL_CFSML_POS 2 +#define TFA98XX_AUDIO_CONTROL_CFSML_LEN 1 +#define TFA98XX_AUDIO_CONTROL_CFSML_MAX 1 +#define TFA98XX_AUDIO_CONTROL_CFSML_MSK 0x4 + +/* + * cf_mute_right + */ +#define TFA98XX_AUDIO_CONTROL_CFSMR (0x1<<3) +#define TFA98XX_AUDIO_CONTROL_CFSMR_POS 3 +#define TFA98XX_AUDIO_CONTROL_CFSMR_LEN 1 +#define TFA98XX_AUDIO_CONTROL_CFSMR_MAX 1 +#define TFA98XX_AUDIO_CONTROL_CFSMR_MSK 0x8 + +/* + * bypass_hp_left + */ +#define TFA98XX_AUDIO_CONTROL_HPFBYPL (0x1<<4) +#define TFA98XX_AUDIO_CONTROL_HPFBYPL_POS 4 +#define TFA98XX_AUDIO_CONTROL_HPFBYPL_LEN 1 +#define TFA98XX_AUDIO_CONTROL_HPFBYPL_MAX 1 +#define TFA98XX_AUDIO_CONTROL_HPFBYPL_MSK 0x10 + +/* + * bypass_hp_right + */ +#define TFA98XX_AUDIO_CONTROL_HPFBYPR (0x1<<5) +#define TFA98XX_AUDIO_CONTROL_HPFBYPR_POS 5 +#define TFA98XX_AUDIO_CONTROL_HPFBYPR_LEN 1 +#define TFA98XX_AUDIO_CONTROL_HPFBYPR_MAX 1 +#define TFA98XX_AUDIO_CONTROL_HPFBYPR_MSK 0x20 + +/* + * enbl_dpsa_left + */ +#define TFA98XX_AUDIO_CONTROL_DPSAL (0x1<<6) +#define TFA98XX_AUDIO_CONTROL_DPSAL_POS 6 +#define TFA98XX_AUDIO_CONTROL_DPSAL_LEN 1 +#define TFA98XX_AUDIO_CONTROL_DPSAL_MAX 1 +#define TFA98XX_AUDIO_CONTROL_DPSAL_MSK 0x40 + +/* + * enbl_dpsa_right + */ +#define TFA98XX_AUDIO_CONTROL_DPSAR (0x1<<7) +#define TFA98XX_AUDIO_CONTROL_DPSAR_POS 7 +#define TFA98XX_AUDIO_CONTROL_DPSAR_LEN 1 +#define TFA98XX_AUDIO_CONTROL_DPSAR_MAX 1 +#define TFA98XX_AUDIO_CONTROL_DPSAR_MSK 0x80 + +/* + * cf_volume + */ +#define TFA98XX_AUDIO_CONTROL_VOL (0xff<<8) +#define TFA98XX_AUDIO_CONTROL_VOL_POS 8 +#define TFA98XX_AUDIO_CONTROL_VOL_LEN 8 +#define TFA98XX_AUDIO_CONTROL_VOL_MAX 255 +#define TFA98XX_AUDIO_CONTROL_VOL_MSK 0xff00 + + +/* + * (0x52)-amplifier_config + */ + +/* + * ctrl_rcv + */ +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV (0x1<<0) +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV_POS 0 +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV_LEN 1 +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV_MAX 1 +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV_MSK 0x1 + +/* + * ctrl_cc + */ +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL (0x7<<2) +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL_POS 2 +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL_LEN 3 +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL_MAX 7 +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL_MSK 0x1c + +/* + * gain + */ +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN (0xff<<5) +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN_POS 5 +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN_LEN 8 +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN_MAX 255 +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN_MSK 0x1fe0 + +/* + * ctrl_slopectrl + */ +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE (0x1<<13) +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE_POS 13 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE_LEN 1 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE_MAX 1 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE_MSK 0x2000 + +/* + * ctrl_slope + */ +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET (0x3<<14) +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET_POS 14 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET_LEN 2 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET_MAX 3 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET_MSK 0xc000 + + +/* + * (0x5a)-audio_control2 + */ + +/* + * cf_volume_sec + */ +#define TFA98XX_AUDIO_CONTROL2_VOLSEC (0xff<<0) +#define TFA98XX_AUDIO_CONTROL2_VOLSEC_POS 0 +#define TFA98XX_AUDIO_CONTROL2_VOLSEC_LEN 8 +#define TFA98XX_AUDIO_CONTROL2_VOLSEC_MAX 255 +#define TFA98XX_AUDIO_CONTROL2_VOLSEC_MSK 0xff + +/* + * sw_profile + */ +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL (0xff<<8) +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL_POS 8 +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL_LEN 8 +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL_MAX 255 +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL_MSK 0xff00 + + +/* + * (0x70)-dcdc_control0 + */ + +/* + * boost_volt + */ +#define TFA98XX_DCDC_CONTROL0_DCVO (0x7<<0) +#define TFA98XX_DCDC_CONTROL0_DCVO_POS 0 +#define TFA98XX_DCDC_CONTROL0_DCVO_LEN 3 +#define TFA98XX_DCDC_CONTROL0_DCVO_MAX 7 +#define TFA98XX_DCDC_CONTROL0_DCVO_MSK 0x7 + +/* + * boost_cur + */ +#define TFA98XX_DCDC_CONTROL0_DCMCC (0xf<<3) +#define TFA98XX_DCDC_CONTROL0_DCMCC_POS 3 +#define TFA98XX_DCDC_CONTROL0_DCMCC_LEN 4 +#define TFA98XX_DCDC_CONTROL0_DCMCC_MAX 15 +#define TFA98XX_DCDC_CONTROL0_DCMCC_MSK 0x78 + +/* + * bst_coil_value + */ +#define TFA98XX_DCDC_CONTROL0_DCCV (0x3<<7) +#define TFA98XX_DCDC_CONTROL0_DCCV_POS 7 +#define TFA98XX_DCDC_CONTROL0_DCCV_LEN 2 +#define TFA98XX_DCDC_CONTROL0_DCCV_MAX 3 +#define TFA98XX_DCDC_CONTROL0_DCCV_MSK 0x180 + +/* + * boost_intel + */ +#define TFA98XX_DCDC_CONTROL0_DCIE (0x1<<9) +#define TFA98XX_DCDC_CONTROL0_DCIE_POS 9 +#define TFA98XX_DCDC_CONTROL0_DCIE_LEN 1 +#define TFA98XX_DCDC_CONTROL0_DCIE_MAX 1 +#define TFA98XX_DCDC_CONTROL0_DCIE_MSK 0x200 + +/* + * boost_speed + */ +#define TFA98XX_DCDC_CONTROL0_DCSR (0x1<<10) +#define TFA98XX_DCDC_CONTROL0_DCSR_POS 10 +#define TFA98XX_DCDC_CONTROL0_DCSR_LEN 1 +#define TFA98XX_DCDC_CONTROL0_DCSR_MAX 1 +#define TFA98XX_DCDC_CONTROL0_DCSR_MSK 0x400 + +/* + * dcdc_synchronisation + */ +#define TFA98XX_DCDC_CONTROL0_DCSYNCP (0x7<<11) +#define TFA98XX_DCDC_CONTROL0_DCSYNCP_POS 11 +#define TFA98XX_DCDC_CONTROL0_DCSYNCP_LEN 3 +#define TFA98XX_DCDC_CONTROL0_DCSYNCP_MAX 7 +#define TFA98XX_DCDC_CONTROL0_DCSYNCP_MSK 0x3800 + +/* + * dcdcoff_mode + */ +#define TFA98XX_DCDC_CONTROL0_DCDIS (0x1<<14) +#define TFA98XX_DCDC_CONTROL0_DCDIS_POS 14 +#define TFA98XX_DCDC_CONTROL0_DCDIS_LEN 1 +#define TFA98XX_DCDC_CONTROL0_DCDIS_MAX 1 +#define TFA98XX_DCDC_CONTROL0_DCDIS_MSK 0x4000 + + +/* + * (0x90)-cf_controls + */ + +/* + * cf_rst_dsp + */ +#define TFA98XX_CF_CONTROLS_RST (0x1<<0) +#define TFA98XX_CF_CONTROLS_RST_POS 0 +#define TFA98XX_CF_CONTROLS_RST_LEN 1 +#define TFA98XX_CF_CONTROLS_RST_MAX 1 +#define TFA98XX_CF_CONTROLS_RST_MSK 0x1 + +/* + * cf_dmem + */ +#define TFA98XX_CF_CONTROLS_DMEM (0x3<<1) +#define TFA98XX_CF_CONTROLS_DMEM_POS 1 +#define TFA98XX_CF_CONTROLS_DMEM_LEN 2 +#define TFA98XX_CF_CONTROLS_DMEM_MAX 3 +#define TFA98XX_CF_CONTROLS_DMEM_MSK 0x6 + +/* + * cf_aif + */ +#define TFA98XX_CF_CONTROLS_AIF (0x1<<3) +#define TFA98XX_CF_CONTROLS_AIF_POS 3 +#define TFA98XX_CF_CONTROLS_AIF_LEN 1 +#define TFA98XX_CF_CONTROLS_AIF_MAX 1 +#define TFA98XX_CF_CONTROLS_AIF_MSK 0x8 + +/* + * cf_int + */ +#define TFA98XX_CF_CONTROLS_CFINT (0x1<<4) +#define TFA98XX_CF_CONTROLS_CFINT_POS 4 +#define TFA98XX_CF_CONTROLS_CFINT_LEN 1 +#define TFA98XX_CF_CONTROLS_CFINT_MAX 1 +#define TFA98XX_CF_CONTROLS_CFINT_MSK 0x10 + +/* + * cf_cgate_off + */ +#define TFA98XX_CF_CONTROLS_CFCGATE (0x1<<5) +#define TFA98XX_CF_CONTROLS_CFCGATE_POS 5 +#define TFA98XX_CF_CONTROLS_CFCGATE_LEN 1 +#define TFA98XX_CF_CONTROLS_CFCGATE_MAX 1 +#define TFA98XX_CF_CONTROLS_CFCGATE_MSK 0x20 + +/* + * cf_req_cmd + */ +#define TFA98XX_CF_CONTROLS_REQCMD (0x1<<8) +#define TFA98XX_CF_CONTROLS_REQCMD_POS 8 +#define TFA98XX_CF_CONTROLS_REQCMD_LEN 1 +#define TFA98XX_CF_CONTROLS_REQCMD_MAX 1 +#define TFA98XX_CF_CONTROLS_REQCMD_MSK 0x100 + +/* + * cf_req_reset + */ +#define TFA98XX_CF_CONTROLS_REQRST (0x1<<9) +#define TFA98XX_CF_CONTROLS_REQRST_POS 9 +#define TFA98XX_CF_CONTROLS_REQRST_LEN 1 +#define TFA98XX_CF_CONTROLS_REQRST_MAX 1 +#define TFA98XX_CF_CONTROLS_REQRST_MSK 0x200 + +/* + * cf_req_mips + */ +#define TFA98XX_CF_CONTROLS_REQMIPS (0x1<<10) +#define TFA98XX_CF_CONTROLS_REQMIPS_POS 10 +#define TFA98XX_CF_CONTROLS_REQMIPS_LEN 1 +#define TFA98XX_CF_CONTROLS_REQMIPS_MAX 1 +#define TFA98XX_CF_CONTROLS_REQMIPS_MSK 0x400 + +/* + * cf_req_mute_ready + */ +#define TFA98XX_CF_CONTROLS_REQMUTED (0x1<<11) +#define TFA98XX_CF_CONTROLS_REQMUTED_POS 11 +#define TFA98XX_CF_CONTROLS_REQMUTED_LEN 1 +#define TFA98XX_CF_CONTROLS_REQMUTED_MAX 1 +#define TFA98XX_CF_CONTROLS_REQMUTED_MSK 0x800 + +/* + * cf_req_volume_ready + */ +#define TFA98XX_CF_CONTROLS_REQVOL (0x1<<12) +#define TFA98XX_CF_CONTROLS_REQVOL_POS 12 +#define TFA98XX_CF_CONTROLS_REQVOL_LEN 1 +#define TFA98XX_CF_CONTROLS_REQVOL_MAX 1 +#define TFA98XX_CF_CONTROLS_REQVOL_MSK 0x1000 + +/* + * cf_req_damage + */ +#define TFA98XX_CF_CONTROLS_REQDMG (0x1<<13) +#define TFA98XX_CF_CONTROLS_REQDMG_POS 13 +#define TFA98XX_CF_CONTROLS_REQDMG_LEN 1 +#define TFA98XX_CF_CONTROLS_REQDMG_MAX 1 +#define TFA98XX_CF_CONTROLS_REQDMG_MSK 0x2000 + +/* + * cf_req_calibrate_ready + */ +#define TFA98XX_CF_CONTROLS_REQCAL (0x1<<14) +#define TFA98XX_CF_CONTROLS_REQCAL_POS 14 +#define TFA98XX_CF_CONTROLS_REQCAL_LEN 1 +#define TFA98XX_CF_CONTROLS_REQCAL_MAX 1 +#define TFA98XX_CF_CONTROLS_REQCAL_MSK 0x4000 + +/* + * cf_req_reserved + */ +#define TFA98XX_CF_CONTROLS_REQRSV (0x1<<15) +#define TFA98XX_CF_CONTROLS_REQRSV_POS 15 +#define TFA98XX_CF_CONTROLS_REQRSV_LEN 1 +#define TFA98XX_CF_CONTROLS_REQRSV_MAX 1 +#define TFA98XX_CF_CONTROLS_REQRSV_MSK 0x8000 + + +/* + * (0x91)-cf_mad + */ + +/* + * cf_madd + */ +#define TFA98XX_CF_MAD_MADD (0xffff<<0) +#define TFA98XX_CF_MAD_MADD_POS 0 +#define TFA98XX_CF_MAD_MADD_LEN 16 +#define TFA98XX_CF_MAD_MADD_MAX 65535 +#define TFA98XX_CF_MAD_MADD_MSK 0xffff + + +/* + * (0x92)-cf_mem + */ + +/* + * cf_mema + */ +#define TFA98XX_CF_MEM_MEMA (0xffff<<0) +#define TFA98XX_CF_MEM_MEMA_POS 0 +#define TFA98XX_CF_MEM_MEMA_LEN 16 +#define TFA98XX_CF_MEM_MEMA_MAX 65535 +#define TFA98XX_CF_MEM_MEMA_MSK 0xffff + + +/* + * (0x93)-cf_status + */ + +/* + * cf_err + */ +#define TFA98XX_CF_STATUS_ERR (0xff<<0) +#define TFA98XX_CF_STATUS_ERR_POS 0 +#define TFA98XX_CF_STATUS_ERR_LEN 8 +#define TFA98XX_CF_STATUS_ERR_MAX 255 +#define TFA98XX_CF_STATUS_ERR_MSK 0xff + +/* + * cf_ack_cmd + */ +#define TFA98XX_CF_STATUS_ACKCMD (0x1<<8) +#define TFA98XX_CF_STATUS_ACKCMD_POS 8 +#define TFA98XX_CF_STATUS_ACKCMD_LEN 1 +#define TFA98XX_CF_STATUS_ACKCMD_MAX 1 +#define TFA98XX_CF_STATUS_ACKCMD_MSK 0x100 + +/* + * cf_ack_reset + */ +#define TFA98XX_CF_STATUS_ACKRST (0x1<<9) +#define TFA98XX_CF_STATUS_ACKRST_POS 9 +#define TFA98XX_CF_STATUS_ACKRST_LEN 1 +#define TFA98XX_CF_STATUS_ACKRST_MAX 1 +#define TFA98XX_CF_STATUS_ACKRST_MSK 0x200 + +/* + * cf_ack_mips + */ +#define TFA98XX_CF_STATUS_ACKMIPS (0x1<<10) +#define TFA98XX_CF_STATUS_ACKMIPS_POS 10 +#define TFA98XX_CF_STATUS_ACKMIPS_LEN 1 +#define TFA98XX_CF_STATUS_ACKMIPS_MAX 1 +#define TFA98XX_CF_STATUS_ACKMIPS_MSK 0x400 + +/* + * cf_ack_mute_ready + */ +#define TFA98XX_CF_STATUS_ACKMUTED (0x1<<11) +#define TFA98XX_CF_STATUS_ACKMUTED_POS 11 +#define TFA98XX_CF_STATUS_ACKMUTED_LEN 1 +#define TFA98XX_CF_STATUS_ACKMUTED_MAX 1 +#define TFA98XX_CF_STATUS_ACKMUTED_MSK 0x800 + +/* + * cf_ack_volume_ready + */ +#define TFA98XX_CF_STATUS_ACKVOL (0x1<<12) +#define TFA98XX_CF_STATUS_ACKVOL_POS 12 +#define TFA98XX_CF_STATUS_ACKVOL_LEN 1 +#define TFA98XX_CF_STATUS_ACKVOL_MAX 1 +#define TFA98XX_CF_STATUS_ACKVOL_MSK 0x1000 + +/* + * cf_ack_damage + */ +#define TFA98XX_CF_STATUS_ACKDMG (0x1<<13) +#define TFA98XX_CF_STATUS_ACKDMG_POS 13 +#define TFA98XX_CF_STATUS_ACKDMG_LEN 1 +#define TFA98XX_CF_STATUS_ACKDMG_MAX 1 +#define TFA98XX_CF_STATUS_ACKDMG_MSK 0x2000 + +/* + * cf_ack_calibrate_ready + */ +#define TFA98XX_CF_STATUS_ACKCAL (0x1<<14) +#define TFA98XX_CF_STATUS_ACKCAL_POS 14 +#define TFA98XX_CF_STATUS_ACKCAL_LEN 1 +#define TFA98XX_CF_STATUS_ACKCAL_MAX 1 +#define TFA98XX_CF_STATUS_ACKCAL_MSK 0x4000 + +/* + * cf_ack_reserved + */ +#define TFA98XX_CF_STATUS_ACKRSV (0x1<<15) +#define TFA98XX_CF_STATUS_ACKRSV_POS 15 +#define TFA98XX_CF_STATUS_ACKRSV_LEN 1 +#define TFA98XX_CF_STATUS_ACKRSV_MAX 1 +#define TFA98XX_CF_STATUS_ACKRSV_MSK 0x8000 + + +/* + * (0xa1)-mtpkey2_reg + */ + +/* + * mtpkey2 + */ +#define TFA98XX_MTPKEY2_REG_MTPK (0xff<<0) +#define TFA98XX_MTPKEY2_REG_MTPK_POS 0 +#define TFA98XX_MTPKEY2_REG_MTPK_LEN 8 +#define TFA98XX_MTPKEY2_REG_MTPK_MAX 255 +#define TFA98XX_MTPKEY2_REG_MTPK_MSK 0xff + + +/* + * (0xa2)-mtp_status + */ + +/* + * key01_locked + */ +#define TFA98XX_MTP_STATUS_KEY1LOCKED (0x1<<0) +#define TFA98XX_MTP_STATUS_KEY1LOCKED_POS 0 +#define TFA98XX_MTP_STATUS_KEY1LOCKED_LEN 1 +#define TFA98XX_MTP_STATUS_KEY1LOCKED_MAX 1 +#define TFA98XX_MTP_STATUS_KEY1LOCKED_MSK 0x1 + +/* + * key02_locked + */ +#define TFA98XX_MTP_STATUS_KEY2LOCKED (0x1<<1) +#define TFA98XX_MTP_STATUS_KEY2LOCKED_POS 1 +#define TFA98XX_MTP_STATUS_KEY2LOCKED_LEN 1 +#define TFA98XX_MTP_STATUS_KEY2LOCKED_MAX 1 +#define TFA98XX_MTP_STATUS_KEY2LOCKED_MSK 0x2 + + +/* + * (0xa3)-KEY_protected_mtp_control + */ + +/* + * auto_copy_iic_to_mtp + */ +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP (0x1<<6) +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP_POS 6 +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP_LEN 1 +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP_MAX 1 +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP_MSK 0x40 + + +/* + * (0xa5)-mtp_data_out_msb + */ + +/* + * mtp_man_data_out_msb + */ +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB (0xffff<<0) +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB_POS 0 +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB_LEN 16 +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB_MAX 65535 +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB_MSK 0xffff + + +/* + * (0xa6)-mtp_data_out_lsb + */ + +/* + * mtp_man_data_out_lsb + */ +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB (0xffff<<0) +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB_POS 0 +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB_LEN 16 +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB_MAX 65535 +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB_MSK 0xffff + + +/* + * (0xb1)-temp_sensor_config + */ + +/* + * ext_temp + */ +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS (0x1ff<<0) +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS_POS 0 +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS_LEN 9 +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS_MAX 511 +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS_MSK 0x1ff + +/* + * ext_temp_sel + */ +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS (0x1<<9) +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS_POS 9 +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS_LEN 1 +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS_MAX 1 +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS_MSK 0x200 + + +/* + * (0xf0)-KEY2_protected_MTP0 + */ + +/* + * calibration_onetime + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC (0x1<<0) +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_POS 0 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_LEN 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MAX 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MSK 0x1 + +/* + * calibr_ron_done + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX (0x1<<1) +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_POS 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_LEN 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MAX 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK 0x2 + +/* + * calibr_dcdc_api_calibrate + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI (0x1<<2) +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI_POS 2 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI_LEN 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI_MAX 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI_MSK 0x4 + +/* + * calibr_dcdc_delta_sign + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB (0x1<<3) +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB_POS 3 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB_LEN 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB_MAX 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB_MSK 0x8 + +/* + * calibr_dcdc_delta + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF (0x7<<4) +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF_POS 4 +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF_LEN 3 +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF_MAX 7 +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF_MSK 0x70 + + +/* + * (0xf4)-KEY1_protected_MTP4 + */ + + +/* + * (0xf5)-KEY1_protected_MTP5 + */ + +#endif /* TFA98XX_GENREGS_H */ diff --git a/sound/soc/codecs/tfa98xx_parameters.h b/sound/soc/codecs/tfa98xx_parameters.h new file mode 100644 index 000000000000..d2d68f7e598c --- /dev/null +++ b/sound/soc/codecs/tfa98xx_parameters.h @@ -0,0 +1,724 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA98XXPARAMETERS_H_ +#define TFA98XXPARAMETERS_H_ + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#include "tfa_service.h" + +#if (defined(WIN32) || defined(_X64)) +/* These warnings are disabled because it is only given by Windows and there is no easy fix */ +#pragma warning(disable:4200) +#pragma warning(disable:4214) +#endif + +/* + * profiles & volumesteps + * + */ +#define TFA_MAX_PROFILES (64) +#define TFA_MAX_VSTEPS (64) +#define TFA_MAX_VSTEP_MSG_MARKER (100) /* This marker is used to indicate if all msgs need to be written to the device */ +#define TFA_MAX_MSGS (10) + +// the pack pragma is required to make that the size in memory +// matches the actual variable lenghts +// This is to assure that the binary files can be transported between +// different platforms. +#pragma pack (push, 1) + +/* + * typedef for 24 bit value using 3 bytes + */ +typedef struct uint24 { + uint8_t b[3]; +} uint24_t; +/* + * the generic header + * all char types are in ASCII + */ +typedef struct nxpTfaHeader { + uint16_t id; + char version[2]; // "V_" : V=version, vv=subversion + char subversion[2]; // "vv" : vv=subversion + uint16_t size; // data size in bytes following CRC + uint32_t CRC; // 32-bits CRC for following data + char customer[8]; // “name of customer” + char application[8]; // “application name” + char type[8]; // “application type name” +} nxpTfaHeader_t; + +typedef enum nxpTfaSamplerate { + fs_8k, // 8kHz + fs_11k025, // 11.025kHz + fs_12k, // 12kHz + fs_16k, // 16kHz + fs_22k05, // 22.05kHz + fs_24k, // 24kHz + fs_32k, // 32kHz + fs_44k1, // 44.1kHz + fs_48k, // 48kHz + fs_96k, // 96kHz + fs_count // Should always be last item. +} nxpTfaSamplerate_t; + +// Keep in sync with nxpTfaSamplerate_t ! +static const int nxpTfaSamplerateHz[fs_count] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 96000 }; + + +/* + * coolflux direct memory access + */ +typedef struct nxpTfaDspMem { + uint8_t type; /* 0--3: p, x, y, iomem */ + uint16_t address; /* target address */ + uint8_t size; /* data size in words */ + int words[]; /* payload in signed 32bit integer (two's complement) */ +} nxpTfaDspMem_t; + +/* + * the biquad coefficients for the API together with index in filter + * the biquad_index is the actual index in the equalizer +1 + */ +#define BIQUAD_COEFF_SIZE 6 + +/* +* Output fixed point coeffs structure +*/ +typedef struct { + int a2; + int a1; + int b2; + int b1; + int b0; +} nxpTfaBiquad_t; + +typedef struct nxpTfaBiquadOld { + uint8_t bytes[BIQUAD_COEFF_SIZE*sizeof(uint24_t)]; +} nxpTfaBiquadOld_t; + +typedef struct nxpTfaBiquadFloat { + float headroom; + float b0; + float b1; + float b2; + float a1; + float a2; +} nxpTfaBiquadFloat_t; + +/* +* EQ filter definitions +* Note: This is not in line with smartstudio (JV: 12/12/2016) +*/ +typedef enum nxpTfaFilterType { + fCustom, //User defined biquad coefficients + fFlat, //Vary only gain + fLowpass, //2nd order Butterworth low pass + fHighpass, //2nd order Butterworth high pass + fLowshelf, + fHighshelf, + fNotch, + fPeak, + fBandpass, + f1stLP, + f1stHP, + fElliptic +} nxpTfaFilterType_t; + +/* + * filter parameters for biquad (re-)calculation + */ +typedef struct nxpTfaFilter { + nxpTfaBiquadOld_t biquad; + uint8_t enabled; + uint8_t type; // (== enum FilterTypes, assure 8bits length) + float frequency; + float Q; + float gain; +} nxpTfaFilter_t ; //8 * float + int32 + byte == 37 + +/* + * biquad params for calculation +*/ + +#define TFA_BQ_EQ_INDEX 0 +#define TFA_BQ_ANTI_ALIAS_INDEX 10 +#define TFA_BQ_INTEGRATOR_INDEX 13 + +/* +* Loudspeaker Compensation filter definitions +*/ +typedef struct nxpTfaLsCompensationFilter { + nxpTfaBiquad_t biquad; + uint8_t lsCompOn; // Loudspeaker compensation on/off; when 'off', the DSP code doesn't apply the bwExt => bwExtOn GUI flag should be gray to avoid confusion + uint8_t bwExtOn; // Bandwidth extension on/off + float fRes; // [Hz] speaker resonance frequency + float Qt; // Speaker resonance Q-factor + float fBwExt; // [Hz] Band width extension frequency + float samplingFreq;// [Hz] Sampling frequency +} nxpTfaLsCompensationFilter_t; + +/* +* Anti Aliasing Elliptic filter definitions +*/ +typedef struct nxpTfaAntiAliasFilter { + nxpTfaBiquad_t biquad; /**< Output results fixed point coeffs */ + uint8_t enabled; + float cutOffFreq; // cut off frequency + float samplingFreq; // sampling frequency + float rippleDb; // range: [0.1 3.0] + float rolloff; // range: [-1.0 1.0] +} nxpTfaAntiAliasFilter_t; + +/** +* Integrator filter input definitions +*/ +typedef struct nxpTfaIntegratorFilter { + nxpTfaBiquad_t biquad; /**< Output results fixed point coeffs */ + uint8_t type; /**< Butterworth filter type: high or low pass */ + float cutOffFreq; /**< cut off frequency in Hertz; range: [100.0 4000.0] */ + float samplingFreq; /**< sampling frequency in Hertz */ + float leakage; /**< leakage factor; range [0.0 1.0] */ +} nxpTfaIntegratorFilter_t; + + +typedef struct nxpTfaEqFilter { + nxpTfaBiquad_t biquad; + uint8_t enabled; + uint8_t type; // (== enum FilterTypes, assure 8bits length) + float cutOffFreq; // cut off frequency, // range: [100.0 4000.0] + float samplingFreq; // sampling frequency + float Q; // range: [0.5 5.0] + float gainDb; // range: [-10.0 10.0] +} nxpTfaEqFilter_t ; //8 * float + int32 + byte == 37 + +typedef struct nxpTfaContAntiAlias { + int8_t index; /**< index determines destination type; anti-alias, integrator,eq */ + uint8_t type; + float cutOffFreq; // cut off frequency + float samplingFreq; + float rippleDb; // integrator leakage + float rolloff; + uint8_t bytes[5*3]; // payload 5*24buts coeffs +} nxpTfaContAntiAlias_t; + +typedef struct nxpTfaContIntegrator { + int8_t index; /**< index determines destination type; anti-alias, integrator,eq */ + uint8_t type; + float cutOffFreq; // cut off frequency + float samplingFreq; + float leakage; // integrator leakage + float reserved; + uint8_t bytes[5*3]; // payload 5*24buts coeffs +} nxpTfaContIntegrator_t; + +typedef struct nxpTfaContEq { + int8_t index; + uint8_t type; // (== enum FilterTypes, assure 8bits length) + float cutOffFreq; // cut off frequency, // range: [100.0 4000.0] + float samplingFreq; // sampling frequency + float Q; // range: [0.5 5.0] + float gainDb; // range: [-10.0 10.0] + uint8_t bytes[5*3]; // payload 5*24buts coeffs +} nxpTfaContEq_t ; //8 * float + int32 + byte == 37 + +typedef union nxpTfaContBiquad { + nxpTfaContEq_t eq; + nxpTfaContAntiAlias_t aa; + nxpTfaContIntegrator_t in; +} nxpTfaContBiquad_t; + +#define TFA_BQ_EQ_INDEX 0 +#define TFA_BQ_ANTI_ALIAS_INDEX 10 +#define TFA_BQ_INTEGRATOR_INDEX 13 +#define TFA98XX_MAX_EQ 10 + +typedef struct nxpTfaEqualizer { + nxpTfaFilter_t filter[TFA98XX_MAX_EQ]; +} nxpTfaEqualizer_t; + +/* + * files + */ +#define HDR(c1, c2) (c2<<8|c1) // little endian +typedef enum nxpTfaHeaderType { + paramsHdr = HDR('P', 'M'), /* containter file */ + volstepHdr = HDR('V', 'P'), + patchHdr = HDR('P', 'A'), + speakerHdr = HDR('S', 'P'), + presetHdr = HDR('P', 'R'), + configHdr = HDR('C', 'O'), + equalizerHdr = HDR('E', 'Q'), + drcHdr = HDR('D', 'R'), + msgHdr = HDR('M', 'G'), /* generic message */ + infoHdr = HDR('I', 'N') +} nxpTfaHeaderType_t; + +/* + * equalizer file + */ +#define NXPTFA_EQ_VERSION '1' +#define NXPTFA_EQ_SUBVERSION "00" +typedef struct nxpTfaEqualizerFile { + nxpTfaHeader_t hdr; + uint8_t samplerate; // ==enum samplerates, assure 8 bits + nxpTfaFilter_t filter[TFA98XX_MAX_EQ];// note: API index counts from 1..10 +} nxpTfaEqualizerFile_t; + +/* + * patch file + */ +#define NXPTFA_PA_VERSION '1' +#define NXPTFA_PA_SUBVERSION "00" +typedef struct nxpTfaPatchFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaPatch_t; + +/* + * generic message file + * - the payload of this file includes the opcode and is send straight to the DSP + */ +#define NXPTFA_MG_VERSION '3' +#define NXPTFA_MG_SUBVERSION "00" +typedef struct nxpTfaMsgFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaMsgFile_t; + +/* + * NOTE the tfa98xx API defines the enum Tfa98xx_config_type that defines + * the subtypes as decribes below. + * tfa98xx_dsp_config_parameter_type() can be used to get the + * supported type for the active device.. + */ +/* + * config file V1 sub 1 + */ +#define NXPTFA_CO_VERSION '1' +#define NXPTFA_CO3_VERSION '3' +#define NXPTFA_CO_SUBVERSION1 "01" +typedef struct nxpTfaConfigS1File { + nxpTfaHeader_t hdr; + uint8_t data[55*3]; +} nxpTfaConfigS1_t; + +/* + * config file V1 sub 2 + */ +#define NXPTFA_CO_SUBVERSION2 "02" +typedef struct nxpTfaConfigS2File { + nxpTfaHeader_t hdr; + uint8_t data[67*3]; +} nxpTfaConfigS2_t; + +/* + * config file V1 sub 3 + */ +#define NXPTFA_CO_SUBVERSION3 "03" +typedef struct nxpTfaConfigS3File { + nxpTfaHeader_t hdr; + uint8_t data[67*3]; +} nxpTfaConfigS3_t; + +/* + * config file V1.0 + */ +#define NXPTFA_CO_SUBVERSION "00" +typedef struct nxpTfaConfigFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaConfig_t; + +/* + * preset file + */ +#define NXPTFA_PR_VERSION '1' +#define NXPTFA_PR_SUBVERSION "00" +typedef struct nxpTfaPresetFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaPreset_t; + +/* + * drc file + */ +#define NXPTFA_DR_VERSION '1' +#define NXPTFA_DR_SUBVERSION "00" +typedef struct nxpTfaDrcFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaDrc_t; + +/* + * drc file + * for tfa 2 there is also a xml-version + */ +#define NXPTFA_DR3_VERSION '3' +#define NXPTFA_DR3_SUBVERSION "00" +typedef struct nxpTfaDrcFile2 { + nxpTfaHeader_t hdr; + uint8_t version[3]; + uint8_t data[]; +} nxpTfaDrc2_t; + +/* + * volume step structures + */ +// VP01 +#define NXPTFA_VP1_VERSION '1' +#define NXPTFA_VP1_SUBVERSION "01" +typedef struct nxpTfaVolumeStep1 { + float attenuation; // IEEE single float + uint8_t preset[TFA98XX_PRESET_LENGTH]; +} nxpTfaVolumeStep1_t; + +// VP02 +#define NXPTFA_VP2_VERSION '2' +#define NXPTFA_VP2_SUBVERSION "01" +typedef struct nxpTfaVolumeStep2 { + float attenuation; // IEEE single float + uint8_t preset[TFA98XX_PRESET_LENGTH]; + nxpTfaFilter_t filter[TFA98XX_MAX_EQ];// note: API index counts from 1..10 +} nxpTfaVolumeStep2_t; + +/* + * volumestep file + */ +#define NXPTFA_VP_VERSION '1' +#define NXPTFA_VP_SUBVERSION "00" +typedef struct nxpTfaVolumeStepFile { + nxpTfaHeader_t hdr; + uint8_t vsteps; // can also be calulated from size+type + uint8_t samplerate; // ==enum samplerates, assure 8 bits + uint8_t payload; //start of variable length contents:N times volsteps +} nxpTfaVolumeStepFile_t; +/* + * volumestep2 file + */ +typedef struct nxpTfaVolumeStep2File { + nxpTfaHeader_t hdr; + uint8_t vsteps; // can also be calulated from size+type + uint8_t samplerate; // ==enum samplerates, assure 8 bits + nxpTfaVolumeStep2_t vstep[]; //start of variable length contents:N times volsteps +} nxpTfaVolumeStep2File_t; + +/* + * volumestepMax2 file + */ +typedef struct nxpTfaVolumeStepMax2File { + nxpTfaHeader_t hdr; + uint8_t version[3]; + uint8_t NrOfVsteps; + uint8_t vstepsBin[]; +} nxpTfaVolumeStepMax2File_t; + +/* + * volumestepMax2 file + * This volumestep should ONLY be used for the use of bin2hdr! + * This can only be used to find the messagetype of the vstep (without header) + */ +typedef struct nxpTfaVolumeStepMax2_1File { + uint8_t version[3]; + uint8_t NrOfVsteps; + uint8_t vstepsBin[]; +} nxpTfaVolumeStepMax2_1File_t; + +struct nxpTfaVolumeStepRegisterInfo { + uint8_t NrOfRegisters; + uint16_t registerInfo[]; +}; + +struct nxpTfaVolumeStepMessageInfo { + uint8_t NrOfMessages; + uint8_t MessageType; + uint24_t MessageLength; + uint8_t CmdId[3]; + uint8_t ParameterData[]; +}; +/**************************old v2 *************************************************/ + +/* + * subv 00 volumestep file + */ +typedef struct nxpTfaOldHeader { + uint16_t id; + char version[2]; // "V_" : V=version, vv=subversion + char subversion[2]; // "vv" : vv=subversion + uint16_t size; // data size in bytes following CRC + uint32_t CRC; // 32-bits CRC for following data +} nxpTfaOldHeader_t; + +typedef struct nxpOldTfaFilter { + double bq[5]; + int32_t type; + double frequency; + double Q; + double gain; + uint8_t enabled; +} nxpTfaOldFilter_t ; + +typedef struct nxpTfaOldVolumeStep2 { + float attenuation; // IEEE single float + uint8_t preset[TFA98XX_PRESET_LENGTH]; + nxpTfaOldFilter_t eq[10]; +} nxpTfaOldVolumeStep2_t; + +typedef struct nxpTfaOldVolumeStepFile { + nxpTfaOldHeader_t hdr; + nxpTfaOldVolumeStep2_t step[]; +} nxpTfaOldVolumeStep2File_t; +/**************************end old v2 *************************************************/ + +/* + * speaker file header + */ +struct nxpTfaSpkHeader { + struct nxpTfaHeader hdr; + char name[8]; // speaker nick name (e.g. “dumbo”) + char vendor[16]; + char type[8]; + // dimensions (mm) + uint8_t height; + uint8_t width; + uint8_t depth; + uint16_t ohm; +}; + +/* + * speaker file + */ +#define NXPTFA_SP_VERSION '1' +#define NXPTFA_SP_SUBVERSION "00" +typedef struct nxpTfaSpeakerFile { + nxpTfaHeader_t hdr; + char name[8]; // speaker nick name (e.g. “dumbo”) + char vendor[16]; + char type[8]; + // dimensions (mm) + uint8_t height; + uint8_t width; + uint8_t depth; + uint8_t ohm_primary; + uint8_t ohm_secondary; + uint8_t data[]; //payload TFA98XX_SPEAKERPARAMETER_LENGTH +} nxpTfaSpeakerFile_t; + +#define NXPTFA_VP3_VERSION '3' +#define NXPTFA_VP3_SUBVERSION "00" + +struct nxpTfaFWVer { + uint8_t Major; + uint8_t minor; + uint8_t minor_update:6; + uint8_t Update:2; +}; + +struct nxpTfaFWMsg { + struct nxpTfaFWVer fwVersion; + struct nxpTfaMsg payload; +}; + +typedef struct nxpTfaLiveData { + char name[25]; + char addrs[25]; + int tracker; + int scalefactor; +} nxpTfaLiveData_t; + +#define NXPTFA_SP3_VERSION '3' +#define NXPTFA_SP3_SUBVERSION "00" +struct nxpTfaSpeakerFileMax2 { + nxpTfaHeader_t hdr; + char name[8]; // speaker nick name (e.g. “dumbo”) + char vendor[16]; + char type[8]; + // dimensions (mm) + uint8_t height; + uint8_t width; + uint8_t depth; + uint8_t ohm_primary; + uint8_t ohm_secondary; + struct nxpTfaFWMsg FWmsg; //payload including FW ver and Cmd ID +}; + +/* + * parameter container file + */ +/* + * descriptors + * Note 1: append new DescriptorType at the end + * Note 2: add new descriptors to dsc_name[] in tfaContUtil.c + */ +typedef enum nxpTfaDescriptorType { + dscDevice, // device list + dscProfile, // profile list + dscRegister, // register patch + dscString, // ascii, zero terminated string + dscFile, // filename + file contents + dscPatch, // patch file + dscMarker, // marker to indicate end of a list + dscMode, + dscSetInputSelect, + dscSetOutputSelect, + dscSetProgramConfig, + dscSetLagW, + dscSetGains, + dscSetvBatFactors, + dscSetSensesCal, + dscSetSensesDelay, + dscBitfield, + dscDefault, // used to reset bitfields to there default values + dscLiveData, + dscLiveDataString, + dscGroup, + dscCmd, + dscSetMBDrc, + dscFilter, + dscNoInit, + dscFeatures, + dscCfMem, // coolflux memory x,y,io + dscSetFwkUseCase, + dscSetVddpConfig, + dsc_last // trailer +} nxpTfaDescriptorType_t; + +#define TFA_BITFIELDDSCMSK 0x7fffffff +typedef struct nxpTfaDescPtr { + uint32_t offset:24; + uint32_t type:8; // (== enum nxpTfaDescriptorType, assure 8bits length) +} nxpTfaDescPtr_t; + +/* + * generic file descriptor + */ +typedef struct nxpTfaFileDsc { + nxpTfaDescPtr_t name; + uint32_t size; // file data length in bytes + uint8_t data[]; //payload +} nxpTfaFileDsc_t; + + +/* + * device descriptor list + */ +typedef struct nxpTfaDeviceList { + uint8_t length; // nr of items in the list + uint8_t bus; // bus + uint8_t dev; // device + uint8_t func; // subfunction or subdevice + uint32_t devid; // device hw fw id + nxpTfaDescPtr_t name; // device name + nxpTfaDescPtr_t list[]; // items list +} nxpTfaDeviceList_t; + +/* + * profile descriptor list + */ +typedef struct nxpTfaProfileList { + uint32_t length:8; // nr of items in the list + name + uint32_t group:8; // profile group number + uint32_t ID:16; // profile ID + nxpTfaDescPtr_t name; // profile name + nxpTfaDescPtr_t list[]; // items list (lenght-1 items) +} nxpTfaProfileList_t; +#define TFA_PROFID 0x1234 + +/* + * livedata descriptor list + */ +typedef struct nxpTfaLiveDataList { + uint32_t length:8; // nr of items in the list + uint32_t ID:24; // profile ID + nxpTfaDescPtr_t name; // livedata name + nxpTfaDescPtr_t list[]; // items list +} nxpTfaLiveDataList_t; +#define TFA_LIVEDATAID 0x5678 + +/* + * Bitfield descriptor + */ +typedef struct nxpTfaBitfield { + uint16_t value; + uint16_t field; // ==datasheet defined, 16 bits +} nxpTfaBitfield_t; + +/* + * Bitfield enumuration bits descriptor + */ +typedef struct nxpTfaBfEnum { + unsigned int len:4; // this is the actual length-1 + unsigned int pos:4; + unsigned int address:8; +} nxpTfaBfEnum_t; + +/* + * Register patch descriptor + */ +typedef struct nxpTfaRegpatch { + uint8_t address; // register address + uint16_t value; // value to write + uint16_t mask; // mask of bits to write +} nxpTfaRegpatch_t; + +/* + * Mode descriptor + */ +typedef struct nxpTfaUseCase { + int value; // mode value, maps to enum Tfa98xx_Mode +} nxpTfaMode_t; + +/* + * NoInit descriptor + */ +typedef struct nxpTfaNoInit { + uint8_t value; // noInit value +} nxpTfaNoInit_t; + +/* + * Features descriptor + */ +typedef struct nxpTfaFeatures { + uint16_t value[3]; // features value +} nxpTfaFeatures_t; + + +/* + * the container file + * - the size field is 32bits long (generic=16) + * - all char types are in ASCII + */ +#define NXPTFA_PM_VERSION '1' +#define NXPTFA_PM3_VERSION '3' +#define NXPTFA_PM_SUBVERSION '1' +typedef struct nxpTfaContainer { + char id[2]; // "XX" : XX=type + char version[2]; // "V_" : V=version, vv=subversion + char subversion[2]; // "vv" : vv=subversion + uint32_t size; // data size in bytes following CRC + uint32_t CRC; // 32-bits CRC for following data + uint16_t rev; // "extra chars for rev nr" + char customer[8]; // “name of customer” + char application[8]; // “application name” + char type[8]; // “application type name” + uint16_t ndev; // "nr of device lists" + uint16_t nprof; // "nr of profile lists" + uint16_t nliveData; // "nr of livedata lists" + nxpTfaDescPtr_t index[]; // start of item index table +} nxpTfaContainer_t; + +#pragma pack (pop) + +#endif /* TFA98XXPARAMETERS_H_ */ diff --git a/sound/soc/codecs/tfa98xx_tfafieldnames.h b/sound/soc/codecs/tfa98xx_tfafieldnames.h new file mode 100644 index 000000000000..09f98337c54c --- /dev/null +++ b/sound/soc/codecs/tfa98xx_tfafieldnames.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +typedef struct TfaBfName { + unsigned short bfEnum; + char *bfName; +} tfaBfName_t; + +typedef struct TfaIrqName { + unsigned short irqEnum; + char *irqName; +} tfaIrqName_t; + +#include "tfa1_tfafieldnames.h" +#include "tfa2_tfafieldnames_N1C.h" +/* diffs for specific devices */ +#include "tfa9887_tfafieldnames.h" +#include "tfa9890_tfafieldnames.h" +#include "tfa9891_tfafieldnames.h" +#include "tfa9872_tfafieldnames.h" +#include "tfa9912_tfafieldnames.h" +#include "tfa9896_tfafieldnames.h" +#include "tfa9874_tfafieldnames.h" +#include "tfa9878_tfafieldnames.h" +#include "tfa9894_tfafieldnames.h" +#include "tfa9894_tfafieldnames_N2.h" + +/* missing 'common' defs break the build but unused in TFA1 context */ +#define TFA1_BF_AMPINSEL -1 +#define TFA1_BF_MANSCONF -1 +#define TFA1_BF_MANCOLD -1 +#define TFA1_BF_INTSMUTE -1 +#define TFA1_BF_CFSMR -1 +#define TFA1_BF_CFSML -1 +#define TFA1_BF_DCMCCAPI -1 +#define TFA1_BF_DCMCCSB -1 +#define TFA1_BF_USERDEF -1 +#define TFA1_BF_MANSTATE -1 +#define TFA1_BF_MANOPER -1 +#define TFA1_BF_REFCKSEL -1 +#define TFA1_BF_VOLSEC -1 +#define TFA1_BF_FRACTDEL -1 +#define TFA1_BF_ACKDMG -1 +#define TFA1_BF_SSRIGHTE -1 +#define TFA1_BF_SSLEFTE -1 +#define TFA1_BF_R25CL -1 +#define TFA1_BF_R25CR -1 +#define TFA1_BF_SWPROFIL 0x8045 /*!< profile save */ +#define TFA1_BF_SWVSTEP 0x80a5 /*!< vstep save */ + +/* missing 'common' defs break the build */ +#define TFA2_BF_CFSM -1 + + +/* MTP access uses registers + * defs are derived from corresponding bitfield names as used in the BF macros + */ +#define MTPKEY2 MTPK /* unlock key2 MTPK */ +#define MTP0 MTPOTC /* MTP data */ +#define MTP_CONTROL CIMTP /* copy i2c to mtp */ + +/* interrupt enable register uses HW name in TFA2 */ +#define TFA2_BF_INTENVDDS TFA2_BF_IEVDDS + + +/* TFA9891 specific bit field names */ +#define TFA1_BF_SAAMGAIN 0x2202 +#define TFA2_BF_SAAMGAIN -1 + +/* TFA9872 specific bit field names */ +#define TFA2_BF_IELP0 TFA9872_BF_IELP0 +#define TFA2_BF_ISTLP0 TFA9872_BF_ISTLP0 +#define TFA2_BF_IPOLP0 TFA9872_BF_IPOLP0 +#define TFA2_BF_IELP1 TFA9872_BF_IELP1 +#define TFA2_BF_ISTLP1 TFA9872_BF_ISTLP1 +#define TFA2_BF_IPOLP1 TFA9872_BF_IPOLP1 +#define TFA2_BF_LP0 TFA9872_BF_LP0 +#define TFA2_BF_LP1 TFA9872_BF_LP1 +#define TFA2_BF_R25C TFA9872_BF_R25C +#define TFA2_BF_SAMMODE TFA9872_BF_SAMMODE + +/* interrupt bit field names of TFA2 and TFA1 do not match */ +#define TFA1_BF_IEACS TFA1_BF_INTENACS +#define TFA1_BF_IPOACS TFA1_BF_INTPOLACS +#define TFA1_BF_ISTACS TFA1_BF_INTOACS +#define TFA1_BF_ISTVDDS TFA1_BF_INTOVDDS +#define TFA1_BF_ICLVDDS TFA1_BF_INTIVDDS +#define TFA1_BF_IPOVDDS TFA1_BF_INTPOLVDDS +#define TFA1_BF_IENOCLK TFA1_BF_INTENNOCLK +#define TFA1_BF_ISTNOCLK TFA1_BF_INTONOCLK +#define TFA1_BF_IPONOCLK TFA1_BF_INTPOLNOCLK + +/* interrupt bit fields not available on TFA1 */ +#define TFA1_BF_IECLKOOR -1 +#define TFA1_BF_ISTCLKOOR -1 +#define TFA1_BF_IEMWSRC -1 +#define TFA1_BF_ISTMWSRC -1 +#define TFA1_BF_IPOMWSRC -1 +#define TFA1_BF_IEMWSMU -1 +#define TFA1_BF_ISTMWSMU -1 +#define TFA1_BF_IPOMWSMU -1 +#define TFA1_BF_IEMWCFC -1 +#define TFA1_BF_ISTMWCFC -1 +#define TFA1_BF_IPOMWCFC -1 +#define TFA1_BF_CLKOOR -1 +#define TFA1_BF_MANWAIT1 -1 +#define TFA1_BF_MANWAIT2 -1 +#define TFA1_BF_MANMUTE -1 +#define TFA1_BF_IPCLKOOR -1 +#define TFA1_BF_ICLCLKOOR -1 +#define TFA1_BF_IPOSWS -1 +#define TFA1_BF_IESWS -1 +#define TFA1_BF_ISTSWS -1 +#define TFA1_BF_IESPKS -1 +#define TFA1_BF_ISTSPKS -1 +#define TFA1_BF_IPOSPKS -1 +#define TFA1_BF_IECLKS -1 +#define TFA1_BF_ISTCLKS -1 +#define TFA1_BF_IPOCLKS -1 +#define TFA1_BF_IEAMPS -1 +#define TFA1_BF_ISTAMPS -1 +#define TFA1_BF_IPOAMPS -1 +#define TFA1_BF_IELP0 -1 +#define TFA1_BF_ISTLP0 -1 +#define TFA1_BF_IPOLP0 -1 +#define TFA1_BF_IELP1 -1 +#define TFA1_BF_ISTLP1 -1 +#define TFA1_BF_IPOLP1 -1 +#define TFA1_BF_LP0 -1 +#define TFA1_BF_LP1 -1 +#define TFA1_BF_R25C -1 +#define TFA1_BF_SAMMODE -1 + +/* TDM STATUS fields not available on TFA1 */ +#define TFA1_BF_TDMLUTER -1 +#define TFA1_BF_TDMERR -1 diff --git a/sound/soc/codecs/tfa9912_tfafieldnames.h b/sound/soc/codecs/tfa9912_tfafieldnames.h new file mode 100644 index 000000000000..34043ec052b8 --- /dev/null +++ b/sound/soc/codecs/tfa9912_tfafieldnames.h @@ -0,0 +1,1769 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef _TFA9912_TFAFIELDNAMES_H +#define _TFA9912_TFAFIELDNAMES_H + + +#define TFA9912_I2CVERSION 1.43 + +typedef enum nxpTfa9912BfEnumList { + TFA9912_BF_PWDN = 0x0000, /*!< Powerdown selection */ + TFA9912_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA9912_BF_CFE = 0x0020, /*!< Enable CoolFlux */ + TFA9912_BF_AMPE = 0x0030, /*!< Enables the Amplifier */ + TFA9912_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ + TFA9912_BF_SBSL = 0x0050, /*!< Coolflux configured */ + TFA9912_BF_AMPC = 0x0060, /*!< CoolFlux controls amplifier */ + TFA9912_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA9912_BF_FSSSEL = 0x0090, /*!< Audio sample reference */ + TFA9912_BF_BYPOCP = 0x00b0, /*!< Bypass OCP */ + TFA9912_BF_TSTOCP = 0x00c0, /*!< OCP testing control */ + TFA9912_BF_AMPINSEL = 0x0101, /*!< Amplifier input selection */ + TFA9912_BF_MANSCONF = 0x0120, /*!< I2C configured */ + TFA9912_BF_MANCOLD = 0x0130, /*!< Execute cold start */ + TFA9912_BF_MANAOOSC = 0x0140, /*!< Internal osc off at PWDN */ + TFA9912_BF_MANROBOD = 0x0150, /*!< Reaction on BOD */ + TFA9912_BF_BODE = 0x0160, /*!< BOD Enable */ + TFA9912_BF_BODHYS = 0x0170, /*!< BOD Hysteresis */ + TFA9912_BF_BODFILT = 0x0181, /*!< BOD filter */ + TFA9912_BF_BODTHLVL = 0x01a1, /*!< BOD threshold */ + TFA9912_BF_MUTETO = 0x01d0, /*!< Time out SB mute sequence */ + TFA9912_BF_RCVNS = 0x01e0, /*!< Noise shaper selection */ + TFA9912_BF_MANWDE = 0x01f0, /*!< Watchdog enable */ + TFA9912_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ + TFA9912_BF_INPLEV = 0x0240, /*!< TDM output attenuation */ + TFA9912_BF_FRACTDEL = 0x0255, /*!< V/I Fractional delay */ + TFA9912_BF_BYPHVBF = 0x02b0, /*!< Bypass HVBAT filter */ + TFA9912_BF_TDMC = 0x02c0, /*!< TDM Compatibility with TFA9872 */ + TFA9912_BF_ENBLADC10 = 0x02e0, /*!< ADC10 Enable - I2C direct mode */ + TFA9912_BF_REV = 0x030f, /*!< Revision info */ + TFA9912_BF_REFCKEXT = 0x0401, /*!< PLL external ref clock */ + TFA9912_BF_REFCKSEL = 0x0420, /*!< PLL internal ref clock */ + TFA9912_BF_ENCFCKSEL = 0x0430, /*!< Coolflux DSP clock scaling, low power mode */ + TFA9912_BF_CFCKSEL = 0x0441, /*!< Coolflux DSP clock scaler selection for low power mode */ + TFA9912_BF_TDMINFSEL = 0x0460, /*!< TDM clock selection */ + TFA9912_BF_DISBLAUTOCLKSEL = 0x0470, /*!< Disable Automatic dsp clock source selection */ + TFA9912_BF_SELCLKSRC = 0x0480, /*!< I2C selection of DSP clock when auto select is disabled */ + TFA9912_BF_SELTIMSRC = 0x0490, /*!< I2C selection of Watchdog and Timer clock */ + TFA9912_BF_SSLEFTE = 0x0500, /*!< */ + TFA9912_BF_SPKSSEN = 0x0510, /*!< Enable speaker path */ + TFA9912_BF_VSLEFTE = 0x0520, /*!< */ + TFA9912_BF_VSRIGHTE = 0x0530, /*!< Voltage sense */ + TFA9912_BF_CSLEFTE = 0x0540, /*!< */ + TFA9912_BF_CSRIGHTE = 0x0550, /*!< Current sense */ + TFA9912_BF_SSPDME = 0x0560, /*!< Sub-system PDM */ + TFA9912_BF_PGALE = 0x0570, /*!< Enable PGA chop clock for left channel */ + TFA9912_BF_PGARE = 0x0580, /*!< Enable PGA chop clock */ + TFA9912_BF_SSTDME = 0x0590, /*!< Sub-system TDM */ + TFA9912_BF_SSPBSTE = 0x05a0, /*!< Sub-system boost */ + TFA9912_BF_SSADCE = 0x05b0, /*!< Sub-system ADC */ + TFA9912_BF_SSFAIME = 0x05c0, /*!< Sub-system FAIM */ + TFA9912_BF_SSCFTIME = 0x05d0, /*!< CF Sub-system timer */ + TFA9912_BF_SSCFWDTE = 0x05e0, /*!< CF Sub-system WDT */ + TFA9912_BF_FAIMVBGOVRRL = 0x05f0, /*!< Over rule of vbg for FaIM access */ + TFA9912_BF_SAMSPKSEL = 0x0600, /*!< Input selection for TAP/SAM */ + TFA9912_BF_PDM2IISEN = 0x0610, /*!< PDM2IIS Bridge enable */ + TFA9912_BF_TAPRSTBYPASS = 0x0620, /*!< Tap decimator reset bypass - Bypass the decimator reset from tapdec */ + TFA9912_BF_CARDECISEL0 = 0x0631, /*!< Cardec input 0 sel */ + TFA9912_BF_CARDECISEL1 = 0x0651, /*!< Cardec input sel */ + TFA9912_BF_TAPDECSEL = 0x0670, /*!< Select TAP/Cardec for TAP */ + TFA9912_BF_COMPCOUNT = 0x0680, /*!< Comparator o/p filter selection */ + TFA9912_BF_STARTUPMODE = 0x0691, /*!< Startup Mode Selection */ + TFA9912_BF_AUTOTAP = 0x06b0, /*!< Enable auto tap switching */ + TFA9912_BF_COMPINITIME = 0x06c1, /*!< Comparator initialization time to be used in Tap Machine */ + TFA9912_BF_ANAPINITIME = 0x06e1, /*!< Analog initialization time to be used in Tap Machine */ + TFA9912_BF_CCHKTH = 0x0707, /*!< Clock check Higher Threshold */ + TFA9912_BF_CCHKTL = 0x0787, /*!< Clock check Higher Threshold */ + TFA9912_BF_AMPOCRT = 0x0802, /*!< Amplifier on-off criteria for shutdown */ + TFA9912_BF_AMPTCRR = 0x0832, /*!< Amplifier on-off criteria for tap mode entry */ + TFA9912_BF_STGS = 0x0d00, /*!< PDM side tone gain selector */ + TFA9912_BF_STGAIN = 0x0d18, /*!< Side tone gain */ + TFA9912_BF_STSMUTE = 0x0da0, /*!< Side tone soft mute */ + TFA9912_BF_ST1C = 0x0db0, /*!< side tone one s complement */ + TFA9912_BF_CMFBEL = 0x0e80, /*!< CMFB enable left */ + TFA9912_BF_VDDS = 0x1000, /*!< POR */ + TFA9912_BF_PLLS = 0x1010, /*!< PLL lock */ + TFA9912_BF_OTDS = 0x1020, /*!< OTP alarm */ + TFA9912_BF_OVDS = 0x1030, /*!< OVP alarm */ + TFA9912_BF_UVDS = 0x1040, /*!< UVP alarm */ + TFA9912_BF_CLKS = 0x1050, /*!< Clocks stable */ + TFA9912_BF_MTPB = 0x1060, /*!< MTP busy */ + TFA9912_BF_NOCLK = 0x1070, /*!< Lost clock */ + TFA9912_BF_ACS = 0x1090, /*!< Cold Start */ + TFA9912_BF_SWS = 0x10a0, /*!< Amplifier engage */ + TFA9912_BF_WDS = 0x10b0, /*!< Watchdog */ + TFA9912_BF_AMPS = 0x10c0, /*!< Amplifier enable */ + TFA9912_BF_AREFS = 0x10d0, /*!< References enable */ + TFA9912_BF_ADCCR = 0x10e0, /*!< Control ADC */ + TFA9912_BF_BODNOK = 0x10f0, /*!< BOD */ + TFA9912_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA9912_BF_DCDCA = 0x1110, /*!< DCDC active */ + TFA9912_BF_DCOCPOK = 0x1120, /*!< DCDC OCP nmos */ + TFA9912_BF_DCPEAKCUR = 0x1130, /*!< Indicates current is max in DC-to-DC converter */ + TFA9912_BF_DCHVBAT = 0x1140, /*!< DCDC level 1x */ + TFA9912_BF_DCH114 = 0x1150, /*!< DCDC level 1.14x */ + TFA9912_BF_DCH107 = 0x1160, /*!< DCDC level 1.07x */ + TFA9912_BF_STMUTEB = 0x1170, /*!< side tone (un)mute busy */ + TFA9912_BF_STMUTE = 0x1180, /*!< side tone mute state */ + TFA9912_BF_TDMLUTER = 0x1190, /*!< TDM LUT error */ + TFA9912_BF_TDMSTAT = 0x11a2, /*!< TDM status bits */ + TFA9912_BF_TDMERR = 0x11d0, /*!< TDM error */ + TFA9912_BF_HAPTIC = 0x11e0, /*!< Status haptic driver */ + TFA9912_BF_OCPOAP = 0x1300, /*!< OCPOK pmos A */ + TFA9912_BF_OCPOAN = 0x1310, /*!< OCPOK nmos A */ + TFA9912_BF_OCPOBP = 0x1320, /*!< OCPOK pmos B */ + TFA9912_BF_OCPOBN = 0x1330, /*!< OCPOK nmos B */ + TFA9912_BF_CLIPAH = 0x1340, /*!< Clipping A to Vddp */ + TFA9912_BF_CLIPAL = 0x1350, /*!< Clipping A to gnd */ + TFA9912_BF_CLIPBH = 0x1360, /*!< Clipping B to Vddp */ + TFA9912_BF_CLIPBL = 0x1370, /*!< Clipping B to gnd */ + TFA9912_BF_OCDS = 0x1380, /*!< OCP amplifier */ + TFA9912_BF_CLIPS = 0x1390, /*!< Amplifier clipping */ + TFA9912_BF_TCMPTRG = 0x13a0, /*!< Status Tap comparator triggered */ + TFA9912_BF_TAPDET = 0x13b0, /*!< Status Tap detected */ + TFA9912_BF_MANWAIT1 = 0x13c0, /*!< Wait HW I2C settings */ + TFA9912_BF_MANWAIT2 = 0x13d0, /*!< Wait CF config */ + TFA9912_BF_MANMUTE = 0x13e0, /*!< Audio mute sequence */ + TFA9912_BF_MANOPER = 0x13f0, /*!< Operating state */ + TFA9912_BF_SPKSL = 0x1400, /*!< Left speaker status */ + TFA9912_BF_SPKS = 0x1410, /*!< Speaker status */ + TFA9912_BF_CLKOOR = 0x1420, /*!< External clock status */ + TFA9912_BF_MANSTATE = 0x1433, /*!< Device manager status */ + TFA9912_BF_DCMODE = 0x1471, /*!< DCDC mode status bits */ + TFA9912_BF_DSPCLKSRC = 0x1490, /*!< DSP clock source selected by manager */ + TFA9912_BF_STARTUPMODSTAT = 0x14a1, /*!< Startup Mode Selected by Manager(Read Only) */ + TFA9912_BF_TSPMSTATE = 0x14c3, /*!< Tap Machine State */ + TFA9912_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA9912_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA9912_BF_VDDPS = 0x1709, /*!< IC VDDP voltage ( 1023*VDDP/13 V) */ + TFA9912_BF_DCILCF = 0x17a0, /*!< DCDC current limiting for DSP */ + TFA9912_BF_TDMUC = 0x2000, /*!< Mode setting */ + TFA9912_BF_DIO4SEL = 0x2011, /*!< DIO4 Input selection */ + TFA9912_BF_TDME = 0x2040, /*!< Enable TDM interface */ + TFA9912_BF_TDMMODE = 0x2050, /*!< Slave/master */ + TFA9912_BF_TDMCLINV = 0x2060, /*!< Reception data to BCK clock */ + TFA9912_BF_TDMFSLN = 0x2073, /*!< FS length */ + TFA9912_BF_TDMFSPOL = 0x20b0, /*!< FS polarity */ + TFA9912_BF_TDMNBCK = 0x20c3, /*!< N-BCK's in FS */ + TFA9912_BF_TDMSLOTS = 0x2103, /*!< N-slots in Frame */ + TFA9912_BF_TDMSLLN = 0x2144, /*!< N-bits in slot */ + TFA9912_BF_TDMBRMG = 0x2194, /*!< N-bits remaining */ + TFA9912_BF_TDMDEL = 0x21e0, /*!< data delay to FS */ + TFA9912_BF_TDMADJ = 0x21f0, /*!< data adjustment */ + TFA9912_BF_TDMOOMP = 0x2201, /*!< Received audio compression */ + TFA9912_BF_TDMSSIZE = 0x2224, /*!< Sample size per slot */ + TFA9912_BF_TDMTXDFO = 0x2271, /*!< Format unused bits in a slot */ + TFA9912_BF_TDMTXUS0 = 0x2291, /*!< Format unused slots GAINIO */ + TFA9912_BF_TDMTXUS1 = 0x22b1, /*!< Format unused slots DIO1 */ + TFA9912_BF_TDMTXUS2 = 0x22d1, /*!< Format unused slots DIO2 */ + TFA9912_BF_TDMGIE = 0x2300, /*!< Control gain (channel in 0) */ + TFA9912_BF_TDMDCE = 0x2310, /*!< Control audio left (channel in 1 ) */ + TFA9912_BF_TDMSPKE = 0x2320, /*!< Control audio right (channel in 2 ) */ + TFA9912_BF_TDMCSE = 0x2330, /*!< Current sense */ + TFA9912_BF_TDMVSE = 0x2340, /*!< Voltage sense */ + TFA9912_BF_TDMGOE = 0x2350, /*!< DSP Gainout */ + TFA9912_BF_TDMCF2E = 0x2360, /*!< DSP 2 */ + TFA9912_BF_TDMCF3E = 0x2370, /*!< DSP 3 */ + TFA9912_BF_TDMCFE = 0x2380, /*!< DSP */ + TFA9912_BF_TDMES6 = 0x2390, /*!< Loopback of Audio left (channel 1) */ + TFA9912_BF_TDMES7 = 0x23a0, /*!< Loopback of Audio right (channel 2) */ + TFA9912_BF_TDMCF4E = 0x23b0, /*!< AEC ref right control */ + TFA9912_BF_TDMPD1E = 0x23c0, /*!< PDM 1 control */ + TFA9912_BF_TDMPD2E = 0x23d0, /*!< PDM 2 control */ + TFA9912_BF_TDMGIN = 0x2401, /*!< IO gainin */ + TFA9912_BF_TDMLIO = 0x2421, /*!< IO audio left */ + TFA9912_BF_TDMRIO = 0x2441, /*!< IO audio right */ + TFA9912_BF_TDMCSIO = 0x2461, /*!< IO Current Sense */ + TFA9912_BF_TDMVSIO = 0x2481, /*!< IO voltage sense */ + TFA9912_BF_TDMGOIO = 0x24a1, /*!< IO gain out */ + TFA9912_BF_TDMCFIO2 = 0x24c1, /*!< IO DSP 2 */ + TFA9912_BF_TDMCFIO3 = 0x24e1, /*!< IO DSP 3 */ + TFA9912_BF_TDMCFIO = 0x2501, /*!< IO DSP */ + TFA9912_BF_TDMLPB6 = 0x2521, /*!< IO Source 6 */ + TFA9912_BF_TDMLPB7 = 0x2541, /*!< IO Source 7 */ + TFA9912_BF_TDMGS = 0x2603, /*!< Control gainin */ + TFA9912_BF_TDMDCS = 0x2643, /*!< tdm slot for audio left (channel 1) */ + TFA9912_BF_TDMSPKS = 0x2683, /*!< tdm slot for audio right (channel 2) */ + TFA9912_BF_TDMCSS = 0x26c3, /*!< Slot Position of Current Sense Out */ + TFA9912_BF_TDMVSS = 0x2703, /*!< Slot Position of Voltage sense */ + TFA9912_BF_TDMCGOS = 0x2743, /*!< Slot Position of GAIN out */ + TFA9912_BF_TDMCF2S = 0x2783, /*!< Slot Position DSPout2 */ + TFA9912_BF_TDMCF3S = 0x27c3, /*!< Slot Position DSPout3 */ + TFA9912_BF_TDMCFS = 0x2803, /*!< Slot Position of DSPout */ + TFA9912_BF_TDMEDAT6S = 0x2843, /*!< Slot Position of loopback channel left */ + TFA9912_BF_TDMEDAT7S = 0x2883, /*!< Slot Position of loopback channel right */ + TFA9912_BF_TDMTXUS3 = 0x2901, /*!< Format unused slots D3 */ + TFA9912_BF_PDMSM = 0x3100, /*!< PDM control */ + TFA9912_BF_PDMSTSEL = 0x3110, /*!< PDM Decimator input selection */ + TFA9912_BF_PDMSTENBL = 0x3120, /*!< Side tone input enable */ + TFA9912_BF_PDMLSEL = 0x3130, /*!< PDM data selection for left channel during PDM direct mode */ + TFA9912_BF_PDMRSEL = 0x3140, /*!< PDM data selection for right channel during PDM direct mode */ + TFA9912_BF_MICVDDE = 0x3150, /*!< Enable MICVDD */ + TFA9912_BF_PDMCLRAT = 0x3201, /*!< PDM BCK/Fs ratio */ + TFA9912_BF_PDMGAIN = 0x3223, /*!< PDM gain */ + TFA9912_BF_PDMOSEL = 0x3263, /*!< PDM output selection - RE/FE data combination */ + TFA9912_BF_SELCFHAPD = 0x32a0, /*!< Select the source for haptic data output (not for customer) */ + TFA9912_BF_ISTVDDS = 0x4000, /*!< Status POR */ + TFA9912_BF_ISTPLLS = 0x4010, /*!< Status PLL lock */ + TFA9912_BF_ISTOTDS = 0x4020, /*!< Status OTP alarm */ + TFA9912_BF_ISTOVDS = 0x4030, /*!< Status OVP alarm */ + TFA9912_BF_ISTUVDS = 0x4040, /*!< Status UVP alarm */ + TFA9912_BF_ISTCLKS = 0x4050, /*!< Status clocks stable */ + TFA9912_BF_ISTMTPB = 0x4060, /*!< Status MTP busy */ + TFA9912_BF_ISTNOCLK = 0x4070, /*!< Status lost clock */ + TFA9912_BF_ISTSPKS = 0x4080, /*!< Status speaker error */ + TFA9912_BF_ISTACS = 0x4090, /*!< Status cold start */ + TFA9912_BF_ISTSWS = 0x40a0, /*!< Status amplifier engage */ + TFA9912_BF_ISTWDS = 0x40b0, /*!< Status watchdog */ + TFA9912_BF_ISTAMPS = 0x40c0, /*!< Status amplifier enable */ + TFA9912_BF_ISTAREFS = 0x40d0, /*!< Status Ref enable */ + TFA9912_BF_ISTADCCR = 0x40e0, /*!< Status Control ADC */ + TFA9912_BF_ISTBODNOK = 0x40f0, /*!< Status BOD */ + TFA9912_BF_ISTBSTCU = 0x4100, /*!< Status DCDC current limiting */ + TFA9912_BF_ISTBSTHI = 0x4110, /*!< Status DCDC active */ + TFA9912_BF_ISTBSTOC = 0x4120, /*!< Status DCDC OCP */ + TFA9912_BF_ISTBSTPKCUR = 0x4130, /*!< Status bst peakcur */ + TFA9912_BF_ISTBSTVC = 0x4140, /*!< Status DCDC level 1x */ + TFA9912_BF_ISTBST86 = 0x4150, /*!< Status DCDC level 1.14x */ + TFA9912_BF_ISTBST93 = 0x4160, /*!< Status DCDC level 1.07x */ + TFA9912_BF_ISTRCVLD = 0x4170, /*!< Status rcvldop ready */ + TFA9912_BF_ISTOCPL = 0x4180, /*!< Status ocp alarm left */ + TFA9912_BF_ISTOCPR = 0x4190, /*!< Status ocp alarm */ + TFA9912_BF_ISTMWSRC = 0x41a0, /*!< Status Waits HW I2C settings */ + TFA9912_BF_ISTMWCFC = 0x41b0, /*!< Status waits CF config */ + TFA9912_BF_ISTMWSMU = 0x41c0, /*!< Status Audio mute sequence */ + TFA9912_BF_ISTCFMER = 0x41d0, /*!< Status cfma error */ + TFA9912_BF_ISTCFMAC = 0x41e0, /*!< Status cfma ack */ + TFA9912_BF_ISTCLKOOR = 0x41f0, /*!< Status flag_clk_out_of_range */ + TFA9912_BF_ISTTDMER = 0x4200, /*!< Status tdm error */ + TFA9912_BF_ISTCLPL = 0x4210, /*!< Status clip left */ + TFA9912_BF_ISTCLPR = 0x4220, /*!< Status clip */ + TFA9912_BF_ISTOCPM = 0x4230, /*!< Status mic ocpok */ + TFA9912_BF_ISTLP1 = 0x4250, /*!< Status low power mode1 */ + TFA9912_BF_ISTLA = 0x4260, /*!< Status low amplitude detection */ + TFA9912_BF_ISTVDDP = 0x4270, /*!< Status VDDP greater than VBAT */ + TFA9912_BF_ISTTAPDET = 0x4280, /*!< Status Tap detected */ + TFA9912_BF_ISTAUDMOD = 0x4290, /*!< Status Audio Mode activated */ + TFA9912_BF_ISTSAMMOD = 0x42a0, /*!< Status SAM Mode activated */ + TFA9912_BF_ISTTAPMOD = 0x42b0, /*!< Status Tap Mode Activated */ + TFA9912_BF_ISTTAPTRG = 0x42c0, /*!< Status Tap comparator triggered */ + TFA9912_BF_ICLVDDS = 0x4400, /*!< Clear POR */ + TFA9912_BF_ICLPLLS = 0x4410, /*!< Clear PLL lock */ + TFA9912_BF_ICLOTDS = 0x4420, /*!< Clear OTP alarm */ + TFA9912_BF_ICLOVDS = 0x4430, /*!< Clear OVP alarm */ + TFA9912_BF_ICLUVDS = 0x4440, /*!< Clear UVP alarm */ + TFA9912_BF_ICLCLKS = 0x4450, /*!< Clear clocks stable */ + TFA9912_BF_ICLMTPB = 0x4460, /*!< Clear mtp busy */ + TFA9912_BF_ICLNOCLK = 0x4470, /*!< Clear lost clk */ + TFA9912_BF_ICLSPKS = 0x4480, /*!< Clear speaker error */ + TFA9912_BF_ICLACS = 0x4490, /*!< Clear cold started */ + TFA9912_BF_ICLSWS = 0x44a0, /*!< Clear amplifier engage */ + TFA9912_BF_ICLWDS = 0x44b0, /*!< Clear watchdog */ + TFA9912_BF_ICLAMPS = 0x44c0, /*!< Clear enbl amp */ + TFA9912_BF_ICLAREFS = 0x44d0, /*!< Clear ref enable */ + TFA9912_BF_ICLADCCR = 0x44e0, /*!< Clear control ADC */ + TFA9912_BF_ICLBODNOK = 0x44f0, /*!< Clear BOD */ + TFA9912_BF_ICLBSTCU = 0x4500, /*!< Clear DCDC current limiting */ + TFA9912_BF_ICLBSTHI = 0x4510, /*!< Clear DCDC active */ + TFA9912_BF_ICLBSTOC = 0x4520, /*!< Clear DCDC OCP */ + TFA9912_BF_ICLBSTPC = 0x4530, /*!< Clear bst peakcur */ + TFA9912_BF_ICLBSTVC = 0x4540, /*!< Clear DCDC level 1x */ + TFA9912_BF_ICLBST86 = 0x4550, /*!< Clear DCDC level 1.14x */ + TFA9912_BF_ICLBST93 = 0x4560, /*!< Clear DCDC level 1.07x */ + TFA9912_BF_ICLRCVLD = 0x4570, /*!< Clear rcvldop ready */ + TFA9912_BF_ICLOCPL = 0x4580, /*!< Clear ocp alarm left */ + TFA9912_BF_ICLOCPR = 0x4590, /*!< Clear ocp alarm */ + TFA9912_BF_ICLMWSRC = 0x45a0, /*!< Clear wait HW I2C settings */ + TFA9912_BF_ICLMWCFC = 0x45b0, /*!< Clear wait cf config */ + TFA9912_BF_ICLMWSMU = 0x45c0, /*!< Clear audio mute sequence */ + TFA9912_BF_ICLCFMER = 0x45d0, /*!< Clear cfma err */ + TFA9912_BF_ICLCFMAC = 0x45e0, /*!< Clear cfma ack */ + TFA9912_BF_ICLCLKOOR = 0x45f0, /*!< Clear flag_clk_out_of_range */ + TFA9912_BF_ICLTDMER = 0x4600, /*!< Clear tdm error */ + TFA9912_BF_ICLCLPL = 0x4610, /*!< Clear clip left */ + TFA9912_BF_ICLCLP = 0x4620, /*!< Clear clip */ + TFA9912_BF_ICLOCPM = 0x4630, /*!< Clear mic ocpok */ + TFA9912_BF_ICLLP1 = 0x4650, /*!< Clear low power mode1 */ + TFA9912_BF_ICLLA = 0x4660, /*!< Clear low amplitude detection */ + TFA9912_BF_ICLVDDP = 0x4670, /*!< Clear VDDP greater then VBAT */ + TFA9912_BF_ICLTAPDET = 0x4680, /*!< Clear Tap detected */ + TFA9912_BF_ICLAUDMOD = 0x4690, /*!< Clear Audio Mode activated */ + TFA9912_BF_ICLSAMMOD = 0x46a0, /*!< Clear SAM Mode activated */ + TFA9912_BF_ICLTAPMOD = 0x46b0, /*!< Clear Tap Mode Activated */ + TFA9912_BF_ICLTAPTRG = 0x46c0, /*!< Clear Comparator Interrupt */ + TFA9912_BF_IEVDDS = 0x4800, /*!< Enable por */ + TFA9912_BF_IEPLLS = 0x4810, /*!< Enable pll lock */ + TFA9912_BF_IEOTDS = 0x4820, /*!< Enable OTP alarm */ + TFA9912_BF_IEOVDS = 0x4830, /*!< Enable OVP alarm */ + TFA9912_BF_IEUVDS = 0x4840, /*!< Enable UVP alarm */ + TFA9912_BF_IECLKS = 0x4850, /*!< Enable clocks stable */ + TFA9912_BF_IEMTPB = 0x4860, /*!< Enable mtp busy */ + TFA9912_BF_IENOCLK = 0x4870, /*!< Enable lost clk */ + TFA9912_BF_IESPKS = 0x4880, /*!< Enable speaker error */ + TFA9912_BF_IEACS = 0x4890, /*!< Enable cold started */ + TFA9912_BF_IESWS = 0x48a0, /*!< Enable amplifier engage */ + TFA9912_BF_IEWDS = 0x48b0, /*!< Enable watchdog */ + TFA9912_BF_IEAMPS = 0x48c0, /*!< Enable enbl amp */ + TFA9912_BF_IEAREFS = 0x48d0, /*!< Enable ref enable */ + TFA9912_BF_IEADCCR = 0x48e0, /*!< Enable Control ADC */ + TFA9912_BF_IEBODNOK = 0x48f0, /*!< Enable BOD */ + TFA9912_BF_IEBSTCU = 0x4900, /*!< Enable DCDC current limiting */ + TFA9912_BF_IEBSTHI = 0x4910, /*!< Enable DCDC active */ + TFA9912_BF_IEBSTOC = 0x4920, /*!< Enable DCDC OCP */ + TFA9912_BF_IEBSTPC = 0x4930, /*!< Enable bst peakcur */ + TFA9912_BF_IEBSTVC = 0x4940, /*!< Enable DCDC level 1x */ + TFA9912_BF_IEBST86 = 0x4950, /*!< Enable DCDC level 1.14x */ + TFA9912_BF_IEBST93 = 0x4960, /*!< Enable DCDC level 1.07x */ + TFA9912_BF_IERCVLD = 0x4970, /*!< Enable rcvldop ready */ + TFA9912_BF_IEOCPL = 0x4980, /*!< Enable ocp alarm left */ + TFA9912_BF_IEOCPR = 0x4990, /*!< Enable ocp alarm */ + TFA9912_BF_IEMWSRC = 0x49a0, /*!< Enable waits HW I2C settings */ + TFA9912_BF_IEMWCFC = 0x49b0, /*!< Enable man wait cf config */ + TFA9912_BF_IEMWSMU = 0x49c0, /*!< Enable man Audio mute sequence */ + TFA9912_BF_IECFMER = 0x49d0, /*!< Enable cfma err */ + TFA9912_BF_IECFMAC = 0x49e0, /*!< Enable cfma ack */ + TFA9912_BF_IECLKOOR = 0x49f0, /*!< Enable flag_clk_out_of_range */ + TFA9912_BF_IETDMER = 0x4a00, /*!< Enable tdm error */ + TFA9912_BF_IECLPL = 0x4a10, /*!< Enable clip left */ + TFA9912_BF_IECLPR = 0x4a20, /*!< Enable clip */ + TFA9912_BF_IEOCPM1 = 0x4a30, /*!< Enable mic ocpok */ + TFA9912_BF_IELP1 = 0x4a50, /*!< Enable low power mode1 */ + TFA9912_BF_IELA = 0x4a60, /*!< Enable low amplitude detection */ + TFA9912_BF_IEVDDP = 0x4a70, /*!< Enable VDDP greater than VBAT */ + TFA9912_BF_IETAPDET = 0x4a80, /*!< Enable Tap detected */ + TFA9912_BF_IEAUDMOD = 0x4a90, /*!< Enable Audio Mode activated */ + TFA9912_BF_IESAMMOD = 0x4aa0, /*!< Enable SAM Mode activated */ + TFA9912_BF_IETAPMOD = 0x4ab0, /*!< Enable Tap Mode Activated */ + TFA9912_BF_IETAPTRG = 0x4ac0, /*!< Enable comparator interrupt */ + TFA9912_BF_IPOVDDS = 0x4c00, /*!< Polarity por */ + TFA9912_BF_IPOPLLS = 0x4c10, /*!< Polarity pll lock */ + TFA9912_BF_IPOOTDS = 0x4c20, /*!< Polarity OTP alarm */ + TFA9912_BF_IPOOVDS = 0x4c30, /*!< Polarity OVP alarm */ + TFA9912_BF_IPOUVDS = 0x4c40, /*!< Polarity UVP alarm */ + TFA9912_BF_IPOCLKS = 0x4c50, /*!< Polarity clocks stable */ + TFA9912_BF_IPOMTPB = 0x4c60, /*!< Polarity mtp busy */ + TFA9912_BF_IPONOCLK = 0x4c70, /*!< Polarity lost clk */ + TFA9912_BF_IPOSPKS = 0x4c80, /*!< Polarity speaker error */ + TFA9912_BF_IPOACS = 0x4c90, /*!< Polarity cold started */ + TFA9912_BF_IPOSWS = 0x4ca0, /*!< Polarity amplifier engage */ + TFA9912_BF_IPOWDS = 0x4cb0, /*!< Polarity watchdog */ + TFA9912_BF_IPOAMPS = 0x4cc0, /*!< Polarity enbl amp */ + TFA9912_BF_IPOAREFS = 0x4cd0, /*!< Polarity ref enable */ + TFA9912_BF_IPOADCCR = 0x4ce0, /*!< Polarity Control ADC */ + TFA9912_BF_IPOBODNOK = 0x4cf0, /*!< Polarity BOD */ + TFA9912_BF_IPOBSTCU = 0x4d00, /*!< Polarity DCDC current limiting */ + TFA9912_BF_IPOBSTHI = 0x4d10, /*!< Polarity DCDC active */ + TFA9912_BF_IPOBSTOC = 0x4d20, /*!< Polarity DCDC OCP */ + TFA9912_BF_IPOBSTPC = 0x4d30, /*!< Polarity bst peakcur */ + TFA9912_BF_IPOBSTVC = 0x4d40, /*!< Polarity DCDC level 1x */ + TFA9912_BF_IPOBST86 = 0x4d50, /*!< Polarity DCDC level 1.14x */ + TFA9912_BF_IPOBST93 = 0x4d60, /*!< Polarity DCDC level 1.07x */ + TFA9912_BF_IPORCVLD = 0x4d70, /*!< Polarity rcvldop ready */ + TFA9912_BF_IPOOCPL = 0x4d80, /*!< Polarity ocp alarm left */ + TFA9912_BF_IPOOCPR = 0x4d90, /*!< Polarity ocp alarm */ + TFA9912_BF_IPOMWSRC = 0x4da0, /*!< Polarity waits HW I2C settings */ + TFA9912_BF_IPOMWCFC = 0x4db0, /*!< Polarity man wait cf config */ + TFA9912_BF_IPOMWSMU = 0x4dc0, /*!< Polarity man audio mute sequence */ + TFA9912_BF_IPOCFMER = 0x4dd0, /*!< Polarity cfma err */ + TFA9912_BF_IPOCFMAC = 0x4de0, /*!< Polarity cfma ack */ + TFA9912_BF_IPOCLKOOR = 0x4df0, /*!< Polarity flag_clk_out_of_range */ + TFA9912_BF_IPOTDMER = 0x4e00, /*!< Polarity tdm error */ + TFA9912_BF_IPOCLPL = 0x4e10, /*!< Polarity clip left */ + TFA9912_BF_IPOCLPR = 0x4e20, /*!< Polarity clip */ + TFA9912_BF_IPOOCPM = 0x4e30, /*!< Polarity mic ocpok */ + TFA9912_BF_IPOLP1 = 0x4e50, /*!< Polarity low power mode1 */ + TFA9912_BF_IPOLA = 0x4e60, /*!< Polarity low amplitude detection */ + TFA9912_BF_IPOVDDP = 0x4e70, /*!< Polarity VDDP greater than VBAT */ + TFA9912_BF_IPOLTAPDET = 0x4e80, /*!< PolarityTap detected */ + TFA9912_BF_IPOLAUDMOD = 0x4e90, /*!< PolarityAudio Mode activated */ + TFA9912_BF_IPOLSAMMOD = 0x4ea0, /*!< PolaritySAM Mode activated */ + TFA9912_BF_IPOLTAPMOD = 0x4eb0, /*!< Polarity Tap Mode Activated */ + TFA9912_BF_IPOLTAPTRG = 0x4ec0, /*!< PolarityTap Comparator Trigger */ + TFA9912_BF_BSSCR = 0x5001, /*!< Battery Safeguard attack time */ + TFA9912_BF_BSST = 0x5023, /*!< Battery Safeguard threshold voltage level */ + TFA9912_BF_BSSRL = 0x5061, /*!< Battery Safeguard maximum reduction */ + TFA9912_BF_BSSRR = 0x5082, /*!< Battery Safeguard release time */ + TFA9912_BF_BSSHY = 0x50b1, /*!< Battery Safeguard hysteresis */ + TFA9912_BF_BSSAC = 0x50d0, /*!< Reset clipper - Auto clear */ + TFA9912_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA9912_BF_BSSBY = 0x50f0, /*!< Bypass HW clipper */ + TFA9912_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ + TFA9912_BF_INTSMUTE = 0x5110, /*!< Soft mute HW */ + TFA9912_BF_CFSML = 0x5120, /*!< Soft mute FW left */ + TFA9912_BF_CFSM = 0x5130, /*!< Soft mute FW */ + TFA9912_BF_HPFBYPL = 0x5140, /*!< Bypass HPF left */ + TFA9912_BF_HPFBYP = 0x5150, /*!< Bypass HPF */ + TFA9912_BF_DPSAL = 0x5160, /*!< Enable DPSA left */ + TFA9912_BF_DPSA = 0x5170, /*!< Enable DPSA */ + TFA9912_BF_VOL = 0x5187, /*!< FW volume control for primary audio channel */ + TFA9912_BF_HNDSFRCV = 0x5200, /*!< Selection receiver */ + TFA9912_BF_CLIPCTRL = 0x5222, /*!< Clip control setting */ + TFA9912_BF_AMPGAIN = 0x5257, /*!< Amplifier gain */ + TFA9912_BF_SLOPEE = 0x52d0, /*!< Enables slope control */ + TFA9912_BF_SLOPESET = 0x52e0, /*!< Slope speed setting (bin. coded) */ + TFA9912_BF_CFTAPPAT = 0x5c07, /*!< Coolflux tap pattern */ + TFA9912_BF_TAPDBGINFO = 0x5c83, /*!< Reserved */ + TFA9912_BF_TATPSTAT1 = 0x5d0f, /*!< Tap Status 1 from CF FW */ + TFA9912_BF_TCOMPTHR = 0x5f03, /*!< Comparator threshold (in uV) */ + TFA9912_BF_PGAGAIN = 0x6081, /*!< PGA gain selection */ + TFA9912_BF_TDMSPKG = 0x6123, /*!< System gain (INPLEV 0) */ + TFA9912_BF_LPM1LVL = 0x6505, /*!< low power mode1 detector ctrl threshold for low_audio_lvl */ + TFA9912_BF_LPM1HLD = 0x6565, /*!< Low power mode1 detector, ctrl hold time before low audio is reckoned to be low audio */ + TFA9912_BF_LPM1DIS = 0x65c0, /*!< low power mode1 detector control */ + TFA9912_BF_DCDIS = 0x6630, /*!< DCDC */ + TFA9912_BF_TDMSRCMAP = 0x6801, /*!< tdm source mapping */ + TFA9912_BF_TDMSRCAS = 0x6821, /*!< frame a selection */ + TFA9912_BF_TDMSRCBS = 0x6841, /*!< frame b selection */ + TFA9912_BF_ANC1C = 0x68a0, /*!< ANC one s complement */ + TFA9912_BF_SAMMODE = 0x6901, /*!< Sam mode */ + TFA9912_BF_DCMCC = 0x7033, /*!< Max coil current */ + TFA9912_BF_DCCV = 0x7071, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ + TFA9912_BF_DCIE = 0x7090, /*!< Adaptive boost mode */ + TFA9912_BF_DCSR = 0x70a0, /*!< Soft ramp up/down */ + TFA9912_BF_DCINSEL = 0x70c1, /*!< DCDC IIR input Selection */ + TFA9912_BF_DCPWM = 0x70f0, /*!< DCDC PWM only mode */ + TFA9912_BF_DCTRIP = 0x7504, /*!< Adaptive boost trip levels 1, effective only when boost_intelligent is set to 1 */ + TFA9912_BF_DCTRIP2 = 0x7554, /*!< Adaptive boost trip level 2, effective only when boost_intelligent is set to 1 */ + TFA9912_BF_DCTRIPT = 0x75a4, /*!< Adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ + TFA9912_BF_DCVOF = 0x7635, /*!< First boost voltage level */ + TFA9912_BF_DCVOS = 0x7695, /*!< Second boost voltage level */ + TFA9912_BF_RST = 0x9000, /*!< Reset */ + TFA9912_BF_DMEM = 0x9011, /*!< Target memory */ + TFA9912_BF_AIF = 0x9030, /*!< Auto increment */ + TFA9912_BF_CFINT = 0x9040, /*!< Interrupt - auto clear */ + TFA9912_BF_CFCGATE = 0x9050, /*!< Coolflux clock gating disabling control */ + TFA9912_BF_REQCMD = 0x9080, /*!< Firmware event request rpc command */ + TFA9912_BF_REQRST = 0x9090, /*!< Firmware event request reset restart */ + TFA9912_BF_REQMIPS = 0x90a0, /*!< Firmware event request short on mips */ + TFA9912_BF_REQMUTED = 0x90b0, /*!< Firmware event request mute sequence ready */ + TFA9912_BF_REQVOL = 0x90c0, /*!< Firmware event request volume ready */ + TFA9912_BF_REQDMG = 0x90d0, /*!< Firmware event request speaker damage detected */ + TFA9912_BF_REQCAL = 0x90e0, /*!< Firmware event request calibration completed */ + TFA9912_BF_REQRSV = 0x90f0, /*!< Firmware event request reserved */ + TFA9912_BF_MADD = 0x910f, /*!< Memory address */ + TFA9912_BF_MEMA = 0x920f, /*!< Activate memory access */ + TFA9912_BF_ERR = 0x9307, /*!< Error flags */ + TFA9912_BF_ACKCMD = 0x9380, /*!< Firmware event acknowledge rpc command */ + TFA9912_BF_ACKRST = 0x9390, /*!< Firmware event acknowledge reset restart */ + TFA9912_BF_ACKMIPS = 0x93a0, /*!< Firmware event acknowledge short on mips */ + TFA9912_BF_ACKMUTED = 0x93b0, /*!< Firmware event acknowledge mute sequence ready */ + TFA9912_BF_ACKVOL = 0x93c0, /*!< Firmware event acknowledge volume ready */ + TFA9912_BF_ACKDMG = 0x93d0, /*!< Firmware event acknowledge speaker damage detected */ + TFA9912_BF_ACKCAL = 0x93e0, /*!< Firmware event acknowledge calibration completed */ + TFA9912_BF_ACKRSV = 0x93f0, /*!< Firmware event acknowledge reserved */ + TFA9912_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ + TFA9912_BF_KEY1LOCKED = 0xa200, /*!< Indicates KEY1 is locked */ + TFA9912_BF_KEY2LOCKED = 0xa210, /*!< Indicates KEY2 is locked */ + TFA9912_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp */ + TFA9912_BF_MTPRDMSB = 0xa50f, /*!< MSB word of MTP manual read data */ + TFA9912_BF_MTPRDLSB = 0xa60f, /*!< LSB word of MTP manual read data */ + TFA9912_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA9912_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA9912_BF_SWPROFIL = 0xee0f, /*!< Software profile data */ + TFA9912_BF_SWVSTEP = 0xef0f, /*!< Software vstep information */ + TFA9912_BF_MTPOTC = 0xf000, /*!< Calibration schedule */ + TFA9912_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA9912_BF_DCMCCAPI = 0xf020, /*!< Calibration current limit DCDC */ + TFA9912_BF_DCMCCSB = 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA9912_BF_DCMCCCL = 0xf042, /*!< Calibration delta current limit DCDC */ + TFA9912_BF_USERDEF = 0xf078, /*!< Reserved space for allowing customer to store speaker information */ + TFA9912_BF_R25C = 0xf40f, /*!< Ron resistance of speaker coil */ +} nxpTfa9912BfEnumList_t; +#define TFA9912_NAMETABLE static tfaBfName_t Tfa9912DatasheetNames[] = {\ + { 0x0, "PWDN"}, /* Powerdown selection , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x20, "CFE"}, /* Enable CoolFlux , */\ + { 0x30, "AMPE"}, /* Enables the Amplifier , */\ + { 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ + { 0x50, "SBSL"}, /* Coolflux configured , */\ + { 0x60, "AMPC"}, /* CoolFlux controls amplifier , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0x90, "FSSSEL"}, /* Audio sample reference , */\ + { 0xb0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xc0, "TSTOCP"}, /* OCP testing control , */\ + { 0x101, "AMPINSEL"}, /* Amplifier input selection , */\ + { 0x120, "MANSCONF"}, /* I2C configured , */\ + { 0x130, "MANCOLD"}, /* Execute cold start , */\ + { 0x140, "MANAOOSC"}, /* Internal osc off at PWDN , */\ + { 0x150, "MANROBOD"}, /* Reaction on BOD , */\ + { 0x160, "BODE"}, /* BOD Enable , */\ + { 0x170, "BODHYS"}, /* BOD Hysteresis , */\ + { 0x181, "BODFILT"}, /* BOD filter , */\ + { 0x1a1, "BODTHLVL"}, /* BOD threshold , */\ + { 0x1d0, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x1e0, "RCVNS"}, /* Noise shaper selection , */\ + { 0x1f0, "MANWDE"}, /* Watchdog enable , */\ + { 0x203, "AUDFS"}, /* Sample rate (fs) , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ + { 0x2b0, "BYPHVBF"}, /* Bypass HVBAT filter , */\ + { 0x2c0, "TDMC"}, /* TDM Compatibility with TFA9872 , */\ + { 0x2e0, "ENBLADC10"}, /* ADC10 Enable - I2C direct mode , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ + { 0x430, "ENCFCKSEL"}, /* Coolflux DSP clock scaling, low power mode , */\ + { 0x441, "CFCKSEL"}, /* Coolflux DSP clock scaler selection for low power mode, */\ + { 0x460, "TDMINFSEL"}, /* TDM clock selection , */\ + { 0x470, "DISBLAUTOCLKSEL"}, /* Disable Automatic dsp clock source selection , */\ + { 0x480, "SELCLKSRC"}, /* I2C selection of DSP clock when auto select is disabled, */\ + { 0x490, "SELTIMSRC"}, /* I2C selection of Watchdog and Timer clock , */\ + { 0x500, "SSLEFTE"}, /* , */\ + { 0x510, "SPKSSEN"}, /* Enable speaker path , */\ + { 0x520, "VSLEFTE"}, /* , */\ + { 0x530, "VSRIGHTE"}, /* Voltage sense , */\ + { 0x540, "CSLEFTE"}, /* , */\ + { 0x550, "CSRIGHTE"}, /* Current sense , */\ + { 0x560, "SSPDME"}, /* Sub-system PDM , */\ + { 0x570, "PGALE"}, /* Enable PGA chop clock for left channel , */\ + { 0x580, "PGARE"}, /* Enable PGA chop clock , */\ + { 0x590, "SSTDME"}, /* Sub-system TDM , */\ + { 0x5a0, "SSPBSTE"}, /* Sub-system boost , */\ + { 0x5b0, "SSADCE"}, /* Sub-system ADC , */\ + { 0x5c0, "SSFAIME"}, /* Sub-system FAIM , */\ + { 0x5d0, "SSCFTIME"}, /* CF Sub-system timer , */\ + { 0x5e0, "SSCFWDTE"}, /* CF Sub-system WDT , */\ + { 0x5f0, "FAIMVBGOVRRL"}, /* Over rule of vbg for FaIM access , */\ + { 0x600, "SAMSPKSEL"}, /* Input selection for TAP/SAM , */\ + { 0x610, "PDM2IISEN"}, /* PDM2IIS Bridge enable , */\ + { 0x620, "TAPRSTBYPASS"}, /* Tap decimator reset bypass - Bypass the decimator reset from tapdec, */\ + { 0x631, "CARDECISEL0"}, /* Cardec input 0 sel , */\ + { 0x651, "CARDECISEL1"}, /* Cardec input sel , */\ + { 0x670, "TAPDECSEL"}, /* Select TAP/Cardec for TAP , */\ + { 0x680, "COMPCOUNT"}, /* Comparator o/p filter selection , */\ + { 0x691, "STARTUPMODE"}, /* Startup Mode Selection , */\ + { 0x6b0, "AUTOTAP"}, /* Enable auto tap switching , */\ + { 0x6c1, "COMPINITIME"}, /* Comparator initialization time to be used in Tap Machine, */\ + { 0x6e1, "ANAPINITIME"}, /* Analog initialization time to be used in Tap Machine, */\ + { 0x707, "CCHKTH"}, /* Clock check Higher Threshold , */\ + { 0x787, "CCHKTL"}, /* Clock check Higher Threshold , */\ + { 0x802, "AMPOCRT"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x832, "AMPTCRR"}, /* Amplifier on-off criteria for tap mode entry , */\ + { 0xd00, "STGS"}, /* PDM side tone gain selector , */\ + { 0xd18, "STGAIN"}, /* Side tone gain , */\ + { 0xda0, "STSMUTE"}, /* Side tone soft mute , */\ + { 0xdb0, "ST1C"}, /* side tone one s complement , */\ + { 0xe80, "CMFBEL"}, /* CMFB enable left , */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "PLLS"}, /* PLL lock , */\ + { 0x1020, "OTDS"}, /* OTP alarm , */\ + { 0x1030, "OVDS"}, /* OVP alarm , */\ + { 0x1040, "UVDS"}, /* UVP alarm , */\ + { 0x1050, "CLKS"}, /* Clocks stable , */\ + { 0x1060, "MTPB"}, /* MTP busy , */\ + { 0x1070, "NOCLK"}, /* Lost clock , */\ + { 0x1090, "ACS"}, /* Cold Start , */\ + { 0x10a0, "SWS"}, /* Amplifier engage , */\ + { 0x10b0, "WDS"}, /* Watchdog , */\ + { 0x10c0, "AMPS"}, /* Amplifier enable , */\ + { 0x10d0, "AREFS"}, /* References enable , */\ + { 0x10e0, "ADCCR"}, /* Control ADC , */\ + { 0x10f0, "BODNOK"}, /* BOD , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active , */\ + { 0x1120, "DCOCPOK"}, /* DCDC OCP nmos , */\ + { 0x1130, "DCPEAKCUR"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1170, "STMUTEB"}, /* side tone (un)mute busy , */\ + { 0x1180, "STMUTE"}, /* side tone mute state , */\ + { 0x1190, "TDMLUTER"}, /* TDM LUT error , */\ + { 0x11a2, "TDMSTAT"}, /* TDM status bits , */\ + { 0x11d0, "TDMERR"}, /* TDM error , */\ + { 0x11e0, "HAPTIC"}, /* Status haptic driver , */\ + { 0x1300, "OCPOAP"}, /* OCPOK pmos A , */\ + { 0x1310, "OCPOAN"}, /* OCPOK nmos A , */\ + { 0x1320, "OCPOBP"}, /* OCPOK pmos B , */\ + { 0x1330, "OCPOBN"}, /* OCPOK nmos B , */\ + { 0x1340, "CLIPAH"}, /* Clipping A to Vddp , */\ + { 0x1350, "CLIPAL"}, /* Clipping A to gnd , */\ + { 0x1360, "CLIPBH"}, /* Clipping B to Vddp , */\ + { 0x1370, "CLIPBL"}, /* Clipping B to gnd , */\ + { 0x1380, "OCDS"}, /* OCP amplifier , */\ + { 0x1390, "CLIPS"}, /* Amplifier clipping , */\ + { 0x13a0, "TCMPTRG"}, /* Status Tap comparator triggered , */\ + { 0x13b0, "TAPDET"}, /* Status Tap detected , */\ + { 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ + { 0x13d0, "MANWAIT2"}, /* Wait CF config , */\ + { 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x13f0, "MANOPER"}, /* Operating state , */\ + { 0x1400, "SPKSL"}, /* Left speaker status , */\ + { 0x1410, "SPKS"}, /* Speaker status , */\ + { 0x1420, "CLKOOR"}, /* External clock status , */\ + { 0x1433, "MANSTATE"}, /* Device manager status , */\ + { 0x1471, "DCMODE"}, /* DCDC mode status bits , */\ + { 0x1490, "DSPCLKSRC"}, /* DSP clock source selected by manager , */\ + { 0x14a1, "STARTUPMODSTAT"}, /* Startup Mode Selected by Manager(Read Only) , */\ + { 0x14c3, "TSPMSTATE"}, /* Tap Machine State , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x1709, "VDDPS"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ + { 0x17a0, "DCILCF"}, /* DCDC current limiting for DSP , */\ + { 0x2000, "TDMUC"}, /* Mode setting , */\ + { 0x2011, "DIO4SEL"}, /* DIO4 Input selection , */\ + { 0x2040, "TDME"}, /* Enable TDM interface , */\ + { 0x2050, "TDMMODE"}, /* Slave/master , */\ + { 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2073, "TDMFSLN"}, /* FS length , */\ + { 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ + { 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ + { 0x2103, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x21e0, "TDMDEL"}, /* data delay to FS , */\ + { 0x21f0, "TDMADJ"}, /* data adjustment , */\ + { 0x2201, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2271, "TDMTXDFO"}, /* Format unused bits in a slot , */\ + { 0x2291, "TDMTXUS0"}, /* Format unused slots GAINIO , */\ + { 0x22b1, "TDMTXUS1"}, /* Format unused slots DIO1 , */\ + { 0x22d1, "TDMTXUS2"}, /* Format unused slots DIO2 , */\ + { 0x2300, "TDMGIE"}, /* Control gain (channel in 0) , */\ + { 0x2310, "TDMDCE"}, /* Control audio left (channel in 1 ) , */\ + { 0x2320, "TDMSPKE"}, /* Control audio right (channel in 2 ) , */\ + { 0x2330, "TDMCSE"}, /* Current sense , */\ + { 0x2340, "TDMVSE"}, /* Voltage sense , */\ + { 0x2350, "TDMGOE"}, /* DSP Gainout , */\ + { 0x2360, "TDMCF2E"}, /* DSP 2 , */\ + { 0x2370, "TDMCF3E"}, /* DSP 3 , */\ + { 0x2380, "TDMCFE"}, /* DSP , */\ + { 0x2390, "TDMES6"}, /* Loopback of Audio left (channel 1) , */\ + { 0x23a0, "TDMES7"}, /* Loopback of Audio right (channel 2) , */\ + { 0x23b0, "TDMCF4E"}, /* AEC ref right control , */\ + { 0x23c0, "TDMPD1E"}, /* PDM 1 control , */\ + { 0x23d0, "TDMPD2E"}, /* PDM 2 control , */\ + { 0x2401, "TDMGIN"}, /* IO gainin , */\ + { 0x2421, "TDMLIO"}, /* IO audio left , */\ + { 0x2441, "TDMRIO"}, /* IO audio right , */\ + { 0x2461, "TDMCSIO"}, /* IO Current Sense , */\ + { 0x2481, "TDMVSIO"}, /* IO voltage sense , */\ + { 0x24a1, "TDMGOIO"}, /* IO gain out , */\ + { 0x24c1, "TDMCFIO2"}, /* IO DSP 2 , */\ + { 0x24e1, "TDMCFIO3"}, /* IO DSP 3 , */\ + { 0x2501, "TDMCFIO"}, /* IO DSP , */\ + { 0x2521, "TDMLPB6"}, /* IO Source 6 , */\ + { 0x2541, "TDMLPB7"}, /* IO Source 7 , */\ + { 0x2603, "TDMGS"}, /* Control gainin , */\ + { 0x2643, "TDMDCS"}, /* tdm slot for audio left (channel 1) , */\ + { 0x2683, "TDMSPKS"}, /* tdm slot for audio right (channel 2) , */\ + { 0x26c3, "TDMCSS"}, /* Slot Position of Current Sense Out , */\ + { 0x2703, "TDMVSS"}, /* Slot Position of Voltage sense , */\ + { 0x2743, "TDMCGOS"}, /* Slot Position of GAIN out , */\ + { 0x2783, "TDMCF2S"}, /* Slot Position DSPout2 , */\ + { 0x27c3, "TDMCF3S"}, /* Slot Position DSPout3 , */\ + { 0x2803, "TDMCFS"}, /* Slot Position of DSPout , */\ + { 0x2843, "TDMEDAT6S"}, /* Slot Position of loopback channel left , */\ + { 0x2883, "TDMEDAT7S"}, /* Slot Position of loopback channel right , */\ + { 0x2901, "TDMTXUS3"}, /* Format unused slots D3 , */\ + { 0x3100, "PDMSM"}, /* PDM control , */\ + { 0x3110, "PDMSTSEL"}, /* PDM Decimator input selection , */\ + { 0x3120, "PDMSTENBL"}, /* Side tone input enable , */\ + { 0x3130, "PDMLSEL"}, /* PDM data selection for left channel during PDM direct mode, */\ + { 0x3140, "PDMRSEL"}, /* PDM data selection for right channel during PDM direct mode, */\ + { 0x3150, "MICVDDE"}, /* Enable MICVDD , */\ + { 0x3201, "PDMCLRAT"}, /* PDM BCK/Fs ratio , */\ + { 0x3223, "PDMGAIN"}, /* PDM gain , */\ + { 0x3263, "PDMOSEL"}, /* PDM output selection - RE/FE data combination , */\ + { 0x32a0, "SELCFHAPD"}, /* Select the source for haptic data output (not for customer), */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTPLLS"}, /* Status PLL lock , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOVDS"}, /* Status OVP alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTCLKS"}, /* Status clocks stable , */\ + { 0x4060, "ISTMTPB"}, /* Status MTP busy , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4080, "ISTSPKS"}, /* Status speaker error , */\ + { 0x4090, "ISTACS"}, /* Status cold start , */\ + { 0x40a0, "ISTSWS"}, /* Status amplifier engage , */\ + { 0x40b0, "ISTWDS"}, /* Status watchdog , */\ + { 0x40c0, "ISTAMPS"}, /* Status amplifier enable , */\ + { 0x40d0, "ISTAREFS"}, /* Status Ref enable , */\ + { 0x40e0, "ISTADCCR"}, /* Status Control ADC , */\ + { 0x40f0, "ISTBODNOK"}, /* Status BOD , */\ + { 0x4100, "ISTBSTCU"}, /* Status DCDC current limiting , */\ + { 0x4110, "ISTBSTHI"}, /* Status DCDC active , */\ + { 0x4120, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4130, "ISTBSTPKCUR"}, /* Status bst peakcur , */\ + { 0x4140, "ISTBSTVC"}, /* Status DCDC level 1x , */\ + { 0x4150, "ISTBST86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "ISTBST93"}, /* Status DCDC level 1.07x , */\ + { 0x4170, "ISTRCVLD"}, /* Status rcvldop ready , */\ + { 0x4180, "ISTOCPL"}, /* Status ocp alarm left , */\ + { 0x4190, "ISTOCPR"}, /* Status ocp alarm , */\ + { 0x41a0, "ISTMWSRC"}, /* Status Waits HW I2C settings , */\ + { 0x41b0, "ISTMWCFC"}, /* Status waits CF config , */\ + { 0x41c0, "ISTMWSMU"}, /* Status Audio mute sequence , */\ + { 0x41d0, "ISTCFMER"}, /* Status cfma error , */\ + { 0x41e0, "ISTCFMAC"}, /* Status cfma ack , */\ + { 0x41f0, "ISTCLKOOR"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "ISTTDMER"}, /* Status tdm error , */\ + { 0x4210, "ISTCLPL"}, /* Status clip left , */\ + { 0x4220, "ISTCLPR"}, /* Status clip , */\ + { 0x4230, "ISTOCPM"}, /* Status mic ocpok , */\ + { 0x4250, "ISTLP1"}, /* Status low power mode1 , */\ + { 0x4260, "ISTLA"}, /* Status low amplitude detection , */\ + { 0x4270, "ISTVDDP"}, /* Status VDDP greater than VBAT , */\ + { 0x4280, "ISTTAPDET"}, /* Status Tap detected , */\ + { 0x4290, "ISTAUDMOD"}, /* Status Audio Mode activated , */\ + { 0x42a0, "ISTSAMMOD"}, /* Status SAM Mode activated , */\ + { 0x42b0, "ISTTAPMOD"}, /* Status Tap Mode Activated , */\ + { 0x42c0, "ISTTAPTRG"}, /* Status Tap comparator triggered , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLPLLS"}, /* Clear PLL lock , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOVDS"}, /* Clear OVP alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLCLKS"}, /* Clear clocks stable , */\ + { 0x4460, "ICLMTPB"}, /* Clear mtp busy , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4480, "ICLSPKS"}, /* Clear speaker error , */\ + { 0x4490, "ICLACS"}, /* Clear cold started , */\ + { 0x44a0, "ICLSWS"}, /* Clear amplifier engage , */\ + { 0x44b0, "ICLWDS"}, /* Clear watchdog , */\ + { 0x44c0, "ICLAMPS"}, /* Clear enbl amp , */\ + { 0x44d0, "ICLAREFS"}, /* Clear ref enable , */\ + { 0x44e0, "ICLADCCR"}, /* Clear control ADC , */\ + { 0x44f0, "ICLBODNOK"}, /* Clear BOD , */\ + { 0x4500, "ICLBSTCU"}, /* Clear DCDC current limiting , */\ + { 0x4510, "ICLBSTHI"}, /* Clear DCDC active , */\ + { 0x4520, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4530, "ICLBSTPC"}, /* Clear bst peakcur , */\ + { 0x4540, "ICLBSTVC"}, /* Clear DCDC level 1x , */\ + { 0x4550, "ICLBST86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "ICLBST93"}, /* Clear DCDC level 1.07x , */\ + { 0x4570, "ICLRCVLD"}, /* Clear rcvldop ready , */\ + { 0x4580, "ICLOCPL"}, /* Clear ocp alarm left , */\ + { 0x4590, "ICLOCPR"}, /* Clear ocp alarm , */\ + { 0x45a0, "ICLMWSRC"}, /* Clear wait HW I2C settings , */\ + { 0x45b0, "ICLMWCFC"}, /* Clear wait cf config , */\ + { 0x45c0, "ICLMWSMU"}, /* Clear audio mute sequence , */\ + { 0x45d0, "ICLCFMER"}, /* Clear cfma err , */\ + { 0x45e0, "ICLCFMAC"}, /* Clear cfma ack , */\ + { 0x45f0, "ICLCLKOOR"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "ICLTDMER"}, /* Clear tdm error , */\ + { 0x4610, "ICLCLPL"}, /* Clear clip left , */\ + { 0x4620, "ICLCLP"}, /* Clear clip , */\ + { 0x4630, "ICLOCPM"}, /* Clear mic ocpok , */\ + { 0x4650, "ICLLP1"}, /* Clear low power mode1 , */\ + { 0x4660, "ICLLA"}, /* Clear low amplitude detection , */\ + { 0x4670, "ICLVDDP"}, /* Clear VDDP greater then VBAT , */\ + { 0x4680, "ICLTAPDET"}, /* Clear Tap detected , */\ + { 0x4690, "ICLAUDMOD"}, /* Clear Audio Mode activated , */\ + { 0x46a0, "ICLSAMMOD"}, /* Clear SAM Mode activated , */\ + { 0x46b0, "ICLTAPMOD"}, /* Clear Tap Mode Activated , */\ + { 0x46c0, "ICLTAPTRG"}, /* Clear Comparator Interrupt , */\ + { 0x4800, "IEVDDS"}, /* Enable por , */\ + { 0x4810, "IEPLLS"}, /* Enable pll lock , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOVDS"}, /* Enable OVP alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IECLKS"}, /* Enable clocks stable , */\ + { 0x4860, "IEMTPB"}, /* Enable mtp busy , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4880, "IESPKS"}, /* Enable speaker error , */\ + { 0x4890, "IEACS"}, /* Enable cold started , */\ + { 0x48a0, "IESWS"}, /* Enable amplifier engage , */\ + { 0x48b0, "IEWDS"}, /* Enable watchdog , */\ + { 0x48c0, "IEAMPS"}, /* Enable enbl amp , */\ + { 0x48d0, "IEAREFS"}, /* Enable ref enable , */\ + { 0x48e0, "IEADCCR"}, /* Enable Control ADC , */\ + { 0x48f0, "IEBODNOK"}, /* Enable BOD , */\ + { 0x4900, "IEBSTCU"}, /* Enable DCDC current limiting , */\ + { 0x4910, "IEBSTHI"}, /* Enable DCDC active , */\ + { 0x4920, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4930, "IEBSTPC"}, /* Enable bst peakcur , */\ + { 0x4940, "IEBSTVC"}, /* Enable DCDC level 1x , */\ + { 0x4950, "IEBST86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "IEBST93"}, /* Enable DCDC level 1.07x , */\ + { 0x4970, "IERCVLD"}, /* Enable rcvldop ready , */\ + { 0x4980, "IEOCPL"}, /* Enable ocp alarm left , */\ + { 0x4990, "IEOCPR"}, /* Enable ocp alarm , */\ + { 0x49a0, "IEMWSRC"}, /* Enable waits HW I2C settings , */\ + { 0x49b0, "IEMWCFC"}, /* Enable man wait cf config , */\ + { 0x49c0, "IEMWSMU"}, /* Enable man Audio mute sequence , */\ + { 0x49d0, "IECFMER"}, /* Enable cfma err , */\ + { 0x49e0, "IECFMAC"}, /* Enable cfma ack , */\ + { 0x49f0, "IECLKOOR"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "IETDMER"}, /* Enable tdm error , */\ + { 0x4a10, "IECLPL"}, /* Enable clip left , */\ + { 0x4a20, "IECLPR"}, /* Enable clip , */\ + { 0x4a30, "IEOCPM1"}, /* Enable mic ocpok , */\ + { 0x4a50, "IELP1"}, /* Enable low power mode1 , */\ + { 0x4a60, "IELA"}, /* Enable low amplitude detection , */\ + { 0x4a70, "IEVDDP"}, /* Enable VDDP greater than VBAT , */\ + { 0x4a80, "IETAPDET"}, /* Enable Tap detected , */\ + { 0x4a90, "IEAUDMOD"}, /* Enable Audio Mode activated , */\ + { 0x4aa0, "IESAMMOD"}, /* Enable SAM Mode activated , */\ + { 0x4ab0, "IETAPMOD"}, /* Enable Tap Mode Activated , */\ + { 0x4ac0, "IETAPTRG"}, /* Enable comparator interrupt , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity por , */\ + { 0x4c10, "IPOPLLS"}, /* Polarity pll lock , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOVDS"}, /* Polarity OVP alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOCLKS"}, /* Polarity clocks stable , */\ + { 0x4c60, "IPOMTPB"}, /* Polarity mtp busy , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4c80, "IPOSPKS"}, /* Polarity speaker error , */\ + { 0x4c90, "IPOACS"}, /* Polarity cold started , */\ + { 0x4ca0, "IPOSWS"}, /* Polarity amplifier engage , */\ + { 0x4cb0, "IPOWDS"}, /* Polarity watchdog , */\ + { 0x4cc0, "IPOAMPS"}, /* Polarity enbl amp , */\ + { 0x4cd0, "IPOAREFS"}, /* Polarity ref enable , */\ + { 0x4ce0, "IPOADCCR"}, /* Polarity Control ADC , */\ + { 0x4cf0, "IPOBODNOK"}, /* Polarity BOD , */\ + { 0x4d00, "IPOBSTCU"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "IPOBSTHI"}, /* Polarity DCDC active , */\ + { 0x4d20, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "IPOBSTPC"}, /* Polarity bst peakcur , */\ + { 0x4d40, "IPOBSTVC"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "IPOBST86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "IPOBST93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d70, "IPORCVLD"}, /* Polarity rcvldop ready , */\ + { 0x4d80, "IPOOCPL"}, /* Polarity ocp alarm left , */\ + { 0x4d90, "IPOOCPR"}, /* Polarity ocp alarm , */\ + { 0x4da0, "IPOMWSRC"}, /* Polarity waits HW I2C settings , */\ + { 0x4db0, "IPOMWCFC"}, /* Polarity man wait cf config , */\ + { 0x4dc0, "IPOMWSMU"}, /* Polarity man audio mute sequence , */\ + { 0x4dd0, "IPOCFMER"}, /* Polarity cfma err , */\ + { 0x4de0, "IPOCFMAC"}, /* Polarity cfma ack , */\ + { 0x4df0, "IPOCLKOOR"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "IPOTDMER"}, /* Polarity tdm error , */\ + { 0x4e10, "IPOCLPL"}, /* Polarity clip left , */\ + { 0x4e20, "IPOCLPR"}, /* Polarity clip , */\ + { 0x4e30, "IPOOCPM"}, /* Polarity mic ocpok , */\ + { 0x4e50, "IPOLP1"}, /* Polarity low power mode1 , */\ + { 0x4e60, "IPOLA"}, /* Polarity low amplitude detection , */\ + { 0x4e70, "IPOVDDP"}, /* Polarity VDDP greater than VBAT , */\ + { 0x4e80, "IPOLTAPDET"}, /* PolarityTap detected , */\ + { 0x4e90, "IPOLAUDMOD"}, /* PolarityAudio Mode activated , */\ + { 0x4ea0, "IPOLSAMMOD"}, /* PolaritySAM Mode activated , */\ + { 0x4eb0, "IPOLTAPMOD"}, /* Polarity Tap Mode Activated , */\ + { 0x4ec0, "IPOLTAPTRG"}, /* PolarityTap Comparator Trigger , */\ + { 0x5001, "BSSCR"}, /* Battery Safeguard attack time , */\ + { 0x5023, "BSST"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery Safeguard maximum reduction , */\ + { 0x5082, "BSSRR"}, /* Battery Safeguard release time , */\ + { 0x50b1, "BSSHY"}, /* Battery Safeguard hysteresis , */\ + { 0x50d0, "BSSAC"}, /* Reset clipper - Auto clear , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass HW clipper , */\ + { 0x5100, "BSSS"}, /* Vbat prot steepness , */\ + { 0x5110, "INTSMUTE"}, /* Soft mute HW , */\ + { 0x5120, "CFSML"}, /* Soft mute FW left , */\ + { 0x5130, "CFSM"}, /* Soft mute FW , */\ + { 0x5140, "HPFBYPL"}, /* Bypass HPF left , */\ + { 0x5150, "HPFBYP"}, /* Bypass HPF , */\ + { 0x5160, "DPSAL"}, /* Enable DPSA left , */\ + { 0x5170, "DPSA"}, /* Enable DPSA , */\ + { 0x5187, "VOL"}, /* FW volume control for primary audio channel , */\ + { 0x5200, "HNDSFRCV"}, /* Selection receiver , */\ + { 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x52d0, "SLOPEE"}, /* Enables slope control , */\ + { 0x52e0, "SLOPESET"}, /* Slope speed setting (bin. coded) , */\ + { 0x5c07, "CFTAPPAT"}, /* Coolflux tap pattern , */\ + { 0x5c83, "TAPDBGINFO"}, /* Reserved , */\ + { 0x5d0f, "TATPSTAT1"}, /* Tap Status 1 from CF FW , */\ + { 0x5f03, "TCOMPTHR"}, /* Comparator threshold (in uV) , */\ + { 0x6081, "PGAGAIN"}, /* PGA gain selection , */\ + { 0x6123, "TDMSPKG"}, /* System gain (INPLEV 0) , */\ + { 0x6505, "LPM1LVL"}, /* low power mode1 detector ctrl threshold for low_audio_lvl , */\ + { 0x6565, "LPM1HLD"}, /* Low power mode1 detector, ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x65c0, "LPM1DIS"}, /* low power mode1 detector control , */\ + { 0x6630, "DCDIS"}, /* DCDC , */\ + { 0x6801, "TDMSRCMAP"}, /* tdm source mapping , */\ + { 0x6821, "TDMSRCAS"}, /* frame a selection , */\ + { 0x6841, "TDMSRCBS"}, /* frame b selection , */\ + { 0x68a0, "ANC1C"}, /* ANC one s complement , */\ + { 0x6901, "SAMMODE"}, /* Sam mode , */\ + { 0x7033, "DCMCC"}, /* Max coil current , */\ + { 0x7071, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7090, "DCIE"}, /* Adaptive boost mode , */\ + { 0x70a0, "DCSR"}, /* Soft ramp up/down , */\ + { 0x70c1, "DCINSEL"}, /* DCDC IIR input Selection , */\ + { 0x70f0, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x7504, "DCTRIP"}, /* Adaptive boost trip levels 1, effective only when boost_intelligent is set to 1, */\ + { 0x7554, "DCTRIP2"}, /* Adaptive boost trip level 2, effective only when boost_intelligent is set to 1, */\ + { 0x75a4, "DCTRIPT"}, /* Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x7635, "DCVOF"}, /* First boost voltage level , */\ + { 0x7695, "DCVOS"}, /* Second boost voltage level , */\ + { 0x9000, "RST"}, /* Reset , */\ + { 0x9011, "DMEM"}, /* Target memory , */\ + { 0x9030, "AIF"}, /* Auto increment , */\ + { 0x9040, "CFINT"}, /* Interrupt - auto clear , */\ + { 0x9050, "CFCGATE"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "REQCMD"}, /* Firmware event request rpc command , */\ + { 0x9090, "REQRST"}, /* Firmware event request reset restart , */\ + { 0x90a0, "REQMIPS"}, /* Firmware event request short on mips , */\ + { 0x90b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "REQVOL"}, /* Firmware event request volume ready , */\ + { 0x90d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "REQCAL"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "REQRSV"}, /* Firmware event request reserved , */\ + { 0x910f, "MADD"}, /* Memory address , */\ + { 0x920f, "MEMA"}, /* Activate memory access , */\ + { 0x9307, "ERR"}, /* Error flags , */\ + { 0x9380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "ACKVOL"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "ACKDMG"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "ACKRSV"}, /* Firmware event acknowledge reserved , */\ + { 0xa107, "MTPK"}, /* MTP KEY2 register , */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xee0f, "SWPROFIL"}, /* Software profile data , */\ + { 0xef0f, "SWVSTEP"}, /* Software vstep information , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "DCMCCCL"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "USERDEF"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf40f, "R25C"}, /* Ron resistance of speaker coil , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9912_BITNAMETABLE static tfaBfName_t Tfa9912BitNames[] = {\ + { 0x0, "powerdown"}, /* Powerdown selection , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x20, "enbl_coolflux"}, /* Enable CoolFlux , */\ + { 0x30, "enbl_amplifier"}, /* Enables the Amplifier , */\ + { 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ + { 0x50, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x60, "sel_enbl_amplifier"}, /* CoolFlux controls amplifier , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0x90, "fs_pulse_sel"}, /* Audio sample reference , */\ + { 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xc0, "test_ocp"}, /* OCP testing control , */\ + { 0x101, "vamp_sel"}, /* Amplifier input selection , */\ + { 0x120, "src_set_configured"}, /* I2C configured , */\ + { 0x130, "execute_cold_start"}, /* Execute cold start , */\ + { 0x140, "enbl_fro8m_auto_off"}, /* Internal osc off at PWDN , */\ + { 0x150, "man_enbl_brown_out"}, /* Reaction on BOD , */\ + { 0x160, "enbl_bod"}, /* BOD Enable , */\ + { 0x170, "enbl_bod_hyst"}, /* BOD Hysteresis , */\ + { 0x181, "bod_delay"}, /* BOD filter , */\ + { 0x1a1, "bod_lvlsel"}, /* BOD threshold , */\ + { 0x1d0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x1e0, "pwm_sel_rcv_ns"}, /* Noise shaper selection , */\ + { 0x1f0, "man_enbl_watchdog"}, /* Watchdog enable , */\ + { 0x203, "audio_fs"}, /* Sample rate (fs) , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ + { 0x2b0, "bypass_hvbat_filter"}, /* Bypass HVBAT filter , */\ + { 0x2c0, "tdm_tfa9872_compatible"}, /* TDM Compatibility with TFA9872 , */\ + { 0x2d0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ + { 0x2e0, "enbl_adc10"}, /* ADC10 Enable - I2C direct mode , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ + { 0x430, "cf_clock_scaling"}, /* Coolflux DSP clock scaling, low power mode , */\ + { 0x441, "sel_cf_clock"}, /* Coolflux DSP clock scaler selection for low power mode, */\ + { 0x460, "tdm_intf_sel"}, /* TDM clock selection , */\ + { 0x470, "disable_auto_sel_refclk"}, /* Disable Automatic dsp clock source selection , */\ + { 0x480, "sel_clk_src"}, /* I2C selection of DSP clock when auto select is disabled, */\ + { 0x490, "wdt_tim_clk_src"}, /* I2C selection of Watchdog and Timer clock , */\ + { 0x510, "enbl_spkr_ss"}, /* Enable speaker path , */\ + { 0x530, "enbl_volsense"}, /* Voltage sense , */\ + { 0x550, "enbl_cursense"}, /* Current sense , */\ + { 0x560, "enbl_pdm_ss"}, /* Sub-system PDM , */\ + { 0x580, "enbl_pga_chop"}, /* Enable PGA chop clock , */\ + { 0x590, "enbl_tdm_ss"}, /* Sub-system TDM , */\ + { 0x5a0, "enbl_bst_ss"}, /* Sub-system boost , */\ + { 0x5b0, "enbl_adc10_ss"}, /* Sub-system ADC , */\ + { 0x5c0, "enbl_faim_ss"}, /* Sub-system FAIM , */\ + { 0x5d0, "enbl_tim_clk"}, /* CF Sub-system timer , */\ + { 0x5e0, "enbl_wdt_clk"}, /* CF Sub-system WDT , */\ + { 0x5f0, "faim_enable_vbg"}, /* Over rule of vbg for FaIM access , */\ + { 0x600, "aux_spkr_sel"}, /* Input selection for TAP/SAM , */\ + { 0x620, "bypass_tapdec_reset"}, /* Tap decimator reset bypass - Bypass the decimator reset from tapdec, */\ + { 0x631, "car_dec_in_sel0"}, /* Cardec input 0 sel , */\ + { 0x651, "car_dec_in_sel1"}, /* Cardec input sel , */\ + { 0x670, "tapdec_sel"}, /* Select TAP/Cardec for TAP , */\ + { 0x680, "comp_count"}, /* Comparator o/p filter selection , */\ + { 0x691, "startup_mode"}, /* Startup Mode Selection , */\ + { 0x6b0, "enable_auto_tap_switching"}, /* Enable auto tap switching , */\ + { 0x6c1, "comp_init_time"}, /* Comparator initialization time to be used in Tap Machine, */\ + { 0x6e1, "ana_init_time"}, /* Analog initialization time to be used in Tap Machine, */\ + { 0x707, "clkchk_th_hi"}, /* Clock check Higher Threshold , */\ + { 0x787, "clkchk_th_lo"}, /* Clock check Higher Threshold , */\ + { 0x802, "ctrl_on2off_criterion"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x832, "ctrl_on2tap_criterion"}, /* Amplifier on-off criteria for tap mode entry , */\ + { 0xd00, "side_tone_gain_sel"}, /* PDM side tone gain selector , */\ + { 0xd18, "side_tone_gain"}, /* Side tone gain , */\ + { 0xda0, "mute_side_tone"}, /* Side tone soft mute , */\ + { 0xdb0, "side_tone_1scomplement"}, /* side tone one s complement , */\ + { 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ + { 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_pll_lock"}, /* PLL lock , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm , */\ + { 0x1030, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm , */\ + { 0x1050, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1060, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1070, "flag_lost_clk"}, /* Lost clock , */\ + { 0x1090, "flag_cold_started"}, /* Cold Start , */\ + { 0x10a0, "flag_engage"}, /* Amplifier engage , */\ + { 0x10b0, "flag_watchdog_reset"}, /* Watchdog , */\ + { 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x10d0, "flag_enbl_ref"}, /* References enable , */\ + { 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x10f0, "flag_bod_vddd_nok"}, /* BOD , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active , */\ + { 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos , */\ + { 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1170, "flag_soft_mute_busy"}, /* side tone (un)mute busy , */\ + { 0x1180, "flag_soft_mute_state"}, /* side tone mute state , */\ + { 0x1190, "flag_tdm_lut_error"}, /* TDM LUT error , */\ + { 0x11a2, "flag_tdm_status"}, /* TDM status bits , */\ + { 0x11d0, "flag_tdm_error"}, /* TDM error , */\ + { 0x1300, "flag_ocpokap"}, /* OCPOK pmos A , */\ + { 0x1310, "flag_ocpokan"}, /* OCPOK nmos A , */\ + { 0x1320, "flag_ocpokbp"}, /* OCPOK pmos B , */\ + { 0x1330, "flag_ocpokbn"}, /* OCPOK nmos B , */\ + { 0x1340, "flag_clipa_high"}, /* Clipping A to Vddp , */\ + { 0x1350, "flag_clipa_low"}, /* Clipping A to gnd , */\ + { 0x1360, "flag_clipb_high"}, /* Clipping B to Vddp , */\ + { 0x1370, "flag_clipb_low"}, /* Clipping B to gnd , */\ + { 0x1380, "flag_ocp_alarm"}, /* OCP amplifier , */\ + { 0x1390, "flag_clip"}, /* Amplifier clipping , */\ + { 0x13a0, "flag_tap_comp_trig"}, /* Status Tap comparator triggered , */\ + { 0x13b0, "flag_cf_tapdetected"}, /* Status Tap detected , */\ + { 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ + { 0x13d0, "flag_man_wait_cf_config"}, /* Wait CF config , */\ + { 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x1410, "flag_cf_speakererror"}, /* Speaker status , */\ + { 0x1420, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x1433, "man_state"}, /* Device manager status , */\ + { 0x1471, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x1490, "man_dsp_clk_src"}, /* DSP clock source selected by manager , */\ + { 0x14a1, "man_startup_mode"}, /* Startup Mode Selected by Manager(Read Only) , */\ + { 0x14c3, "tap_machine_state"}, /* Tap Machine State , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x1709, "vddp_adc"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ + { 0x17a0, "flag_bst_bstcur_cf"}, /* DCDC current limiting for DSP , */\ + { 0x2000, "tdm_usecase"}, /* Mode setting , */\ + { 0x2011, "dio4_input_sel"}, /* DIO4 Input selection , */\ + { 0x2040, "tdm_enable"}, /* Enable TDM interface , */\ + { 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2073, "tdm_fs_ws_length"}, /* FS length , */\ + { 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ + { 0x2103, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ + { 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ + { 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2271, "tdm_txdata_format"}, /* Format unused bits in a slot , */\ + { 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots GAINIO , */\ + { 0x22b1, "tdm_txdata_format_unused_slot_sd1"}, /* Format unused slots DIO1 , */\ + { 0x22d1, "tdm_txdata_format_unused_slot_sd2"}, /* Format unused slots DIO2 , */\ + { 0x2300, "tdm_sink0_enable"}, /* Control gain (channel in 0) , */\ + { 0x2310, "tdm_sink1_enable"}, /* Control audio left (channel in 1 ) , */\ + { 0x2320, "tdm_sink2_enable"}, /* Control audio right (channel in 2 ) , */\ + { 0x2330, "tdm_source0_enable"}, /* Current sense , */\ + { 0x2340, "tdm_source1_enable"}, /* Voltage sense , */\ + { 0x2350, "tdm_source2_enable"}, /* DSP Gainout , */\ + { 0x2360, "tdm_source3_enable"}, /* DSP 2 , */\ + { 0x2370, "tdm_source4_enable"}, /* DSP 3 , */\ + { 0x2380, "tdm_source5_enable"}, /* DSP , */\ + { 0x2390, "tdm_source6_enable"}, /* Loopback of Audio left (channel 1) , */\ + { 0x23a0, "tdm_source7_enable"}, /* Loopback of Audio right (channel 2) , */\ + { 0x2401, "tdm_sink0_io"}, /* IO gainin , */\ + { 0x2421, "tdm_sink1_io"}, /* IO audio left , */\ + { 0x2441, "tdm_sink2_io"}, /* IO audio right , */\ + { 0x2461, "tdm_source0_io"}, /* IO Current Sense , */\ + { 0x2481, "tdm_source1_io"}, /* IO voltage sense , */\ + { 0x24a1, "tdm_source2_io"}, /* IO gain out , */\ + { 0x24c1, "tdm_source3_io"}, /* IO DSP 2 , */\ + { 0x24e1, "tdm_source4_io"}, /* IO DSP 3 , */\ + { 0x2501, "tdm_source5_io"}, /* IO DSP , */\ + { 0x2521, "tdm_source6_io"}, /* IO Source 6 , */\ + { 0x2541, "tdm_source7_io"}, /* IO Source 7 , */\ + { 0x2603, "tdm_sink0_slot"}, /* Control gainin , */\ + { 0x2643, "tdm_sink1_slot"}, /* tdm slot for audio left (channel 1) , */\ + { 0x2683, "tdm_sink2_slot"}, /* tdm slot for audio right (channel 2) , */\ + { 0x26c3, "tdm_source0_slot"}, /* Slot Position of Current Sense Out , */\ + { 0x2703, "tdm_source1_slot"}, /* Slot Position of Voltage sense , */\ + { 0x2743, "tdm_source2_slot"}, /* Slot Position of GAIN out , */\ + { 0x2783, "tdm_source3_slot"}, /* Slot Position DSPout2 , */\ + { 0x27c3, "tdm_source4_slot"}, /* Slot Position DSPout3 , */\ + { 0x2803, "tdm_source5_slot"}, /* Slot Position of DSPout , */\ + { 0x2843, "tdm_source6_slot"}, /* Slot Position of loopback channel left , */\ + { 0x2883, "tdm_source7_slot"}, /* Slot Position of loopback channel right , */\ + { 0x2901, "tdm_txdata_format_unused_slot_sd3"}, /* Format unused slots D3 , */\ + { 0x3100, "pdm_mode"}, /* PDM control , */\ + { 0x3110, "pdm_input_sel"}, /* PDM Decimator input selection , */\ + { 0x3120, "enbl_pdm_side_tone"}, /* Side tone input enable , */\ + { 0x3201, "pdm_nbck"}, /* PDM BCK/Fs ratio , */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_pll_lock"}, /* Status PLL lock , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ovpok"}, /* Status OVP alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_clocks_stable"}, /* Status clocks stable , */\ + { 0x4060, "int_out_flag_mtp_busy"}, /* Status MTP busy , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4080, "int_out_flag_cf_speakererror"}, /* Status speaker error , */\ + { 0x4090, "int_out_flag_cold_started"}, /* Status cold start , */\ + { 0x40a0, "int_out_flag_engage"}, /* Status amplifier engage , */\ + { 0x40b0, "int_out_flag_watchdog_reset"}, /* Status watchdog , */\ + { 0x40c0, "int_out_flag_enbl_amp"}, /* Status amplifier enable , */\ + { 0x40d0, "int_out_flag_enbl_ref"}, /* Status Ref enable , */\ + { 0x40e0, "int_out_flag_adc10_ready"}, /* Status Control ADC , */\ + { 0x40f0, "int_out_flag_bod_vddd_nok"}, /* Status BOD , */\ + { 0x4100, "int_out_flag_bst_bstcur"}, /* Status DCDC current limiting , */\ + { 0x4110, "int_out_flag_bst_hiz"}, /* Status DCDC active , */\ + { 0x4120, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4130, "int_out_flag_bst_peakcur"}, /* Status bst peakcur , */\ + { 0x4140, "int_out_flag_bst_voutcomp"}, /* Status DCDC level 1x , */\ + { 0x4150, "int_out_flag_bst_voutcomp86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "int_out_flag_bst_voutcomp93"}, /* Status DCDC level 1.07x , */\ + { 0x4190, "int_out_flag_ocp_alarm"}, /* Status ocp alarm , */\ + { 0x41a0, "int_out_flag_man_wait_src_settings"}, /* Status Waits HW I2C settings , */\ + { 0x41b0, "int_out_flag_man_wait_cf_config"}, /* Status waits CF config , */\ + { 0x41c0, "int_out_flag_man_start_mute_audio"}, /* Status Audio mute sequence , */\ + { 0x41d0, "int_out_flag_cfma_err"}, /* Status cfma error , */\ + { 0x41e0, "int_out_flag_cfma_ack"}, /* Status cfma ack , */\ + { 0x41f0, "int_out_flag_clk_out_of_range"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "int_out_flag_tdm_error"}, /* Status tdm error , */\ + { 0x4220, "int_out_flag_clip"}, /* Status clip , */\ + { 0x4250, "int_out_flag_lp_detect_mode1"}, /* Status low power mode1 , */\ + { 0x4260, "int_out_flag_low_amplitude"}, /* Status low amplitude detection , */\ + { 0x4270, "int_out_flag_vddp_gt_vbat"}, /* Status VDDP greater than VBAT , */\ + { 0x4280, "int_out_newtap"}, /* Status Tap detected , */\ + { 0x4290, "int_out_audiomodeactive"}, /* Status Audio Mode activated , */\ + { 0x42a0, "int_out_sammodeactive"}, /* Status SAM Mode activated , */\ + { 0x42b0, "int_out_tapmodeactive"}, /* Status Tap Mode Activated , */\ + { 0x42c0, "int_out_flag_tap_comp_trig"}, /* Status Tap comparator triggered , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_pll_lock"}, /* Clear PLL lock , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ovpok"}, /* Clear OVP alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_clocks_stable"}, /* Clear clocks stable , */\ + { 0x4460, "int_in_flag_mtp_busy"}, /* Clear mtp busy , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4480, "int_in_flag_cf_speakererror"}, /* Clear speaker error , */\ + { 0x4490, "int_in_flag_cold_started"}, /* Clear cold started , */\ + { 0x44a0, "int_in_flag_engage"}, /* Clear amplifier engage , */\ + { 0x44b0, "int_in_flag_watchdog_reset"}, /* Clear watchdog , */\ + { 0x44c0, "int_in_flag_enbl_amp"}, /* Clear enbl amp , */\ + { 0x44d0, "int_in_flag_enbl_ref"}, /* Clear ref enable , */\ + { 0x44e0, "int_in_flag_adc10_ready"}, /* Clear control ADC , */\ + { 0x44f0, "int_in_flag_bod_vddd_nok"}, /* Clear BOD , */\ + { 0x4500, "int_in_flag_bst_bstcur"}, /* Clear DCDC current limiting , */\ + { 0x4510, "int_in_flag_bst_hiz"}, /* Clear DCDC active , */\ + { 0x4520, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4530, "int_in_flag_bst_peakcur"}, /* Clear bst peakcur , */\ + { 0x4540, "int_in_flag_bst_voutcomp"}, /* Clear DCDC level 1x , */\ + { 0x4550, "int_in_flag_bst_voutcomp86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "int_in_flag_bst_voutcomp93"}, /* Clear DCDC level 1.07x , */\ + { 0x4590, "int_in_flag_ocp_alarm"}, /* Clear ocp alarm , */\ + { 0x45a0, "int_in_flag_man_wait_src_settings"}, /* Clear wait HW I2C settings , */\ + { 0x45b0, "int_in_flag_man_wait_cf_config"}, /* Clear wait cf config , */\ + { 0x45c0, "int_in_flag_man_start_mute_audio"}, /* Clear audio mute sequence , */\ + { 0x45d0, "int_in_flag_cfma_err"}, /* Clear cfma err , */\ + { 0x45e0, "int_in_flag_cfma_ack"}, /* Clear cfma ack , */\ + { 0x45f0, "int_in_flag_clk_out_of_range"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ + { 0x4620, "int_in_flag_clip"}, /* Clear clip , */\ + { 0x4650, "int_in_flag_lp_detect_mode1"}, /* Clear low power mode1 , */\ + { 0x4660, "int_in_flag_low_amplitude"}, /* Clear low amplitude detection , */\ + { 0x4670, "int_in_flag_vddp_gt_vbat"}, /* Clear VDDP greater then VBAT , */\ + { 0x4680, "int_in_newtap"}, /* Clear Tap detected , */\ + { 0x4690, "int_in_audiomodeactive"}, /* Clear Audio Mode activated , */\ + { 0x46a0, "int_in_sammodeactive"}, /* Clear SAM Mode activated , */\ + { 0x46b0, "int_in_tapmodeactive"}, /* Clear Tap Mode Activated , */\ + { 0x46c0, "int_in_flag_tap_comp_trig"}, /* Clear Comparator Interrupt , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable por , */\ + { 0x4810, "int_enable_flag_pll_lock"}, /* Enable pll lock , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ovpok"}, /* Enable OVP alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_clocks_stable"}, /* Enable clocks stable , */\ + { 0x4860, "int_enable_flag_mtp_busy"}, /* Enable mtp busy , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4880, "int_enable_flag_cf_speakererror"}, /* Enable speaker error , */\ + { 0x4890, "int_enable_flag_cold_started"}, /* Enable cold started , */\ + { 0x48a0, "int_enable_flag_engage"}, /* Enable amplifier engage , */\ + { 0x48b0, "int_enable_flag_watchdog_reset"}, /* Enable watchdog , */\ + { 0x48c0, "int_enable_flag_enbl_amp"}, /* Enable enbl amp , */\ + { 0x48d0, "int_enable_flag_enbl_ref"}, /* Enable ref enable , */\ + { 0x48e0, "int_enable_flag_adc10_ready"}, /* Enable Control ADC , */\ + { 0x48f0, "int_enable_flag_bod_vddd_nok"}, /* Enable BOD , */\ + { 0x4900, "int_enable_flag_bst_bstcur"}, /* Enable DCDC current limiting , */\ + { 0x4910, "int_enable_flag_bst_hiz"}, /* Enable DCDC active , */\ + { 0x4920, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4930, "int_enable_flag_bst_peakcur"}, /* Enable bst peakcur , */\ + { 0x4940, "int_enable_flag_bst_voutcomp"}, /* Enable DCDC level 1x , */\ + { 0x4950, "int_enable_flag_bst_voutcomp86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "int_enable_flag_bst_voutcomp93"}, /* Enable DCDC level 1.07x , */\ + { 0x4990, "int_enable_flag_ocp_alarm"}, /* Enable ocp alarm , */\ + { 0x49a0, "int_enable_flag_man_wait_src_settings"}, /* Enable waits HW I2C settings , */\ + { 0x49b0, "int_enable_flag_man_wait_cf_config"}, /* Enable man wait cf config , */\ + { 0x49c0, "int_enable_flag_man_start_mute_audio"}, /* Enable man Audio mute sequence , */\ + { 0x49d0, "int_enable_flag_cfma_err"}, /* Enable cfma err , */\ + { 0x49e0, "int_enable_flag_cfma_ack"}, /* Enable cfma ack , */\ + { 0x49f0, "int_enable_flag_clk_out_of_range"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ + { 0x4a20, "int_enable_flag_clip"}, /* Enable clip , */\ + { 0x4a50, "int_enable_flag_lp_detect_mode1"}, /* Enable low power mode1 , */\ + { 0x4a60, "int_enable_flag_low_amplitude"}, /* Enable low amplitude detection , */\ + { 0x4a70, "int_enable_flag_vddp_gt_vbat"}, /* Enable VDDP greater than VBAT , */\ + { 0x4a80, "int_enable_newtap"}, /* Enable Tap detected , */\ + { 0x4a90, "int_enable_audiomodeactive"}, /* Enable Audio Mode activated , */\ + { 0x4aa0, "int_enable_sammodeactive"}, /* Enable SAM Mode activated , */\ + { 0x4ab0, "int_enable_tapmodeactive"}, /* Enable Tap Mode Activated , */\ + { 0x4ac0, "int_enable_flag_tap_comp_trig"}, /* Enable comparator interrupt , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ + { 0x4c10, "int_polarity_flag_pll_lock"}, /* Polarity pll lock , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ovpok"}, /* Polarity OVP alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_clocks_stable"}, /* Polarity clocks stable , */\ + { 0x4c60, "int_polarity_flag_mtp_busy"}, /* Polarity mtp busy , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4c80, "int_polarity_flag_cf_speakererror"}, /* Polarity speaker error , */\ + { 0x4c90, "int_polarity_flag_cold_started"}, /* Polarity cold started , */\ + { 0x4ca0, "int_polarity_flag_engage"}, /* Polarity amplifier engage , */\ + { 0x4cb0, "int_polarity_flag_watchdog_reset"}, /* Polarity watchdog , */\ + { 0x4cc0, "int_polarity_flag_enbl_amp"}, /* Polarity enbl amp , */\ + { 0x4cd0, "int_polarity_flag_enbl_ref"}, /* Polarity ref enable , */\ + { 0x4ce0, "int_polarity_flag_adc10_ready"}, /* Polarity Control ADC , */\ + { 0x4cf0, "int_polarity_flag_bod_vddd_nok"}, /* Polarity BOD , */\ + { 0x4d00, "int_polarity_flag_bst_bstcur"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "int_polarity_flag_bst_hiz"}, /* Polarity DCDC active , */\ + { 0x4d20, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "int_polarity_flag_bst_peakcur"}, /* Polarity bst peakcur , */\ + { 0x4d40, "int_polarity_flag_bst_voutcomp"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "int_polarity_flag_bst_voutcomp86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "int_polarity_flag_bst_voutcomp93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d90, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ + { 0x4da0, "int_polarity_flag_man_wait_src_settings"}, /* Polarity waits HW I2C settings , */\ + { 0x4db0, "int_polarity_flag_man_wait_cf_config"}, /* Polarity man wait cf config , */\ + { 0x4dc0, "int_polarity_flag_man_start_mute_audio"}, /* Polarity man audio mute sequence , */\ + { 0x4dd0, "int_polarity_flag_cfma_err"}, /* Polarity cfma err , */\ + { 0x4de0, "int_polarity_flag_cfma_ack"}, /* Polarity cfma ack , */\ + { 0x4df0, "int_polarity_flag_clk_out_of_range"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ + { 0x4e20, "int_polarity_flag_clip"}, /* Polarity clip , */\ + { 0x4e50, "int_polarity_flag_lp_detect_mode1"}, /* Polarity low power mode1 , */\ + { 0x4e60, "int_polarity_flag_low_amplitude"}, /* Polarity low amplitude detection , */\ + { 0x4e70, "int_polarity_flag_vddp_gt_vbat"}, /* Polarity VDDP greater than VBAT , */\ + { 0x4e80, "int_polarity_newtap"}, /* PolarityTap detected , */\ + { 0x4e90, "int_polarity_audiomodeactive"}, /* PolarityAudio Mode activated , */\ + { 0x4ea0, "int_polarity_sammodeactive"}, /* PolaritySAM Mode activated , */\ + { 0x4eb0, "int_polarity_tapmodeactive"}, /* Polarity Tap Mode Activated , */\ + { 0x4ec0, "int_polarity_flag_tap_comp_trig"}, /* PolarityTap Comparator Trigger , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery Safeguard attack time , */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery Safeguard maximum reduction , */\ + { 0x5082, "vbat_prot_release_time"}, /* Battery Safeguard release time , */\ + { 0x50b1, "vbat_prot_hysterese"}, /* Battery Safeguard hysteresis , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass HW clipper , */\ + { 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ + { 0x5110, "soft_mute"}, /* Soft mute HW , */\ + { 0x5130, "cf_mute"}, /* Soft mute FW , */\ + { 0x5150, "bypass_hp"}, /* Bypass HPF , */\ + { 0x5170, "enbl_dpsa"}, /* Enable DPSA , */\ + { 0x5187, "cf_volume"}, /* FW volume control for primary audio channel , */\ + { 0x5222, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5257, "gain"}, /* Amplifier gain , */\ + { 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x52e0, "ctrl_slope"}, /* Slope speed setting (bin. coded) , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5340, "clipfast"}, /* Clock selection for HW clipper for Battery Safeguard, */\ + { 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x5360, "enbl_low_latency"}, /* CF low latency outputs for add module , */\ + { 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5410, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5430, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x5503, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5543, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5582, "dpsa_drive"}, /* Drive setting (bin. coded) - I2C direct mode , */\ + { 0x570a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually , */\ + { 0x57b0, "enbl_engage"}, /* Enables/engage power stage and control loop - I2C direct mode, */\ + { 0x57c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ + { 0x5810, "hard_mute"}, /* Hard mute - PWM , */\ + { 0x5820, "pwm_shape"}, /* PWM shape , */\ + { 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clock is 1/(k*2048*fs), */\ + { 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ + { 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ + { 0x58c0, "enbl_pwm_phase_shift"}, /* Control for pwm phase shift , */\ + { 0x5c07, "flag_cf_tap_pattern"}, /* Coolflux tap pattern , */\ + { 0x5c83, "tap_debug_info"}, /* Reserved , */\ + { 0x5d0f, "tap_status_1"}, /* Tap Status 1 from CF FW , */\ + { 0x5f03, "tap_comp_threshold"}, /* Comparator threshold (in uV) , */\ + { 0x6081, "pga_gain_set"}, /* PGA gain selection , */\ + { 0x60b0, "pga_lowpass_enable"}, /* Lowpass enable , */\ + { 0x60c0, "pga_pwr_enable"}, /* PGA power enable , */\ + { 0x60d0, "pga_switch_enable"}, /* PGA switch enable , */\ + { 0x60e0, "pga_switch_aux_enable"}, /* Switch enable aux , */\ + { 0x6123, "ctrl_att"}, /* System gain (INPLEV 0) , */\ + { 0x6265, "zero_lvl"}, /* ctrl threshold for zero X-ing , */\ + { 0x62c1, "ctrl_fb_resistor"}, /* Select amplifier feedback resistor connection , */\ + { 0x62e1, "lownoisegain_mode"}, /* ctrl select mode , */\ + { 0x6305, "threshold_lvl"}, /* ctrl threshold for low_audio_lvl , */\ + { 0x6365, "hold_time"}, /* ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x6405, "lpm1_cal_offset"}, /* low power mode1 detector ctrl cal_offset from gain module , */\ + { 0x6465, "lpm1_zero_lvl"}, /* low power mode1 detector ctrl threshold for zero X-ing , */\ + { 0x64e1, "lpm1_mode"}, /* low power mode1 detector ctrl select mode , */\ + { 0x6505, "lpm1_threshold_lvl"}, /* low power mode1 detector ctrl threshold for low_audio_lvl , */\ + { 0x6565, "lpm1_hold_time"}, /* Low power mode1 detector, ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x65c0, "disable_low_power_mode"}, /* low power mode1 detector control , */\ + { 0x6600, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ + { 0x6611, "dcdc_ctrl_maxzercnt"}, /* DCDC. Number of zero current flags to count before going to pfm mode, */\ + { 0x6630, "dcdcoff_mode"}, /* DCDC , */\ + { 0x6656, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ + { 0x66c0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x6700, "enbl_minion"}, /* Enables minion (small) power stage - direct ctrl , */\ + { 0x6713, "vth_vddpvbat"}, /* select vddp-vbat thres signal , */\ + { 0x6750, "lpen_vddpvbat"}, /* select vddp-vbat filtered vs unfiltered compare , */\ + { 0x6761, "ctrl_rfb"}, /* Feedback resistor selection - I2C direct mode , */\ + { 0x6801, "tdm_source_mapping"}, /* tdm source mapping , */\ + { 0x6821, "tdm_sourcea_frame_sel"}, /* frame a selection , */\ + { 0x6841, "tdm_sourceb_frame_sel"}, /* frame b selection , */\ + { 0x6901, "sam_mode"}, /* Sam mode , */\ + { 0x6931, "pdmdat_h_sel"}, /* pdm out value when pdm_clk is higth , */\ + { 0x6951, "pdmdat_l_sel"}, /* pdm out value when pdm_clk is low , */\ + { 0x6970, "cs_sam_set"}, /* Enable SAM input for current sense - I2C Direct Mode, */\ + { 0x6980, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x6990, "sam_spkr_sel"}, /* SAM o/p sel during SAM and audio , */\ + { 0x6b00, "disable_engage"}, /* Disable auto engage , */\ + { 0x6c02, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ + { 0x6c32, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ + { 0x6c60, "sel_clip_pwms"}, /* To select clip-flags , */\ + { 0x6c72, "pwms_clip_lvl"}, /* To set the amount of pwm pulse that may be skipped before clip-flag is triggered. , */\ + { 0x6ca5, "spare_out"}, /* spare_out , */\ + { 0x6d0f, "spare_in"}, /* spare_in , */\ + { 0x6e10, "flag_lp_detect_mode1"}, /* low power mode 1 detection , */\ + { 0x6e20, "flag_low_amplitude"}, /* low amplitude detection , */\ + { 0x6e30, "flag_vddp_gt_vbat"}, /* vddp greater than vbat , */\ + { 0x7033, "boost_cur"}, /* Max coil current , */\ + { 0x7071, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7090, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x70a0, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x70c1, "dcdc_sel"}, /* DCDC IIR input Selection , */\ + { 0x70f0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7174, "bst_slopecur"}, /* For testing direct control slope current - I2C direct mode, */\ + { 0x71c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller - I2C direct mode, */\ + { 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator - I2C direct mode , */\ + { 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7230, "enbl_bst_peakcur"}, /* Enable peak current - I2C direct mode , */\ + { 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage - I2C direct mode , */\ + { 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac - I2C direct mode , */\ + { 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators - I2C direct mode , */\ + { 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators - I2C direct mode , */\ + { 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators - I2C direct mode , */\ + { 0x7290, "enbl_bst_windac"}, /* Enable window dac - I2C direct mode , */\ + { 0x72a5, "bst_windac"}, /* for testing direct control windac - I2C direct mode, */\ + { 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7331, "bst_freq"}, /* DCDC boost frequency control , */\ + { 0x7430, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7494, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x74e0, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x74f0, "ignore_flag_voutcomp86"}, /* Ignore flag_voutcomp86 , */\ + { 0x7504, "boost_trip_lvl_1st"}, /* Adaptive boost trip levels 1, effective only when boost_intelligent is set to 1, */\ + { 0x7554, "boost_trip_lvl_2nd"}, /* Adaptive boost trip level 2, effective only when boost_intelligent is set to 1, */\ + { 0x75a4, "boost_trip_lvl_track"}, /* Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x7602, "track_decay"}, /* DCDC Boost decay speed after a peak value, effective only when boost_track is set to 1, */\ + { 0x7635, "frst_boost_voltage"}, /* First boost voltage level , */\ + { 0x7695, "scnd_boost_voltage"}, /* Second boost voltage level , */\ + { 0x7720, "pga_test_ldo_bypass"}, /* bypass internal PGA LDO , */\ + { 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ + { 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ + { 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8200, "enbl_cmfb"}, /* Current sense common mode feedback control , */\ + { 0x8210, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ + { 0x8222, "cmfb_gain"}, /* Current sense common mode feedback control gain , */\ + { 0x8256, "cmfb_offset"}, /* Current sense common mode feedback control offset , */\ + { 0x8305, "cs_ktemp"}, /* First order temperature compensation coefficient , */\ + { 0x8364, "cs_ktemp2"}, /* Second order temperature compensation coefficient , */\ + { 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8421, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ + { 0x8453, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ + { 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x84a4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ + { 0x8500, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ + { 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ + { 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8700, "enbl_cs_adc"}, /* Enable current sense ADC - I2C direct mode , */\ + { 0x8710, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 - I2C direct mode, */\ + { 0x8720, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 - I2C direct mode, */\ + { 0x8730, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ + { 0x8740, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 - I2C direct mode, */\ + { 0x8750, "enbl_cs_ldo"}, /* Enable current sense LDO - I2C direct mode , */\ + { 0x8760, "enbl_cs_nofloating_n"}, /* Connect current sense negative to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8770, "enbl_cs_nofloating_p"}, /* Connect current sense positive to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8780, "enbl_cs_vbatldo"}, /* Enable of current sense LDO -- I2C direct mode , */\ + { 0x8800, "volsense_pwm_sel"}, /* Voltage sense PWM source selection control , */\ + { 0x8810, "vol_cur_sense_dc_offset"}, /* voltage and current sense decimator offset control, */\ + { 0x8902, "cursense_comp_delay"}, /* To align compensation signal with current sense signal, */\ + { 0x8930, "cursense_comp_sign"}, /* To change polarity of compensation for current sense compensation, */\ + { 0x8940, "enbl_cursense_comp"}, /* To enable current sense compensation , */\ + { 0x9000, "cf_rst_dsp"}, /* Reset , */\ + { 0x9011, "cf_dmem"}, /* Target memory , */\ + { 0x9030, "cf_aif"}, /* Auto increment , */\ + { 0x9040, "cf_int"}, /* Interrupt - auto clear , */\ + { 0x9050, "cf_cgate_off"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "cf_req_cmd"}, /* Firmware event request rpc command , */\ + { 0x9090, "cf_req_reset"}, /* Firmware event request reset restart , */\ + { 0x90a0, "cf_req_mips"}, /* Firmware event request short on mips , */\ + { 0x90b0, "cf_req_mute_ready"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "cf_req_volume_ready"}, /* Firmware event request volume ready , */\ + { 0x90d0, "cf_req_damage"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "cf_req_calibrate_ready"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "cf_req_reserved"}, /* Firmware event request reserved , */\ + { 0x910f, "cf_madd"}, /* Memory address , */\ + { 0x920f, "cf_mema"}, /* Activate memory access , */\ + { 0x9307, "cf_err"}, /* Error flags , */\ + { 0x9380, "cf_ack_cmd"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "cf_ack_reset"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "cf_ack_mips"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "cf_ack_mute_ready"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "cf_ack_volume_ready"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "cf_ack_damage"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "cf_ack_calibrate_ready"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "cf_ack_reserved"}, /* Firmware event acknowledge reserved , */\ + { 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa400, "faim_set_clkws"}, /* Sets the FaIM controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the FaIM are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the FaIM are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb050, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually - - I2C direct mode, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ + { 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high - I2C direct mode, */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc130, "tap_comp_enable"}, /* Tap Comparator enable control - I2C direct mode , */\ + { 0xc140, "tap_comp_switch_enable"}, /* Tap Comparator Switch enable control - I2C direct mode, */\ + { 0xc150, "tap_comp_switch_aux_enable"}, /* Tap Comparator Switch enable control - I2C direct mode, */\ + { 0xc161, "tap_comp_test_enable"}, /* Comparator threshold - fine value , */\ + { 0xc180, "curdist_enable"}, /* Enable control - I2C direct mode , */\ + { 0xc190, "vbg2i_enbl"}, /* Enable control - I2C direct mode , */\ + { 0xc1a0, "bg_filt_bypass_enbl"}, /* Enable control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ + { 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0xc3d0, "test_abistfft_enbl"}, /* FFT Coolflux , */\ + { 0xc3e0, "test_pwr_switch"}, /* Test mode for digital power switches core sw/mem sw/micvdd sw, */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc560, "bypass_fro8"}, /* Bypass fro8 with pdm_clk , */\ + { 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc5b0, "pga_test_enable"}, /* Enable PGA test mode , */\ + { 0xc5c0, "pga_test_offset_enable"}, /* Enable PGA test offset , */\ + { 0xc5d0, "pga_test_shortinput_enable"}, /* Enable PGA test short input , */\ + { 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc660, "enbl_powerswitch"}, /* Vddd core power switch control - overrules the manager control, */\ + { 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to DIO4 (see Digimux list for details), */\ + { 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to DIO3 (see Digimux list for details), */\ + { 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to TDO (see Digimux list for details), */\ + { 0xc901, "dio1_ehs"}, /* Speed/load setting for DIO1 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc921, "dio2_ehs"}, /* Speed/load setting for DIO2 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc941, "dio3_ehs"}, /* Speed/load setting for DIO3 cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc961, "dio4_ehs"}, /* Speed/load setting for DIO4 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc981, "spdmo_ehs"}, /* Speed/load setting for PDMO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9a1, "tdo_ehs"}, /* Speed/load setting for TDM IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9c0, "int_ehs"}, /* Slew Rate INT IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xc9d0, "pdmclk_ehs"}, /* Slew RateBCK2/PDMCLK IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xc9e0, "fs2_ehs"}, /* Slew Rate DS2 IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xc9f0, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xcb04, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ + { 0xcb54, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ + { 0xcba4, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ + { 0xcc05, "pll_seli_lbw"}, /* PLL SELI - Low B/W PLL control mode or I2C direct PLL control mode only, */\ + { 0xcc64, "pll_selp_lbw"}, /* PLL SELP - Low B/W PLL control mode or I2C direct PLL control mode only, */\ + { 0xccb3, "pll_selr_lbw"}, /* PLL SELR - Low B/W PLL control mode or I2C direct PLL control mode only, */\ + { 0xccf0, "sel_user_pll_bw"}, /* PLL Low Bandwidth Mode control , */\ + { 0xcdf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ + { 0xce09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0xcea0, "pll_mdec_msb"}, /* MSB of pll_mdec - I2C direct PLL control mode only, */\ + { 0xceb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ + { 0xcec0, "enbl_fro8"}, /* Enables FRO8M in I2C direct control mode only , */\ + { 0xced0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ + { 0xcee0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ + { 0xcef0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ + { 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ + { 0xd006, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd283, "tsig_gain"}, /* Test signal gain , */\ + { 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd507, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd580, "enbl_clk_range_chk"}, /* Clock out of range , */\ + { 0xd601, "clkdiv_dsp_sel"}, /* DSP clock divider selection in direct clock control mode, */\ + { 0xd621, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ + { 0xd641, "clkdiv_muxa_sel"}, /* DCDC MUXA clock divider selection in direct clock control mode, */\ + { 0xd661, "clkdiv_muxb_sel"}, /* DCDC MUXB clock divider selection in direct clock control mode, */\ + { 0xd681, "dsp_tap_clk"}, /* Dsp clock frequency selection in TAP mode; , */\ + { 0xd6a1, "sel_wdt_clk"}, /* Watch dog clock post divider value , */\ + { 0xd6c1, "sel_tim_clk"}, /* Timer clock post divider value , */\ + { 0xd700, "ads1_ehs"}, /* Slew Rate ADS1 IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xd710, "ads2_ehs"}, /* Slew Rate ADS2 IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xd822, "test_parametric_io"}, /* test io parametric , */\ + { 0xd850, "ctrl_bst_clk_lp1"}, /* boost clock control in low power mode1 , */\ + { 0xd861, "test_spare_out1"}, /* test spare out 1 , */\ + { 0xd880, "bst_dcmbst"}, /* dcm boost - I2C direct mode , */\ + { 0xd8a1, "force_pga_clock"}, /* force pga clock , */\ + { 0xd8c3, "test_spare_out2"}, /* test spare out 1 , */\ + { 0xd900, "overrules_usercase"}, /* Overrule Mode control use , */\ + { 0xd910, "ovr_switch_ref"}, /* Overrule Value , */\ + { 0xd920, "ovr_enbl_pll"}, /* Overrule Value , */\ + { 0xd930, "ovr_switch_amp"}, /* Overrule Value , */\ + { 0xd940, "ovr_enbl_clk_cs"}, /* Overrule Value , */\ + { 0xd951, "ovr_sel_clk_cs"}, /* CS clock selection overrule , */\ + { 0xd970, "ovr_switch_cs"}, /* Overrule Value , */\ + { 0xd980, "ovr_enbl_csvs_ss"}, /* Overrule Value , */\ + { 0xd990, "ovr_enbl_comp"}, /* Overrule Value , */\ + { 0xed00, "enbl_fro8cal"}, /* Enable FRO calibration , */\ + { 0xed10, "start_fro8_calibration"}, /* Start FRO8 Calibration , */\ + { 0xed20, "fro8_calibration_done"}, /* FRO8 Calibration done - Read Only , */\ + { 0xed45, "fro8_auto_trim_val"}, /* Calibration value from Auto Calibration block, to be written into MTP - Read Only, */\ + { 0xee0f, "sw_profile"}, /* Software profile data , */\ + { 0xef0f, "sw_vstep"}, /* Software vstep information , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf163, "spare_mtp1_9_6"}, /* HW gain module - left channel (2's complement) , */\ + { 0xf1a5, "spare_mtp1_15_10"}, /* Offset for amplifier, HW gain module - left channel (2's complement), */\ + { 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ + { 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ + { 0xf2a3, "spare_mtp2_13_10"}, /* Trimming of LDO (2.7V) , */\ + { 0xf307, "spare_mtp3_7_0"}, /* SPARE , */\ + { 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ + { 0xf40f, "calibr_R25C"}, /* Ron resistance of speaker coil , */\ + { 0xf50f, "spare_mtp5_15_0"}, /* SPARE , */\ + { 0xf600, "mtp_lock_enbl_coolflux"}, /* Disable function dcdcoff_mode , */\ + { 0xf610, "mtp_pwm_delay_enbl_clk_auto_gating"}, /* Auto clock gating on pwm_delay , */\ + { 0xf620, "mtp_ocp_enbl_clk_auto_gating"}, /* Auto clock gating on module ocp , */\ + { 0xf630, "mtp_disable_clk_a_gating"}, /* Disable clock_a gating , */\ + { 0xf642, "spare_mtp6_6_3"}, /* SPARE , */\ + { 0xf686, "spare_mtp6_14_8"}, /* Offset of left amplifier level shifter B , */\ + { 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ + { 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf910, "disable_sam_mode"}, /* Disable sam mode , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Disable programming of max dcdc boost voltage , */\ + { 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf987, "type_bits_fw"}, /* MTP-control FW - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ + { 0xff05, "fro8_trim"}, /* 8 MHz oscillator trim code , */\ + { 0xff61, "fro8_short_nwell_r"}, /* Short 4 or 6 n-well resistors , */\ + { 0xff81, "fro8_boost_i"}, /* Self bias current selection , */\ + { 0xffff, "Unknown bitfield enum" } /* not found */\ +}; + +enum tfa9912_irq { + tfa9912_irq_stvdds = 0, + tfa9912_irq_stplls = 1, + tfa9912_irq_stotds = 2, + tfa9912_irq_stovds = 3, + tfa9912_irq_stuvds = 4, + tfa9912_irq_stclks = 5, + tfa9912_irq_stmtpb = 6, + tfa9912_irq_stnoclk = 7, + tfa9912_irq_stspks = 8, + tfa9912_irq_stacs = 9, + tfa9912_irq_stsws = 10, + tfa9912_irq_stwds = 11, + tfa9912_irq_stamps = 12, + tfa9912_irq_starefs = 13, + tfa9912_irq_stadccr = 14, + tfa9912_irq_stbodnok = 15, + tfa9912_irq_stbstcu = 16, + tfa9912_irq_stbsthi = 17, + tfa9912_irq_stbstoc = 18, + tfa9912_irq_stbstpkcur = 19, + tfa9912_irq_stbstvc = 20, + tfa9912_irq_stbst86 = 21, + tfa9912_irq_stbst93 = 22, + tfa9912_irq_strcvld = 23, + tfa9912_irq_stocpl = 24, + tfa9912_irq_stocpr = 25, + tfa9912_irq_stmwsrc = 26, + tfa9912_irq_stmwcfc = 27, + tfa9912_irq_stmwsmu = 28, + tfa9912_irq_stcfmer = 29, + tfa9912_irq_stcfmac = 30, + tfa9912_irq_stclkoor = 31, + tfa9912_irq_sttdmer = 32, + tfa9912_irq_stclpl = 33, + tfa9912_irq_stclpr = 34, + tfa9912_irq_stocpm = 35, + tfa9912_irq_stlp1 = 37, + tfa9912_irq_stla = 38, + tfa9912_irq_stvddp = 39, + tfa9912_irq_sttapdet = 40, + tfa9912_irq_staudmod = 41, + tfa9912_irq_stsammod = 42, + tfa9912_irq_sttapmod = 43, + tfa9912_irq_sttaptrg = 44, + tfa9912_irq_max = 45, + tfa9912_irq_all = -1 /* all irqs */}; + +#define TFA9912_IRQ_NAMETABLE static tfaIrqName_t Tfa9912IrqNames[] = {\ + { 0, "STVDDS"},\ + { 1, "STPLLS"},\ + { 2, "STOTDS"},\ + { 3, "STOVDS"},\ + { 4, "STUVDS"},\ + { 5, "STCLKS"},\ + { 6, "STMTPB"},\ + { 7, "STNOCLK"},\ + { 8, "STSPKS"},\ + { 9, "STACS"},\ + { 10, "STSWS"},\ + { 11, "STWDS"},\ + { 12, "STAMPS"},\ + { 13, "STAREFS"},\ + { 14, "STADCCR"},\ + { 15, "STBODNOK"},\ + { 16, "STBSTCU"},\ + { 17, "STBSTHI"},\ + { 18, "STBSTOC"},\ + { 19, "STBSTPKCUR"},\ + { 20, "STBSTVC"},\ + { 21, "STBST86"},\ + { 22, "STBST93"},\ + { 23, "STRCVLD"},\ + { 24, "STOCPL"},\ + { 25, "STOCPR"},\ + { 26, "STMWSRC"},\ + { 27, "STMWCFC"},\ + { 28, "STMWSMU"},\ + { 29, "STCFMER"},\ + { 30, "STCFMAC"},\ + { 31, "STCLKOOR"},\ + { 32, "STTDMER"},\ + { 33, "STCLPL"},\ + { 34, "STCLPR"},\ + { 35, "STOCPM"},\ + { 36, "36"},\ + { 37, "STLP1"},\ + { 38, "STLA"},\ + { 39, "STVDDP"},\ + { 40, "STTAPDET"},\ + { 41, "STAUDMOD"},\ + { 42, "STSAMMOD"},\ + { 43, "STTAPMOD"},\ + { 44, "STTAPTRG"},\ + { 45, "45"},\ +}; +#endif /* _TFA9912_TFAFIELDNAMES_H */ diff --git a/sound/soc/codecs/tfa_container.c b/sound/soc/codecs/tfa_container.c new file mode 100644 index 000000000000..0cea84f53cc3 --- /dev/null +++ b/sound/soc/codecs/tfa_container.c @@ -0,0 +1,2410 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#include "dbgprint.h" +#include "tfa_container.h" +#include "tfa.h" +#include "tfa98xx_tfafieldnames.h" +#include "tfa_internal.h" + + /* defines */ +#define MODULE_BIQUADFILTERBANK 2 +#define BIQUAD_COEFF_SIZE 6 +#define ERR -1 + +/* module globals */ +/* This is used to SET the slave with the --slave option */ +static uint8_t gslave_address; + +static int float_to_int(uint32_t x) +{ + unsigned int e = (0x7F + 31) - ((*(unsigned int *)&x & 0x7F800000) >> 23); + unsigned int m = 0x80000000 | (*(unsigned int *)&x << 8); + + return -(int)((m >> e) & -(e < 32)); +} + +/* + * check the container file + */ +enum tfa_error tfa_load_cnt(void *cnt, int length) +{ + nxpTfaContainer_t *cntbuf = (nxpTfaContainer_t *)cnt; + + if (length > TFA_MAX_CNT_LENGTH) { + pr_err("incorrect length\n"); + return tfa_error_container; + } + + if (HDR(cntbuf->id[0], cntbuf->id[1]) == 0) { + pr_err("header is 0\n"); + return tfa_error_container; + } + + if ((HDR(cntbuf->id[0], cntbuf->id[1])) != paramsHdr) { + pr_err("wrong header type: 0x%02x 0x%02x\n", + cntbuf->id[0], cntbuf->id[1]); + return tfa_error_container; + } + + if (cntbuf->size == 0) { + pr_err("data size is 0\n"); + return tfa_error_container; + } + + /* check CRC */ + if (tfaContCrcCheckContainer(cntbuf)) { + pr_err("CRC error\n"); + return tfa_error_container; + } + + /* check sub version level */ + if ((cntbuf->subversion[1] != NXPTFA_PM_SUBVERSION) && + (cntbuf->subversion[0] != '0')) { + pr_err("container sub-version not supported: %c%c\n", + cntbuf->subversion[0], cntbuf->subversion[1]); + return tfa_error_container; + } + + return tfa_error_ok; +} + +/* + * Dump the contents of the file header + */ +void tfaContShowHeader(nxpTfaHeader_t *hdr) +{ + char _id[2]; + + pr_debug("File header\n"); + + _id[1] = hdr->id >> 8; + _id[0] = hdr->id & 0xff; + pr_debug("\tid:%.2s version:%.2s subversion:%.2s\n", _id, + hdr->version, hdr->subversion); + pr_debug("\tsize:%d CRC:0x%08x \n", hdr->size, hdr->CRC); + pr_debug("\tcustomer:%.8s application:%.8s type:%.8s\n", hdr->customer, + hdr->application, hdr->type); +} + +/* + * return device list dsc from index + */ +nxpTfaDeviceList_t *tfaContGetDevList(nxpTfaContainer_t *cont, int dev_idx) +{ + uint8_t *base = (uint8_t *)cont; + + if (cont == NULL) + return NULL; + + if ((dev_idx < 0) || (dev_idx >= cont->ndev)) + return NULL; + + if (cont->index[dev_idx].type != dscDevice) + return NULL; + + base += cont->index[dev_idx].offset; + return (nxpTfaDeviceList_t *)base; +} + +/* + * get the Nth profile for the Nth device + */ +nxpTfaProfileList_t *tfaContGetDevProfList(nxpTfaContainer_t *cont, + int devIdx, int profIdx) +{ + nxpTfaDeviceList_t *dev; + int idx, hit; + uint8_t *base = (uint8_t *)cont; + + dev = tfaContGetDevList(cont, devIdx); + if (dev) { + for (idx = 0, hit = 0; idx < dev->length; idx++) { + if (dev->list[idx].type == dscProfile) { + if (profIdx == hit++) + return (nxpTfaProfileList_t *)(dev->list[idx].offset + base); + } + } + } + + return NULL; +} + +/* + * get the number of profiles for the Nth device + */ +int tfa_cnt_get_dev_nprof(struct tfa_device *tfa) +{ + nxpTfaDeviceList_t *dev; + int idx, nprof = 0; + + if (tfa->cnt == NULL) + return 0; + + if ((tfa->dev_idx < 0) || (tfa->dev_idx >= tfa->cnt->ndev)) + return 0; + + dev = tfaContGetDevList(tfa->cnt, tfa->dev_idx); + if (dev) { + for (idx = 0; idx < dev->length; idx++) { + if (dev->list[idx].type == dscProfile) { + nprof++; + } + } + } + + return nprof; +} + +/* + * get the Nth lifedata for the Nth device + */ +nxpTfaLiveDataList_t *tfaContGetDevLiveDataList(nxpTfaContainer_t *cont, + int devIdx, int lifeDataIdx) +{ + nxpTfaDeviceList_t *dev; + int idx, hit; + uint8_t *base = (uint8_t *)cont; + + dev = tfaContGetDevList(cont, devIdx); + if (dev) { + for (idx = 0, hit = 0; idx < dev->length; idx++) { + if (dev->list[idx].type == dscLiveData) { + if (lifeDataIdx == hit++) + return (nxpTfaLiveDataList_t *) + (dev->list[idx].offset + base); + } + } + } + + return NULL; +} + +/* + * Get the max volume step associated with Nth profile for the Nth device + */ +int tfacont_get_max_vstep(struct tfa_device *tfa, int prof_idx) +{ + nxpTfaVolumeStep2File_t *vp; + struct nxpTfaVolumeStepMax2File *vp3; + int vstep_count = 0; + vp = (nxpTfaVolumeStep2File_t *)tfacont_getfiledata(tfa, prof_idx, + volstepHdr); + if (vp == NULL) + return 0; + /* check the header type to load different NrOfVStep appropriately */ + if (tfa->tfa_family == 2) { + /* this is actually tfa2, so re-read the buffer*/ + vp3 = (struct nxpTfaVolumeStepMax2File *) + tfacont_getfiledata(tfa, prof_idx, volstepHdr); + if (vp3) { + vstep_count = vp3->NrOfVsteps; + } + } else { + /* this is max1*/ + if (vp) { + vstep_count = vp->vsteps; + } + } + return vstep_count; +} + +/** + * Get the file contents associated with the device or profile + * Search within the device tree, if not found, search within the profile + * tree. There can only be one type of file within profile or device. + */ +nxpTfaFileDsc_t *tfacont_getfiledata(struct tfa_device *tfa, + int prof_idx, enum nxpTfaHeaderType type) +{ + nxpTfaDeviceList_t *dev; + nxpTfaProfileList_t *prof; + nxpTfaFileDsc_t *file; + nxpTfaHeader_t *hdr; + unsigned int i; + + if (tfa->cnt == NULL) { + pr_err("invalid pointer to container file\n"); + return NULL; + } + + dev = tfaContGetDevList(tfa->cnt, tfa->dev_idx); + if (dev == NULL) { + pr_err("invalid pointer to container file device list\n"); + return NULL; + } + + /* process the device list until a file type is encountered */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscFile) { + file = (nxpTfaFileDsc_t *)(dev->list[i].offset + (uint8_t *)tfa->cnt); + if (file != NULL) { + hdr = (nxpTfaHeader_t *)file->data; + /* check for file type */ + if (hdr->id == type) { + return (nxpTfaFileDsc_t *)&file->data; + } + } + } + } + + /* File not found in device tree. + * So, look in the profile list until the file type is encountered + */ + prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + if (prof == NULL) { + pr_err("invalid pointer to container file profile list\n"); + return NULL; + } + + for (i = 0; i < prof->length; i++) { + if (prof->list[i].type == dscFile) { + file = (nxpTfaFileDsc_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + if (file != NULL) { + hdr = (nxpTfaHeader_t *)file->data; + if (hdr != NULL) { + /* check for file type */ + if (hdr->id == type) { + return (nxpTfaFileDsc_t *)&file->data; + } + } + } + } + } + + if (tfa->verbose) + pr_debug("%s: no file found of type %d\n", __FUNCTION__, type); + + return NULL; +} + +/* + * write a parameter file to the device + */ +static enum Tfa98xx_Error tfaContWriteVstep(struct tfa_device *tfa, + nxpTfaVolumeStep2File_t *vp, int vstep) +{ + enum Tfa98xx_Error err; + unsigned short vol; + + if (vstep < vp->vsteps) { + /* vol = (unsigned short)(voldB / (-0.5f)); */ + vol = (unsigned short)(-2 * float_to_int(*((uint32_t *)&vp->vstep[vstep].attenuation))); + if (vol > 255) /* restricted to 8 bits */ + vol = 255; + + err = tfa98xx_set_volume_level(tfa, vol); + if (err != Tfa98xx_Error_Ok) + return err; + + err = tfa98xx_dsp_write_preset(tfa, sizeof(vp->vstep[0].preset), vp->vstep[vstep].preset); + if (err != Tfa98xx_Error_Ok) + return err; + err = tfa_cont_write_filterbank(tfa, vp->vstep[vstep].filter); + + } else { + pr_err("Incorrect volume given. The value vstep[%d] >= %d\n", vstep, vp->vsteps); + err = Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->verbose) + pr_debug("vstep[%d][%d]\n", tfa->dev_idx, vstep); + + return err; +} + +static struct nxpTfaVolumeStepMessageInfo * +tfaContGetmsgInfoFromReg(struct nxpTfaVolumeStepRegisterInfo *regInfo) +{ + char *p = (char *)regInfo; + p += sizeof(regInfo->NrOfRegisters) + (regInfo->NrOfRegisters * sizeof(uint32_t)); + return (struct nxpTfaVolumeStepMessageInfo *) p; +} + +static int +tfaContGetmsgLen(struct nxpTfaVolumeStepMessageInfo *msgInfo) +{ + return (msgInfo->MessageLength.b[0] << 16) + + (msgInfo->MessageLength.b[1] << 8) + msgInfo->MessageLength.b[2]; +} + +static struct nxpTfaVolumeStepMessageInfo * +tfaContGetNextmsgInfo(struct nxpTfaVolumeStepMessageInfo *msgInfo) +{ + char *p = (char *)msgInfo; + int msgLen = tfaContGetmsgLen(msgInfo); + int type = msgInfo->MessageType; + + p += sizeof(msgInfo->MessageType) + sizeof(msgInfo->MessageLength); + if (type == 3) + p += msgLen; + else + p += msgLen * 3; + + return (struct nxpTfaVolumeStepMessageInfo *) p; +} + +static struct nxpTfaVolumeStepRegisterInfo* +tfaContGetNextRegFromEndInfo(struct nxpTfaVolumeStepMessageInfo *msgInfo) +{ + char *p = (char *)msgInfo; + p += sizeof(msgInfo->NrOfMessages); + return (struct nxpTfaVolumeStepRegisterInfo *) p; + +} + +static struct nxpTfaVolumeStepRegisterInfo* +tfaContGetRegForVstep(nxpTfaVolumeStepMax2File_t *vp, int idx) +{ + int i, j, nrMessage; + + struct nxpTfaVolumeStepRegisterInfo *regInfo + = (struct nxpTfaVolumeStepRegisterInfo *) vp->vstepsBin; + struct nxpTfaVolumeStepMessageInfo *msgInfo = NULL; + + for (i = 0; i < idx; i++) { + msgInfo = tfaContGetmsgInfoFromReg(regInfo); + nrMessage = msgInfo->NrOfMessages; + + for (j = 0; j < nrMessage; j++) { + msgInfo = tfaContGetNextmsgInfo(msgInfo); + } + regInfo = tfaContGetNextRegFromEndInfo(msgInfo); + } + + return regInfo; +} + +#pragma pack (push, 1) +struct tfa_partial_msg_block { + uint8_t offset; + uint16_t change; + uint8_t update[16][3]; +}; +#pragma pack (pop) + +static enum Tfa98xx_Error tfaContWriteVstepMax2_One(struct tfa_device *tfa, + struct nxpTfaVolumeStepMessageInfo *new_msg, + struct nxpTfaVolumeStepMessageInfo *old_msg, + int enable_partial_update) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int len = (tfaContGetmsgLen(new_msg) - 1) * 3; + char *buf = (char *)new_msg->ParameterData; + uint8_t *partial = NULL; + uint8_t cmdid[3]; + int use_partial_coeff = 0; + + if (enable_partial_update) { + if (new_msg->MessageType != old_msg->MessageType) { + pr_debug("Message type differ - Disable Partial Update\n"); + enable_partial_update = 0; + } else if (tfaContGetmsgLen(new_msg) != tfaContGetmsgLen(old_msg)) { + pr_debug("Message Length differ - Disable Partial Update\n"); + enable_partial_update = 0; + } + } + + if ((enable_partial_update) && (new_msg->MessageType == 1)) { + /* No patial updates for message type 1 (Coefficients) */ + enable_partial_update = 0; + if ((tfa->rev & 0xff) == 0x88) + use_partial_coeff = 1; + else if ((tfa->rev & 0xff) == 0x13) + use_partial_coeff = 1; + } + + /* Change Message Len to the actual buffer len */ + memcpy(cmdid, new_msg->CmdId, sizeof(cmdid)); + + /* The algoparams and mbdrc msg id will be changed to the reset type when SBSL=0 + * if SBSL=1 the msg will remain unchanged. It's up to the tuning engineer to choose the 'without_reset' + * types inside the vstep. In other words: the reset msg is applied during SBSL==0 else it remains unchanged. + */ + if (tfa_needs_reset(tfa) == 1) { + if (new_msg->MessageType == 0) { + cmdid[2] = SB_PARAM_SET_ALGO_PARAMS; + if (tfa->verbose) + pr_debug("P-ID for SetAlgoParams modified!\n"); + } else if (new_msg->MessageType == 2) { + cmdid[2] = SB_PARAM_SET_MBDRC; + if (tfa->verbose) + pr_debug("P-ID for SetMBDrc modified!\n"); + } + } + + /* + * +sizeof(struct tfa_partial_msg_block) will allow to fit one + * additonnal partial block If the partial update goes over the len of + * a regular message ,we can safely write our block and check afterward + * that we are over the size of a usual update + */ + if (enable_partial_update) { + partial = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (!partial) + pr_debug("Partial update memory error - Disabling\n"); + } + + if (partial) { + uint8_t offset = 0, i = 0; + uint16_t *change; + uint8_t *n = new_msg->ParameterData; + uint8_t *o = old_msg->ParameterData; + uint8_t *p = partial; + uint8_t *trim = partial; + + /* set dspFiltersReset */ + *p++ = 0x02; + *p++ = 0x00; + *p++ = 0x00; + + while ((o < (old_msg->ParameterData + len)) && + (p < (partial + len - 3))) { + if ((offset == 0xff) || + (memcmp(n, o, 3 * sizeof(uint8_t)))) { + *p++ = offset; + change = (uint16_t *)p; + *change = 0; + p += 2; + + for (i = 0; + (i < 16) && (o < (old_msg->ParameterData + len)); + i++, n += 3, o += 3) { + if (memcmp(n, o, 3 * sizeof(uint8_t))) { + *change |= BIT(i); + memcpy(p, n, 3); + p += 3; + trim = p; + } + } + + offset = 0; + *change = cpu_to_be16(*change); + } else { + n += 3; + o += 3; + offset++; + } + } + + if (trim == partial) { + pr_debug("No Change in message - discarding %d bytes\n", len); + len = 0; + + } else if (trim < (partial + len - 3)) { + pr_debug("Using partial update: %d -> %d bytes\n", len, (int)(trim - partial + 3)); + + /* Add the termination marker */ + memset(trim, 0x00, 3); + trim += 3; + + /* Signal This will be a partial update */ + cmdid[2] |= BIT(6); + buf = (char *)partial; + len = (int)(trim - partial); + } else { + pr_debug("Partial too big - use regular update\n"); + } + } + + if (use_partial_coeff) { + err = dsp_partial_coefficients(tfa, old_msg->ParameterData, new_msg->ParameterData); + } else if (len) { + uint8_t *buffer; + + if (tfa->verbose) + pr_debug("Command-ID used: 0x%02x%02x%02x \n", cmdid[0], cmdid[1], cmdid[2]); + + buffer = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (buffer == NULL) { + err = Tfa98xx_Error_Fail; + } else { + memcpy(&buffer[0], cmdid, 3); + memcpy(&buffer[3], buf, len); + err = dsp_msg(tfa, 3 + len, (char *)buffer); + kmem_cache_free(tfa->cachep, buffer); + } + } + + if (partial) + kmem_cache_free(tfa->cachep, partial); + + return err; +} + +static enum Tfa98xx_Error tfaContWriteVstepMax2(struct tfa_device *tfa, + nxpTfaVolumeStepMax2File_t *vp, int vstep_idx, + int vstep_msg_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + struct nxpTfaVolumeStepRegisterInfo *regInfo = NULL; + struct nxpTfaVolumeStepMessageInfo *msgInfo = NULL, *p_msgInfo = NULL; + nxpTfaBitfield_t bitF; + int i, nrMessages, enp = tfa->partial_enable; + + if (vstep_idx >= vp->NrOfVsteps) { + pr_debug("Volumestep %d is not available \n", vstep_idx); + return Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->p_regInfo == NULL) { + if (tfa->verbose) + pr_debug("Inital vstep write\n"); + enp = 0; + } + + regInfo = tfaContGetRegForVstep(vp, vstep_idx); + + msgInfo = tfaContGetmsgInfoFromReg(regInfo); + nrMessages = msgInfo->NrOfMessages; + + if (enp) { + p_msgInfo = tfaContGetmsgInfoFromReg(tfa->p_regInfo); + if (nrMessages != p_msgInfo->NrOfMessages) { + pr_debug("Message different - Disable partial update\n"); + enp = 0; + } + } + + for (i = 0; i < nrMessages; i++) { + /* Messagetype(3) is Smartstudio Info! Dont send this! */ + if (msgInfo->MessageType == 3) { + /* MessageLength is in bytes */ + msgInfo = tfaContGetNextmsgInfo(msgInfo); + if (enp) + p_msgInfo = tfaContGetNextmsgInfo(p_msgInfo); + continue; + } + + /* If no vstepMsgIndex is passed on, all message needs to be send */ + if ((vstep_msg_idx >= TFA_MAX_VSTEP_MSG_MARKER) || (vstep_msg_idx == i)) { + err = tfaContWriteVstepMax2_One(tfa, msgInfo, p_msgInfo, enp); + if (err != Tfa98xx_Error_Ok) { + /* + * Force a full update for the next write + * As the current status of the DSP is unknown + */ + tfa->p_regInfo = NULL; + return err; + } + } + + msgInfo = tfaContGetNextmsgInfo(msgInfo); + if (enp) + p_msgInfo = tfaContGetNextmsgInfo(p_msgInfo); + } + + tfa->p_regInfo = regInfo; + + for (i = 0; i < regInfo->NrOfRegisters * 2; i++) { + /* Byte swap the datasheetname */ + bitF.field = (uint16_t)(regInfo->registerInfo[i] >> 8) | (regInfo->registerInfo[i] << 8); + i++; + bitF.value = (uint16_t)regInfo->registerInfo[i] >> 8; + err = tfaRunWriteBitfield(tfa, bitF); + if (err != Tfa98xx_Error_Ok) + return err; + } + + /* Save the current vstep */ + tfa_dev_set_swvstep(tfa, (unsigned short)vstep_idx); + + return err; +} + +/* + * Write DRC message to the dsp + * If needed modify the cmd-id + */ + +enum Tfa98xx_Error tfaContWriteDrcFile(struct tfa_device *tfa, + int size, uint8_t data[]) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + uint8_t *msg = NULL; + + msg = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (msg == NULL) + return Tfa98xx_Error_Fail; + memcpy(msg, data, size); + + if (TFA_GET_BF(tfa, SBSL) == 0) { + /* Only do this when not set already */ + if (msg[2] != SB_PARAM_SET_MBDRC) { + msg[2] = SB_PARAM_SET_MBDRC; + + if (tfa->verbose) { + pr_debug("P-ID for SetMBDrc modified!: "); + pr_debug("Command-ID used: 0x%02x%02x%02x \n", + msg[0], msg[1], msg[2]); + } + } + } + + /* Send cmdId + payload to dsp */ + err = dsp_msg(tfa, size, (const char *)msg); + + kmem_cache_free(tfa->cachep, msg); + + return err; +} + + +/* + * write a parameter file to the device + * The VstepIndex and VstepMsgIndex are only used to write a specific msg from the vstep file. + */ +enum Tfa98xx_Error tfaContWriteFile(struct tfa_device *tfa, + nxpTfaFileDsc_t *file, int vstep_idx, int vstep_msg_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaHeader_t *hdr = (nxpTfaHeader_t *)file->data; + nxpTfaHeaderType_t type; + int size, i; + char subVerString[8] = { 0 }; + int subversion = 0; + + if (tfa->verbose) { + tfaContShowHeader(hdr); + } + + type = (nxpTfaHeaderType_t)hdr->id; + if ((type == msgHdr) || ((type == volstepHdr) && (tfa->tfa_family == 2))) { + subVerString[0] = hdr->subversion[0]; + subVerString[1] = hdr->subversion[1]; + subVerString[2] = '\0'; + + sscanf(subVerString, "%d", &subversion); + + if ((subversion > 0) && + (((hdr->customer[0]) == 'A') && ((hdr->customer[1]) == 'P') && + ((hdr->customer[2]) == 'I') && ((hdr->customer[3]) == 'V'))) { + if (tfa->is_probus_device) { + /* Temporary workaround (example: For climax --calibrate + * scenario for probus devices) + */ + err = tfaGetFwApiVersion(tfa, + (unsigned char *)&tfa->fw_itf_ver[0]); + if (err) { + pr_debug("[%s] cannot get FWAPI error = %d \n", + __FUNCTION__, err); + return err; + } + for (i = 0; i < 3; i++) { + //+4 to skip "?PIV" string part in the .msg file. + if (tfa->fw_itf_ver[i] != hdr->customer[i + 4]) { + ERRORMSG("Error: tfaContWriteFile: Expected FW API \ + version = %d.%d.%d, Msg File version: %d.%d.%d \n", + tfa->fw_itf_ver[0], + tfa->fw_itf_ver[1], + tfa->fw_itf_ver[2], + hdr->customer[4], + hdr->customer[5], + hdr->customer[6]); + return Tfa98xx_Error_Bad_Parameter; + } + } + } else if ((tfa->fw_itf_ver[2] != hdr->customer[4]) || + (tfa->fw_itf_ver[1] != hdr->customer[5]) || + ((tfa->fw_itf_ver[0] >> 6) & 0x03) != hdr->customer[6]) { + + ERRORMSG("Error: tfaContWriteFile: Expected FW API version = %d.%d.%d, Msg File version: %d.%d.%d \n", + (tfa->fw_itf_ver[2]) & 0xff, + (tfa->fw_itf_ver[1]) & 0xff, + (tfa->fw_itf_ver[0] >> 6) & 0x03, + hdr->customer[4], + hdr->customer[5], + hdr->customer[6]); + return Tfa98xx_Error_Bad_Parameter; + } + } + } + + switch (type) { + case msgHdr: /* generic DSP message */ + size = hdr->size - sizeof(nxpTfaMsgFile_t); + err = dsp_msg(tfa, size, (const char *)((nxpTfaMsgFile_t *)hdr)->data); + break; + case volstepHdr: + if (tfa->tfa_family == 2) { + err = tfaContWriteVstepMax2(tfa, + (nxpTfaVolumeStepMax2File_t *)hdr, + vstep_idx, vstep_msg_idx); + } else { + err = tfaContWriteVstep(tfa, (nxpTfaVolumeStep2File_t *)hdr, + vstep_idx); + } + break; + case speakerHdr: + if (tfa->tfa_family == 2) { + /* Remove header and xml_id */ + size = hdr->size - sizeof(struct nxpTfaSpkHeader) + - sizeof(struct nxpTfaFWVer); + + err = dsp_msg(tfa, size, + (const char *)(((nxpTfaSpeakerFile_t *)hdr)->data + + (sizeof(struct nxpTfaFWVer)))); + } else { + size = hdr->size - sizeof(nxpTfaSpeakerFile_t); + err = tfa98xx_dsp_write_speaker_parameters(tfa, size, + (const unsigned char *)((nxpTfaSpeakerFile_t *)hdr)->data); + } + break; + case presetHdr: + size = hdr->size - sizeof(nxpTfaPreset_t); + err = tfa98xx_dsp_write_preset(tfa, size, + (const unsigned char *)((nxpTfaPreset_t *)hdr)->data); + break; + case equalizerHdr: + err = tfa_cont_write_filterbank(tfa, ((nxpTfaEqualizerFile_t *)hdr)->filter); + break; + case patchHdr: + size = hdr->size - sizeof(nxpTfaPatch_t); // size is total length + err = tfa_dsp_patch(tfa, size, (const unsigned char *)((nxpTfaPatch_t *)hdr)->data); + break; + case configHdr: + size = hdr->size - sizeof(nxpTfaConfig_t); + err = tfa98xx_dsp_write_config(tfa, size, + (const unsigned char *)((nxpTfaConfig_t *)hdr)->data); + break; + case drcHdr: + if (hdr->version[0] == NXPTFA_DR3_VERSION) { + /* Size is total size - hdrsize(36) - xmlversion(3) */ + size = hdr->size - sizeof(nxpTfaDrc2_t); + err = tfaContWriteDrcFile(tfa, size, ((nxpTfaDrc2_t *)hdr)->data); + } else { + /* + * The DRC file is split as: + * 36 bytes for generic header (customer, application, and type) + * 127x3 (381) bytes first block contains the device and sample rate + * independent settings + * 127x3 (381) bytes block the device and sample rate specific values. + * The second block can always be recalculated from the first block, + * if vlsCal and the sample rate are known. + */ + //size = hdr->size - sizeof(nxpTfaDrc_t); + size = 381; /* fixed size for first block */ + + //+381 is done to only send the second part of the drc block + err = tfa98xx_dsp_write_drc(tfa, size, + ((const unsigned char *)((nxpTfaDrc_t *)hdr)->data + 381)); + } + break; + case infoHdr: + /* Ignore */ + break; + default: + pr_err("Header is of unknown type: 0x%x\n", type); + return Tfa98xx_Error_Bad_Parameter; + } + + return err; +} + +/** + * get the 1st of this dsc type this devicelist + */ +static nxpTfaDescPtr_t *tfa_cnt_get_dsc(nxpTfaContainer_t *cnt, nxpTfaDescriptorType_t type, int dev_idx) +{ + nxpTfaDeviceList_t *dev = tfaContDevice(cnt, dev_idx); + nxpTfaDescPtr_t *_this; + int i; + + if (!dev) { + return NULL; + } + /* process the list until a the type is encountered */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == (uint32_t)type) { + _this = (nxpTfaDescPtr_t *)(dev->list[i].offset + (uint8_t *)cnt); + return _this; + } + + } + + return NULL; +} + +/** + * get the device type from the patch in this devicelist + * - find the patch file for this devidx + * - return the devid from the patch or 0 if not found + */ +int tfa_cnt_get_devid(nxpTfaContainer_t *cnt, int dev_idx) +{ + nxpTfaPatch_t *patchfile; + nxpTfaDescPtr_t *patchdsc; + uint8_t *patchheader; + unsigned short devid, checkaddress; + int checkvalue; + + patchdsc = tfa_cnt_get_dsc(cnt, dscPatch, dev_idx); + if (!patchdsc) /* no patch for this device, assume non-i2c */ + return 0; + patchdsc += 2; /* first the filename dsc and filesize, so skip them */ + patchfile = (nxpTfaPatch_t *)patchdsc; + + patchheader = patchfile->data; + + checkaddress = (patchheader[1] << 8) + patchheader[2]; + checkvalue = + (patchheader[3] << 16) + (patchheader[4] << 8) + patchheader[5]; + + devid = patchheader[0]; + + if (checkaddress == 0xFFFF && checkvalue != 0xFFFFFF && checkvalue != 0) { + devid = patchheader[5] << 8 | patchheader[0]; /* full revid */ + } + + return devid; +} + +/** + * get the firmware version from the patch in this devicelist + */ +int tfa_cnt_get_patch_version(struct tfa_device *tfa) +{ + nxpTfaPatch_t *patchfile; + nxpTfaDescPtr_t *patchdsc; + uint8_t *data; + int size, version; + + if (tfa->cnt == NULL) + return ERR; + + patchdsc = tfa_cnt_get_dsc(tfa->cnt, dscPatch, tfa->dev_idx); + patchdsc += 2; /* first the filename dsc and filesize, so skip them */ + patchfile = (nxpTfaPatch_t *)patchdsc; + + size = patchfile->hdr.size - sizeof(nxpTfaPatch_t); + data = patchfile->data; + + version = (data[size - 3] << 16) + (data[size - 2] << 8) + data[size - 1]; + + return version; +} + + +/* + * get the slave for the device if it exists + */ +enum Tfa98xx_Error tfaContGetSlave(struct tfa_device *tfa, uint8_t *slave_addr) +{ + nxpTfaDeviceList_t *dev = NULL; + + /* Make sure the cnt file is loaded */ + if (tfa->cnt != NULL) { + dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + } + + if (dev == NULL) { + /* Check if slave argument is used! */ + if (gslave_address == 0) { + return Tfa98xx_Error_Bad_Parameter; + } else { + *slave_addr = gslave_address; + return Tfa98xx_Error_Ok; + } + } + + *slave_addr = dev->dev; + return Tfa98xx_Error_Ok; +} + +/* If no container file is given, we can always have used the slave argument */ +void tfaContSetSlave(uint8_t slave_addr) +{ + gslave_address = slave_addr; +} + +/* + * lookup slave and return device index + */ +int tfa_cont_get_idx(struct tfa_device *tfa) +{ + nxpTfaDeviceList_t *dev = NULL; + int i; + + for (i = 0; i < tfa->cnt->ndev; i++) { + dev = tfaContDevice(tfa->cnt, i); + if (dev->dev == tfa->slave_address) + break; + + } + if (i == tfa->cnt->ndev) + return ERR; + + return i; +} + +/* + * write a bit field + */ +enum Tfa98xx_Error tfaRunWriteBitfield(struct tfa_device *tfa, nxpTfaBitfield_t bf) +{ + enum Tfa98xx_Error error; + uint16_t value; + union { + uint16_t field; + nxpTfaBfEnum_t Enum; + } bfUni; + + value = bf.value; + bfUni.field = bf.field; +#ifdef TFA_DEBUG + if (tfa->verbose) + pr_debug("bitfield: %s=0x%x (0x%x[%d..%d]=0x%x)\n", tfaContBfName(bfUni.field, tfa->rev), value, + bfUni.Enum.address, bfUni.Enum.pos, bfUni.Enum.pos + bfUni.Enum.len, value); +#endif + error = tfa_set_bf(tfa, bfUni.field, value); + + return error; +} + +/* + * read a bit field + */ +enum Tfa98xx_Error tfaRunReadBitfield(struct tfa_device *tfa, nxpTfaBitfield_t *bf) +{ + enum Tfa98xx_Error error; + union { + uint16_t field; + nxpTfaBfEnum_t Enum; + } bfUni; + uint16_t regvalue, msk; + + bfUni.field = bf->field; + + error = reg_read(tfa, (unsigned char)(bfUni.Enum.address), ®value); + if (error) + return error; + + msk = ((1 << (bfUni.Enum.len + 1)) - 1) << bfUni.Enum.pos; + + regvalue &= msk; + bf->value = regvalue >> bfUni.Enum.pos; + + return error; +} + +/* + dsp mem direct write + */ +static enum Tfa98xx_Error tfaRunWriteDspMem(struct tfa_device *tfa, nxpTfaDspMem_t *cfmem) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int i; + + for (i = 0; i < cfmem->size; i++) { + if (tfa->verbose) + pr_debug("dsp mem (%d): 0x%02x=0x%04x\n", cfmem->type, cfmem->address, cfmem->words[i]); + + error = mem_write(tfa, cfmem->address++, cfmem->words[i], cfmem->type); + if (error) + return error; + } + + return error; +} + +/* + * write filter payload to DSP + * note that the data is in an aligned union for all filter variants + * the aa data is used but it's the same for all of them + */ +static enum Tfa98xx_Error tfaRunWriteFilter(struct tfa_device *tfa, nxpTfaContBiquad_t *bq) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + enum Tfa98xx_DMEM dmem; + uint16_t address; + uint8_t data[3 * 3 + sizeof(bq->aa.bytes)]; + int i, channel = 0, runs = 1; + int8_t saved_index = bq->aa.index; /* This is used to set back the index */ + + /* Channel=1 is primary, Channel=2 is secondary*/ + if (bq->aa.index > 100) { + bq->aa.index -= 100; + channel = 2; + } else if (bq->aa.index > 50) { + bq->aa.index -= 50; + channel = 1; + } else if ((tfa->rev & 0xff) == 0x88) { + runs = 2; + } + + if (tfa->verbose) { + if (channel == 2) + pr_debug("filter[%d,S]", bq->aa.index); + else if (channel == 1) + pr_debug("filter[%d,P]", bq->aa.index); + else + pr_debug("filter[%d]", bq->aa.index); + } + + for (i = 0; i < runs; i++) { + if (runs == 2) + channel++; + + /* get the target address for the filter on this device */ + dmem = tfa98xx_filter_mem(tfa, bq->aa.index, &address, channel); + if (dmem == Tfa98xx_DMEM_ERR) { + if (tfa->verbose) { + pr_debug("Warning: XFilter settings are applied via msg file (ini filter[x] format is skipped).\n"); + } + /* Dont exit with an error here, We could continue without problems */ + return Tfa98xx_Error_Ok; + } + + /* send a DSP memory message that targets the devices specific memory for the filter + * msg params: which_mem, start_offset, num_words + */ + memset(data, 0, 3 * 3); + data[2] = dmem; /* output[0] = which_mem */ + data[4] = address >> 8; /* output[1] = start_offset */ + data[5] = address & 0xff; + data[8] = sizeof(bq->aa.bytes) / 3; /*output[2] = num_words */ + memcpy(&data[9], bq->aa.bytes, sizeof(bq->aa.bytes)); /* payload */ + + if (tfa->tfa_family == 2) + error = tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, FW_PAR_ID_SET_MEMORY, sizeof(data), data); + else + error = tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, 4 /* param */, sizeof(data), data); + } + +#ifdef TFA_DEBUG + if (tfa->verbose) { + if (bq->aa.index == 13) { + pr_debug("=%d,%.0f,%.2f \n", + bq->in.type, bq->in.cutOffFreq, bq->in.leakage); + } else if (bq->aa.index >= 10 && bq->aa.index <= 12) { + pr_debug("=%d,%.0f,%.1f,%.1f \n", bq->aa.type, + bq->aa.cutOffFreq, bq->aa.rippleDb, bq->aa.rolloff); + } else { + pr_debug("= unsupported filter index \n"); + } + } +#endif + + /* Because we can load the same filters multiple times + * For example: When we switch profile we re-write in operating mode. + * We then need to remember the index (primary, secondary or both) + */ + bq->aa.index = saved_index; + + return error; +} + +/* + * write the register based on the input address, value and mask + * only the part that is masked will be updated + */ +static enum Tfa98xx_Error tfaRunWriteRegister(struct tfa_device *tfa, nxpTfaRegpatch_t *reg) +{ + enum Tfa98xx_Error error; + uint16_t value, newvalue; + + if (tfa->verbose) + pr_debug("register: 0x%02x=0x%04x (msk=0x%04x)\n", reg->address, reg->value, reg->mask); + + error = reg_read(tfa, reg->address, &value); + if (error) + return error; + + value &= ~reg->mask; + newvalue = reg->value & reg->mask; + + value |= newvalue; + error = reg_write(tfa, reg->address, value); + + return error; + +} + +// write reg and bitfield items in the devicelist to the target +enum Tfa98xx_Error tfaContWriteRegsDev(struct tfa_device *tfa) +{ + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + nxpTfaBitfield_t *bitF; + int i; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if (!dev) { + return Tfa98xx_Error_Bad_Parameter; + } + + /* process the list until a patch, file of profile is encountered */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscPatch || + dev->list[i].type == dscFile || + dev->list[i].type == dscProfile) + break; + + if (dev->list[i].type == dscBitfield) { + bitF = (nxpTfaBitfield_t *)(dev->list[i].offset + (uint8_t *)tfa->cnt); + err = tfaRunWriteBitfield(tfa, *bitF); + } + if (dev->list[i].type == dscRegister) { + err = tfaRunWriteRegister(tfa, (nxpTfaRegpatch_t *)(dev->list[i].offset + (char *)tfa->cnt)); + } + + if (err) + break; + } + + return err; +} + +// write reg and bitfield items in the profilelist the target +enum Tfa98xx_Error tfaContWriteRegsProf(struct tfa_device *tfa, int prof_idx) +{ + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + nxpTfaBitfield_t *bitf; + unsigned int i; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if (!prof) { + return Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->verbose) + pr_debug("----- profile: %s (%d) -----\n", tfaContGetString(tfa->cnt, &prof->name), prof_idx); + + /* process the list until the end of the profile or the default section */ + for (i = 0; i < prof->length; i++) { + /* We only want to write the values before the default section when we switch profile */ + if (prof->list[i].type == dscDefault) + break; + + if (prof->list[i].type == dscBitfield) { + bitf = (nxpTfaBitfield_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + err = tfaRunWriteBitfield(tfa, *bitf); + } + if (prof->list[i].type == dscRegister) { + err = tfaRunWriteRegister(tfa, (nxpTfaRegpatch_t *)(prof->list[i].offset + (char *)tfa->cnt)); + } + if (err) + break; + } + return err; +} + +// write patchfile in the devicelist to the target +enum Tfa98xx_Error tfaContWritePatch(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + nxpTfaFileDsc_t *file; + nxpTfaPatch_t *patchfile; + int size, i; + + if (!dev) { + return Tfa98xx_Error_Bad_Parameter; + } + /* process the list until a patch is encountered */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscPatch) { + file = (nxpTfaFileDsc_t *)(dev->list[i].offset + (uint8_t *)tfa->cnt); + patchfile = (nxpTfaPatch_t *)&file->data; + if (tfa->verbose) + tfaContShowHeader(&patchfile->hdr); + size = patchfile->hdr.size - sizeof(nxpTfaPatch_t); // size is total length + err = tfa_dsp_patch(tfa, size, (const unsigned char *)patchfile->data); + if (err) + return err; + } + } + + return Tfa98xx_Error_Ok; +} + +/** + * Create a buffer which can be used to send to the dsp. + */ +static void create_dsp_buffer_msg(struct tfa_device *tfa, nxpTfaMsg_t *msg, char *buffer, int *size) +{ + int i, nr = 0; + + (void)tfa; + + /* Copy cmdId. Remember that the cmdId is reversed */ + buffer[nr++] = msg->cmdId[2]; + buffer[nr++] = msg->cmdId[1]; + buffer[nr++] = msg->cmdId[0]; + + /* Copy the data to the buffer */ + for (i = 0; i < msg->msg_size; i++) { + buffer[nr++] = (uint8_t)((msg->data[i] >> 16) & 0xffff); + buffer[nr++] = (uint8_t)((msg->data[i] >> 8) & 0xff); + buffer[nr++] = (uint8_t)(msg->data[i] & 0xff); + } + + *size = nr; +} + +// write all param files in the devicelist to the target +enum Tfa98xx_Error tfaContWriteFiles(struct tfa_device *tfa) +{ + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + nxpTfaFileDsc_t *file; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + char buffer[(MEMTRACK_MAX_WORDS * 3) + 3] = { 0 }; //every word requires 3 and 3 is the msg + int i, size = 0; + + if (!dev) { + return Tfa98xx_Error_Bad_Parameter; + } + /* process the list and write all files */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscFile) { + file = (nxpTfaFileDsc_t *)(dev->list[i].offset + (uint8_t *)tfa->cnt); + if (tfaContWriteFile(tfa, file, 0, TFA_MAX_VSTEP_MSG_MARKER)) { + return Tfa98xx_Error_Bad_Parameter; + } + } + + if (dev->list[i].type == dscSetInputSelect || + dev->list[i].type == dscSetOutputSelect || + dev->list[i].type == dscSetProgramConfig || + dev->list[i].type == dscSetLagW || + dev->list[i].type == dscSetGains || + dev->list[i].type == dscSetvBatFactors || + dev->list[i].type == dscSetSensesCal || + dev->list[i].type == dscSetSensesDelay || + dev->list[i].type == dscSetMBDrc || + dev->list[i].type == dscSetFwkUseCase || + dev->list[i].type == dscSetVddpConfig) { + create_dsp_buffer_msg(tfa, (nxpTfaMsg_t *) + (dev->list[i].offset + (char *)tfa->cnt), buffer, &size); + if (tfa->verbose) { + pr_debug("command: %s=0x%02x%02x%02x \n", + tfaContGetCommandString(dev->list[i].type), + (unsigned char)buffer[0], (unsigned char)buffer[1], (unsigned char)buffer[2]); + } + + err = dsp_msg(tfa, size, buffer); + } + + if (dev->list[i].type == dscCmd) { + size = *(uint16_t *)(dev->list[i].offset + (char *)tfa->cnt); + + err = dsp_msg(tfa, size, dev->list[i].offset + 2 + (char *)tfa->cnt); + if (tfa->verbose) { + const char *cmd_id = dev->list[i].offset + 2 + (char *)tfa->cnt; + pr_debug("Writing cmd=0x%02x%02x%02x \n", (uint8_t)cmd_id[0], (uint8_t)cmd_id[1], (uint8_t)cmd_id[2]); + } + } + if (err != Tfa98xx_Error_Ok) + break; + + if (dev->list[i].type == dscCfMem) { + err = tfaRunWriteDspMem(tfa, (nxpTfaDspMem_t *)(dev->list[i].offset + (uint8_t *)tfa->cnt)); + } + + if (err != Tfa98xx_Error_Ok) + break; + } + + return err; +} + +/* + * write all param files in the profilelist to the target + * this is used during startup when maybe ACS is set + */ +enum Tfa98xx_Error tfaContWriteFilesProf(struct tfa_device *tfa, int prof_idx, int vstep_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + char buffer[(MEMTRACK_MAX_WORDS * 3) + 3] = { 0 }; //every word requires 3 and 3 is the msg + unsigned int i; + nxpTfaFileDsc_t *file; + nxpTfaPatch_t *patchfile; + int size; + + if (!prof) { + return Tfa98xx_Error_Bad_Parameter; + } + + /* process the list and write all files */ + for (i = 0; i < prof->length; i++) { + switch (prof->list[i].type) { + case dscFile: + file = (nxpTfaFileDsc_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + err = tfaContWriteFile(tfa, file, vstep_idx, TFA_MAX_VSTEP_MSG_MARKER); + break; + case dscPatch: + file = (nxpTfaFileDsc_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + patchfile = (nxpTfaPatch_t *)&file->data; + if (tfa->verbose) + tfaContShowHeader(&patchfile->hdr); + size = patchfile->hdr.size - sizeof(nxpTfaPatch_t); // size is total length + err = tfa_dsp_patch(tfa, size, (const unsigned char *)patchfile->data); + break; + case dscCfMem: + err = tfaRunWriteDspMem(tfa, (nxpTfaDspMem_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt)); + break; + case dscSetInputSelect: + case dscSetOutputSelect: + case dscSetProgramConfig: + case dscSetLagW: + case dscSetGains: + case dscSetvBatFactors: + case dscSetSensesCal: + case dscSetSensesDelay: + case dscSetMBDrc: + case dscSetFwkUseCase: + case dscSetVddpConfig: + create_dsp_buffer_msg(tfa, (nxpTfaMsg_t *) + (prof->list[i].offset + (uint8_t *)tfa->cnt), buffer, &size); + if (tfa->verbose) { + pr_debug("command: %s=0x%02x%02x%02x \n", + tfaContGetCommandString(prof->list[i].type), + (unsigned char)buffer[0], (unsigned char)buffer[1], (unsigned char)buffer[2]); + } + + err = dsp_msg(tfa, size, buffer); + break; + default: + /* ignore any other type */ + break; + } + } + + return err; +} + +static enum Tfa98xx_Error tfaContWriteItem(struct tfa_device *tfa, nxpTfaDescPtr_t *dsc) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaRegpatch_t *reg; + nxpTfaMode_t *cas; + nxpTfaBitfield_t *bitf; + + // When no DSP should only write to HW registers. + if (tfa->ext_dsp == 0 && !(dsc->type == dscBitfield || dsc->type == dscRegister)) { + return Tfa98xx_Error_Ok; + } + + switch (dsc->type) { + case dscDefault: + case dscDevice: // ignore + case dscProfile: // profile list + break; + case dscRegister: // register patch + reg = (nxpTfaRegpatch_t *)(dsc->offset + (uint8_t *)tfa->cnt); + return tfaRunWriteRegister(tfa, reg); + //pr_debug("$0x%2x=0x%02x,0x%02x\n", reg->address, reg->mask, reg->value); + break; + case dscString: // ascii: zero terminated string + pr_debug(";string: %s\n", tfaContGetString(tfa->cnt, dsc)); + break; + case dscFile: // filename + file contents + case dscPatch: + break; + case dscMode: + cas = (nxpTfaMode_t *)(dsc->offset + (uint8_t *)tfa->cnt); + if (cas->value == Tfa98xx_Mode_RCV) + tfa98xx_select_mode(tfa, Tfa98xx_Mode_RCV); + else + tfa98xx_select_mode(tfa, Tfa98xx_Mode_Normal); + break; + case dscCfMem: + err = tfaRunWriteDspMem(tfa, (nxpTfaDspMem_t *)(dsc->offset + (uint8_t *)tfa->cnt)); + break; + case dscBitfield: + bitf = (nxpTfaBitfield_t *)(dsc->offset + (uint8_t *)tfa->cnt); + return tfaRunWriteBitfield(tfa, *bitf); + break; + case dscFilter: + return tfaRunWriteFilter(tfa, (nxpTfaContBiquad_t *)(dsc->offset + (uint8_t *)tfa->cnt)); + break; + } + + return err; +} + +static unsigned int tfa98xx_sr_from_field(unsigned int field) +{ + switch (field) { + case 0: + return 8000; + case 1: + return 11025; + case 2: + return 12000; + case 3: + return 16000; + case 4: + return 22050; + case 5: + return 24000; + case 6: + return 32000; + case 7: + return 44100; + case 8: + return 48000; + default: + return 0; + } +} + +enum Tfa98xx_Error tfa_write_filters(struct tfa_device *tfa, int prof_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + unsigned int i; + int status; + + if (!prof) { + return Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->verbose) { + pr_debug("----- profile: %s (%d) -----\n", tfaContGetString(tfa->cnt, &prof->name), prof_idx); + pr_debug("Waiting for CLKS... \n"); + } + + for (i = 10; i > 0; i--) { + err = tfa98xx_dsp_system_stable(tfa, &status); + if (status) + break; + else + msleep_interruptible(10); + } + + if (i == 0) { + if (tfa->verbose) + pr_err("Unable to write filters, CLKS=0 \n"); + + return Tfa98xx_Error_StateTimedOut; + } + + /* process the list until the end of the profile or the default section */ + for (i = 0; i < prof->length; i++) { + if (prof->list[i].type == dscFilter) { + if (tfaContWriteItem(tfa, &prof->list[i]) != Tfa98xx_Error_Ok) + return Tfa98xx_Error_Bad_Parameter; + } + } + + return err; +} + +unsigned int tfa98xx_get_profile_sr(struct tfa_device *tfa, unsigned int prof_idx) +{ + nxpTfaBitfield_t *bitf; + unsigned int i; + nxpTfaDeviceList_t *dev; + nxpTfaProfileList_t *prof; + int fs_profile = -1; + + dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + if (!dev) + return 0; + + prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + if (!prof) + return 0; + + /* Check profile fields first */ + for (i = 0; i < prof->length; i++) { + if (prof->list[i].type == dscDefault) + break; + + /* check for profile settingd (AUDFS) */ + if (prof->list[i].type == dscBitfield) { + bitf = (nxpTfaBitfield_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + if (bitf->field == TFA_FAM(tfa, AUDFS)) { + fs_profile = bitf->value; + break; + } + } + } + + if (tfa->verbose) + pr_debug("%s - profile fs: 0x%x = %dHz (%d - %d)\n", + __FUNCTION__, fs_profile, + tfa98xx_sr_from_field(fs_profile), + tfa->dev_idx, prof_idx); + + if (fs_profile != -1) + return tfa98xx_sr_from_field(fs_profile); + + /* Check for container default setting */ + /* process the list until a patch, file of profile is encountered */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscPatch || + dev->list[i].type == dscFile || + dev->list[i].type == dscProfile) + break; + + if (dev->list[i].type == dscBitfield) { + bitf = (nxpTfaBitfield_t *)(dev->list[i].offset + (uint8_t *)tfa->cnt); + if (bitf->field == TFA_FAM(tfa, AUDFS)) { + fs_profile = bitf->value; + break; + } + } + /* Ignore register case */ + } + + if (tfa->verbose) + pr_debug("%s - default fs: 0x%x = %dHz (%d - %d)\n", + __FUNCTION__, fs_profile, + tfa98xx_sr_from_field(fs_profile), + tfa->dev_idx, prof_idx); + + if (fs_profile != -1) + return tfa98xx_sr_from_field(fs_profile); + + return 48000; /* default of HW */ +} + +static enum Tfa98xx_Error get_sample_rate_info(struct tfa_device *tfa, nxpTfaProfileList_t *prof, nxpTfaProfileList_t *previous_prof, int fs_previous_profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaBitfield_t *bitf; + unsigned int i; + int fs_default_profile = 8; /* default is 48kHz */ + int fs_next_profile = 8; /* default is 48kHz */ + + + /* ---------- default settings previous profile ---------- */ + for (i = 0; i < previous_prof->length; i++) { + /* Search for the default section */ + if (i == 0) { + while (previous_prof->list[i].type != dscDefault && i < previous_prof->length) { + i++; + } + i++; + } + + /* Only if we found the default section search for AUDFS */ + if (i < previous_prof->length) { + if (previous_prof->list[i].type == dscBitfield) { + bitf = (nxpTfaBitfield_t *)(previous_prof->list[i].offset + (uint8_t *)tfa->cnt); + if (bitf->field == TFA_FAM(tfa, AUDFS)) { + fs_default_profile = bitf->value; + break; + } + } + } + } + + /* ---------- settings next profile ---------- */ + for (i = 0; i < prof->length; i++) { + /* We only want to write the values before the default section */ + if (prof->list[i].type == dscDefault) + break; + /* search for AUDFS */ + if (prof->list[i].type == dscBitfield) { + bitf = (nxpTfaBitfield_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + if (bitf->field == TFA_FAM(tfa, AUDFS)) { + fs_next_profile = bitf->value; + break; + } + } + } + + /* Enable if needed for debugging! + if (tfa->verbose) { + pr_debug("sample rate from the previous profile: %d \n", fs_previous_profile); + pr_debug("sample rate in the default section: %d \n", fs_default_profile); + pr_debug("sample rate for the next profile: %d \n", fs_next_profile); + } + */ + + if (fs_next_profile != fs_default_profile) { + if (tfa->verbose) + pr_debug("Writing delay tables for AUDFS=%d \n", fs_next_profile); + + /* If the AUDFS from the next profile is not the same as + * the AUDFS from the default we need to write new delay tables + */ + err = tfa98xx_dsp_write_tables(tfa, fs_next_profile); + } else if (fs_default_profile != fs_previous_profile) { + if (tfa->verbose) + pr_debug("Writing delay tables for AUDFS=%d \n", fs_default_profile); + + /* But if we do not have a new AUDFS in the next profile and + * the AUDFS from the default profile is not the same as the AUDFS + * from the previous profile we also need to write new delay tables + */ + err = tfa98xx_dsp_write_tables(tfa, fs_default_profile); + } + + return err; +} + +/* + * process all items in the profilelist + * NOTE an error return during processing will leave the device muted + * + */ +enum Tfa98xx_Error tfaContWriteProfile(struct tfa_device *tfa, int prof_idx, int vstep_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + nxpTfaProfileList_t *previous_prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, tfa_dev_get_swprof(tfa)); + char buffer[(MEMTRACK_MAX_WORDS * 4) + 4] = { 0 }; //every word requires 3 or 4 bytes, and 3 or 4 is the msg + unsigned int i, k = 0, j = 0, tries = 0; + nxpTfaFileDsc_t *file; + int size = 0, ready, fs_previous_profile = 8; /* default fs is 48kHz*/ + + if (!prof || !previous_prof) { + pr_err("Error trying to get the (previous) swprofile \n"); + return Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->verbose) { + tfa98xx_trace_printk("device:%s profile:%s vstep:%d\n", tfaContDeviceName(tfa->cnt, tfa->dev_idx), + tfaContProfileName(tfa->cnt, tfa->dev_idx, prof_idx), vstep_idx); + } + + /* We only make a power cycle when the profiles are not in the same group */ + if (prof->group == previous_prof->group && prof->group != 0) { + if (tfa->verbose) { + pr_debug("The new profile (%s) is in the same group as the current profile (%s) \n", + tfaContGetString(tfa->cnt, &prof->name), tfaContGetString(tfa->cnt, &previous_prof->name)); + } + } else { + /* mute */ + err = tfaRunMute(tfa); + if (err) + return err; + + /* Get current sample rate before we start switching */ + fs_previous_profile = TFA_GET_BF(tfa, AUDFS); + + /* clear SBSL to make sure we stay in initCF state */ + if (tfa->tfa_family == 2) { + TFA_SET_BF_VOLATILE(tfa, SBSL, 0); + } + + /* When we switch profile we first power down the subsystem + * This should only be done when we are in operating mode + */ + if (((tfa->tfa_family == 2) && (TFA_GET_BF(tfa, MANSTATE) >= 6)) || (tfa->tfa_family != 2)) { + err = tfa98xx_powerdown(tfa, 1); + if (err) + return err; + + /* Wait until we are in PLL powerdown */ + do { + err = tfa98xx_dsp_system_stable(tfa, &ready); + if (!ready) + break; + else + msleep_interruptible(10); /* wait 10ms to avoid busload */ + tries++; + } while (tries <= 100); + + if (tries > 100) { + pr_debug("Wait for PLL powerdown timed out!\n"); + return Tfa98xx_Error_StateTimedOut; + } + } else { + pr_debug("No need to go to powerdown now \n"); + } + } + + /* set all bitfield settings */ + /* First set all default settings */ + if (tfa->verbose) { + pr_debug("---------- default settings profile: %s (%d) ---------- \n", + tfaContGetString(tfa->cnt, &previous_prof->name), tfa_dev_get_swprof(tfa)); + } + + err = show_current_state(tfa); + + /* Loop profile length */ + for (i = 0; i < previous_prof->length; i++) { + /* Search for the default section */ + if (i == 0) { + while (previous_prof->list[i].type != dscDefault && i < previous_prof->length) { + i++; + } + i++; + } + + /* Only if we found the default section try writing the items */ + if (i < previous_prof->length) { + if (tfaContWriteItem(tfa, &previous_prof->list[i]) != Tfa98xx_Error_Ok) + return Tfa98xx_Error_Bad_Parameter; + } + } + + if (tfa->verbose) + pr_debug("---------- new settings profile: %s (%d) ---------- \n", + tfaContGetString(tfa->cnt, &prof->name), prof_idx); + + /* set new settings */ + for (i = 0; i < prof->length; i++) { + /* Remember where we currently are with writing items*/ + j = i; + + /* We only want to write the values before the default section when we switch profile */ + /* process and write all non-file items */ + switch (prof->list[i].type) { + case dscFile: + case dscPatch: + case dscSetInputSelect: + case dscSetOutputSelect: + case dscSetProgramConfig: + case dscSetLagW: + case dscSetGains: + case dscSetvBatFactors: + case dscSetSensesCal: + case dscSetSensesDelay: + case dscSetMBDrc: + case dscSetFwkUseCase: + case dscSetVddpConfig: + case dscCmd: + case dscFilter: + case dscDefault: + /* When one of these files are found, we exit */ + i = prof->length; + break; + default: + err = tfaContWriteItem(tfa, &prof->list[i]); + if (err != Tfa98xx_Error_Ok) + return Tfa98xx_Error_Bad_Parameter; + break; + } + } + + if (prof->group != previous_prof->group || prof->group == 0) { + if (tfa->tfa_family == 2) + TFA_SET_BF_VOLATILE(tfa, MANSCONF, 1); + + /* Leave powerdown state */ + err = tfa_cf_powerup(tfa); + if (err) + return err; + + err = show_current_state(tfa); + + if (tfa->tfa_family == 2) { + /* Reset SBSL to 0 (workaround of enbl_powerswitch=0) */ + TFA_SET_BF_VOLATILE(tfa, SBSL, 0); + /* Sending commands to DSP we need to make sure RST is 0 (otherwise we get no response)*/ + TFA_SET_BF(tfa, RST, 0); + } + } + + /* Check if there are sample rate changes */ + err = get_sample_rate_info(tfa, prof, previous_prof, fs_previous_profile); + if (err) + return err; + + + /* Write files from previous profile (default section) + * Should only be used for the patch&trap patch (file) + */ + if (tfa->ext_dsp != 0) { + if (tfa->tfa_family == 2) { + for (i = 0; i < previous_prof->length; i++) { + /* Search for the default section */ + if (i == 0) { + while (previous_prof->list[i].type != dscDefault && i < previous_prof->length) { + i++; + } + i++; + } + + /* Only if we found the default section try writing the file */ + if (i < previous_prof->length) { + if (previous_prof->list[i].type == dscFile || previous_prof->list[i].type == dscPatch) { + /* Only write this once */ + if (tfa->verbose && k == 0) { + pr_debug("---------- files default profile: %s (%d) ---------- \n", + tfaContGetString(tfa->cnt, &previous_prof->name), prof_idx); + k++; + } + file = (nxpTfaFileDsc_t *)(previous_prof->list[i].offset + (uint8_t *)tfa->cnt); + err = tfaContWriteFile(tfa, file, vstep_idx, TFA_MAX_VSTEP_MSG_MARKER); + } + } + } + } + + if (tfa->verbose) { + pr_debug("---------- files new profile: %s (%d) ---------- \n", + tfaContGetString(tfa->cnt, &prof->name), prof_idx); + } + } + + /* write everything until end or the default section starts + * Start where we currenly left */ + for (i = j; i < prof->length; i++) { + /* We only want to write the values before the default section when we switch profile */ + + if (prof->list[i].type == dscDefault) { + break; + } + + switch (prof->list[i].type) { + case dscFile: + case dscPatch: + /* For tiberius stereo 1 device does not have a dsp! */ + if (tfa->ext_dsp != 0) { + file = (nxpTfaFileDsc_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + err = tfaContWriteFile(tfa, file, vstep_idx, TFA_MAX_VSTEP_MSG_MARKER); + } + break; + case dscSetInputSelect: + case dscSetOutputSelect: + case dscSetProgramConfig: + case dscSetLagW: + case dscSetGains: + case dscSetvBatFactors: + case dscSetSensesCal: + case dscSetSensesDelay: + case dscSetMBDrc: + case dscSetFwkUseCase: + case dscSetVddpConfig: + /* For tiberius stereo 1 device does not have a dsp! */ + if (tfa->ext_dsp != 0) { + create_dsp_buffer_msg(tfa, (nxpTfaMsg_t *) + (prof->list[i].offset + (char *)tfa->cnt), buffer, &size); + err = dsp_msg(tfa, size, buffer); + + if (tfa->verbose) { + pr_debug("command: %s=0x%02x%02x%02x \n", + tfaContGetCommandString(prof->list[i].type), + (unsigned char)buffer[0], (unsigned char)buffer[1], (unsigned char)buffer[2]); + } + } + break; + case dscCmd: + /* For tiberius stereo 1 device does not have a dsp! */ + if (tfa->ext_dsp != 0) { + size = *(uint16_t *)(prof->list[i].offset + (char *)tfa->cnt); + err = dsp_msg(tfa, size, prof->list[i].offset + 2 + (char *)tfa->cnt); + if (tfa->verbose) { + const char *cmd_id = prof->list[i].offset + 2 + (char *)tfa->cnt; + pr_debug("Writing cmd=0x%02x%02x%02x \n", (uint8_t)cmd_id[0], (uint8_t)cmd_id[1], (uint8_t)cmd_id[2]); + } + } + break; + default: + /* This allows us to write bitfield, registers or xmem after files */ + if (tfaContWriteItem(tfa, &prof->list[i]) != Tfa98xx_Error_Ok) { + return Tfa98xx_Error_Bad_Parameter; + } + break; + } + + if (err != Tfa98xx_Error_Ok) { + return err; + } + } + + if ((prof->group != previous_prof->group || prof->group == 0) && (tfa->tfa_family == 2)) { + if (TFA_GET_BF(tfa, REFCKSEL) == 0) { + /* set SBSL to go to operation mode */ + TFA_SET_BF_VOLATILE(tfa, SBSL, 1); + } + } + + return err; +} + +/* + * process only vstep in the profilelist + * + */ +enum Tfa98xx_Error tfaContWriteFilesVstep(struct tfa_device *tfa, int prof_idx, int vstep_idx) +{ + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + unsigned int i; + nxpTfaFileDsc_t *file; + nxpTfaHeader_t *hdr; + nxpTfaHeaderType_t type; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if (!prof) + return Tfa98xx_Error_Bad_Parameter; + + if (tfa->verbose) + tfa98xx_trace_printk("device:%s profile:%s vstep:%d\n", tfaContDeviceName(tfa->cnt, tfa->dev_idx), + tfaContProfileName(tfa->cnt, tfa->dev_idx, prof_idx), vstep_idx); + + /* write vstep file only! */ + for (i = 0; i < prof->length; i++) { + if (prof->list[i].type == dscFile) { + file = (nxpTfaFileDsc_t *)(prof->list[i].offset + (uint8_t *)tfa->cnt); + hdr = (nxpTfaHeader_t *)file->data; + type = (nxpTfaHeaderType_t)hdr->id; + + switch (type) { + case volstepHdr: + if (tfaContWriteFile(tfa, file, vstep_idx, TFA_MAX_VSTEP_MSG_MARKER)) + return Tfa98xx_Error_Bad_Parameter; + break; + default: + break; + } + } + } + + return err; +} + +char *tfaContGetString(nxpTfaContainer_t *cnt, nxpTfaDescPtr_t *dsc) +{ + if (dsc->type != dscString) + return "Undefined string"; + + return dsc->offset + (char *)cnt; +} + +char *tfaContGetCommandString(uint32_t type) +{ + if (type == dscSetInputSelect) + return "SetInputSelector"; + else if (type == dscSetOutputSelect) + return "SetOutputSelector"; + else if (type == dscSetProgramConfig) + return "SetProgramConfig"; + else if (type == dscSetLagW) + return "SetLagW"; + else if (type == dscSetGains) + return "SetGains"; + else if (type == dscSetvBatFactors) + return "SetvBatFactors"; + else if (type == dscSetSensesCal) + return "SetSensesCal"; + else if (type == dscSetSensesDelay) + return "SetSensesDelay"; + else if (type == dscSetMBDrc) + return "SetMBDrc"; + else if (type == dscSetFwkUseCase) + return "SetFwkUseCase"; + else if (type == dscSetVddpConfig) + return "SetVddpConfig"; + else if (type == dscFilter) + return "filter"; + else + return "Undefined string"; +} + +/* + * Get the name of the device at a certain index in the container file + * return device name + */ +char *tfaContDeviceName(nxpTfaContainer_t *cnt, int dev_idx) +{ + nxpTfaDeviceList_t *dev; + + dev = tfaContDevice(cnt, dev_idx); + if (dev == NULL) + return "!ERROR!"; + + return tfaContGetString(cnt, &dev->name); +} + +/* + * Get the application name from the container file application field + * note that the input stringbuffer should be sizeof(application field)+1 + * + */ +int tfa_cnt_get_app_name(struct tfa_device *tfa, char *name) +{ + unsigned int i; + int len = 0; + + for (i = 0; i < sizeof(tfa->cnt->application); i++) { + if (isalnum(tfa->cnt->application[i])) /* copy char if valid */ + name[len++] = tfa->cnt->application[i]; + if (tfa->cnt->application[i] == '\0') + break; + } + name[len++] = '\0'; + + return len; +} + +/* + * Get profile index of the calibration profile. + * Returns: (profile index) if found, (-2) if no + * calibration profile is found or (-1) on error + */ +int tfaContGetCalProfile(struct tfa_device *tfa) +{ + int prof, cal_idx = -2; + + if ((tfa->dev_idx < 0) || (tfa->dev_idx >= tfa->cnt->ndev)) + return ERR; + + /* search for the calibration profile in the list of profiles */ + for (prof = 0; prof < tfa->cnt->nprof; prof++) { + if (strstr(tfaContProfileName(tfa->cnt, + tfa->dev_idx, prof), ".cal") != NULL) { + cal_idx = prof; + pr_debug("Using calibration profile: '%s'\n", + tfaContProfileName(tfa->cnt, tfa->dev_idx, prof)); + break; + } + } + + return cal_idx; +} + +/** + * Is the profile a tap profile + */ +int tfaContIsTapProfile(struct tfa_device *tfa, int prof_idx) +{ + if ((tfa->dev_idx < 0) || (tfa->dev_idx >= tfa->cnt->ndev)) + return ERR; + + /* Check if next profile is tap profile */ + if (strstr(tfaContProfileName(tfa->cnt, + tfa->dev_idx, prof_idx), ".tap") != NULL) { + pr_debug("Using Tap profile: '%s'\n", + tfaContProfileName(tfa->cnt, tfa->dev_idx, prof_idx)); + return 1; + } + + return 0; +} + +/* + * Get the name of the profile at certain index for a device in the container + * file return profile name + */ +char *tfaContProfileName(nxpTfaContainer_t *cnt, int dev_idx, int prof_idx) +{ + nxpTfaProfileList_t *prof = NULL; + + /* the Nth profiles for this device */ + prof = tfaContGetDevProfList(cnt, dev_idx, prof_idx); + + /* If the index is out of bound */ + if (prof == NULL) + return "NONE"; + + return tfaContGetString(cnt, &prof->name); +} + +/* + * return 1st profile list + */ +nxpTfaProfileList_t *tfaContGet1stProfList(nxpTfaContainer_t *cont) +{ + nxpTfaProfileList_t *prof; + uint8_t *b = (uint8_t *)cont; + + int maxdev = 0; + nxpTfaDeviceList_t *dev; + + // get nr of devlists + maxdev = cont->ndev; + // get last devlist + dev = tfaContGetDevList(cont, maxdev - 1); + if (dev == NULL) + return NULL; + // the 1st profile starts after the last device list + b = (uint8_t *)dev + sizeof(nxpTfaDeviceList_t) + + dev->length * (sizeof(nxpTfaDescPtr_t)); + prof = (nxpTfaProfileList_t *)b; + return prof; +} + +/* + * return 1st livedata list + */ +nxpTfaLiveDataList_t *tfaContGet1stLiveDataList(nxpTfaContainer_t *cont) +{ + nxpTfaLiveDataList_t *ldata; + nxpTfaProfileList_t *prof; + nxpTfaDeviceList_t *dev; + uint8_t *b = (uint8_t *)cont; + int maxdev, maxprof; + + // get nr of devlists+1 + maxdev = cont->ndev; + // get nr of proflists + maxprof = cont->nprof; + + // get last devlist + dev = tfaContGetDevList(cont, maxdev - 1); + // the 1st livedata starts after the last device list + b = (uint8_t *)dev + sizeof(nxpTfaDeviceList_t) + + dev->length * (sizeof(nxpTfaDescPtr_t)); + + while (maxprof != 0) { + // get last proflist + prof = (nxpTfaProfileList_t *)b; + b += sizeof(nxpTfaProfileList_t) + + ((prof->length - 1) * (sizeof(nxpTfaDescPtr_t))); + maxprof--; + } + + /* Else the marker falls off */ + b += 4; //bytes + + ldata = (nxpTfaLiveDataList_t *)b; + return ldata; +} + +/* + * return the device list pointer + */ +nxpTfaDeviceList_t *tfaContDevice(nxpTfaContainer_t *cnt, int dev_idx) +{ + return tfaContGetDevList(cnt, dev_idx); +} + +/* + * return the next profile: + * - assume that all profiles are adjacent + * - calculate the total length of the input + * - the input profile + its length is the next profile + */ +nxpTfaProfileList_t *tfaContNextProfile(nxpTfaProfileList_t *prof) +{ + uint8_t *this, *next; /* byte pointers for byte pointer arithmetic */ + nxpTfaProfileList_t *nextprof; + int listlength; /* total length of list in bytes */ + + if (prof == NULL) + return NULL; + + if (prof->ID != TFA_PROFID) + return NULL; /* invalid input */ + + this = (uint8_t *)prof; + /* nr of items in the list, length includes name dsc so - 1*/ + listlength = (prof->length - 1) * sizeof(nxpTfaDescPtr_t); + /* the sizeof(nxpTfaProfileList_t) includes the list[0] length */ + next = this + listlength + + sizeof(nxpTfaProfileList_t);// - sizeof(nxpTfaDescPtr_t); + nextprof = (nxpTfaProfileList_t *)next; + + if (nextprof->ID != TFA_PROFID) + return NULL; + + return nextprof; +} + +/* + * return the next livedata + */ +nxpTfaLiveDataList_t *tfaContNextLiveData(nxpTfaLiveDataList_t *livedata) +{ + nxpTfaLiveDataList_t *nextlivedata = (nxpTfaLiveDataList_t *) + ((char *)livedata + (livedata->length * 4) + + sizeof(nxpTfaLiveDataList_t) - 4); + + if (nextlivedata->ID == TFA_LIVEDATAID) + return nextlivedata; + + return NULL; +} + +/* + * check CRC for container + * CRC is calculated over the bytes following the CRC field + * + * return non zero value on error + */ +int tfaContCrcCheckContainer(nxpTfaContainer_t *cont) +{ + uint8_t *base; + size_t size; + uint32_t crc; + // ptr to bytes following the CRC field + base = (uint8_t *)&cont->CRC + 4; + // nr of bytes following the CRC field + size = (size_t)(cont->size - (base - (uint8_t *)cont)); + crc = ~crc32_le(~0u, base, size); + + return crc != cont->CRC; +} + +static void get_all_features_from_cnt(struct tfa_device *tfa, + int *hw_feature_register, int sw_feature_register[2]) +{ + nxpTfaFeatures_t *features; + int i; + + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + + /* Init values in case no keyword is defined in cnt file: */ + *hw_feature_register = -1; + sw_feature_register[0] = -1; + sw_feature_register[1] = -1; + + if (dev == NULL) + return; + + // process the device list + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscFeatures) { + features = (nxpTfaFeatures_t *)(dev->list[i].offset + + (uint8_t *)tfa->cnt); + *hw_feature_register = features->value[0]; + sw_feature_register[0] = features->value[1]; + sw_feature_register[1] = features->value[2]; + break; + } + } +} + +/* wrapper function */ +void get_hw_features_from_cnt(struct tfa_device *tfa, int *hw_feature_register) +{ + int sw_feature_register[2]; + get_all_features_from_cnt(tfa, hw_feature_register, sw_feature_register); +} + +/* wrapper function */ +void get_sw_features_from_cnt(struct tfa_device *tfa, + int sw_feature_register[2]) +{ + int hw_feature_register; + get_all_features_from_cnt(tfa, &hw_feature_register, sw_feature_register); +} + +enum Tfa98xx_Error tfa98xx_factory_trimmer(struct tfa_device *tfa) +{ + return (tfa->dev_ops.factory_trimmer)(tfa); +} + +enum Tfa98xx_Error tfa_set_filters(struct tfa_device *tfa, int prof_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, + tfa->dev_idx, prof_idx); + unsigned int i; + + if (!prof) + return Tfa98xx_Error_Bad_Parameter; + + /* If we are in powerdown there is no need to set filters */ + if (TFA_GET_BF(tfa, PWDN) == 1) + return Tfa98xx_Error_Ok; + + /* loop the profile to find filter settings */ + for (i = 0; i < prof->length; i++) { + /* We only want to write the values before the default section */ + if (prof->list[i].type == dscDefault) + break; + + /* write all filter settings */ + if (prof->list[i].type == dscFilter) { + if (tfaContWriteItem(tfa, &prof->list[i]) != Tfa98xx_Error_Ok) + return err; + } + } + + return err; +} + +int tfa_tib_dsp_msgmulti(struct tfa_device *tfa, int length, + const char *buffer) +{ + uint8_t *buf = (uint8_t *)buffer; + static uint8_t *blob = NULL, *blobptr; /* TODO: not multi-thread safe */ + static int total; /* TODO: not multi-thread safe */ + int post_len = 0; + + /* checks for 24b_BE or 32_LE */ + int len_word_in_bytes = (tfa->convert_dsp32) ? 4 : 3; + /* + * TODO: get rid of these magic constants max size should depend + * on the tfa device type + */ + int tfadsp_max_msg_size = (tfa->convert_dsp32) ? 5336 : 4000; + + /* No data found*/ + if (length == -1 && blob == NULL) { + return ERR; + } + + if (length == -1) { + int i; + /* set last length field to zero */ + for (i = total; i < (total + len_word_in_bytes); i++) { + blob[i] = 0; + } + total += len_word_in_bytes; + memcpy(buf, blob, total); + + kfree(blob); + /* Set to NULL pointer, otherwise no new malloc is done! */ + blob = NULL; + return total; + } + + if (blob == NULL) { + if (tfa->verbose) + pr_debug("%s, Creating the multi-message \n\n", __FUNCTION__); + + blob = kmalloc(tfadsp_max_msg_size, GFP_KERNEL); + /* add command ID for multi-msg = 0x008015 */ + if (tfa->convert_dsp32) { + blob[0] = 0x15; + blob[1] = 0x80; + blob[2] = 0x0; + blob[3] = 0x0; + } else { + blob[0] = 0x0; + blob[1] = 0x80; + blob[2] = 0x15; + } + blobptr = blob; + blobptr += len_word_in_bytes; + total = len_word_in_bytes; + } + + if (tfa->verbose) { + pr_debug("%s, id:0x%02x%02x%02x, length:%d \n", __FUNCTION__, + buf[0], buf[1], buf[2], length); + } + + /* check total message size after concatination */ + post_len = total + length + (2 * len_word_in_bytes); + if (post_len > tfadsp_max_msg_size) { + /* pr_debug("New multi-message too large! (%d >= %d (max.)), + current length: %d\n", post_len, tfadsp_max_msg_size, total); */ + return Tfa98xx_Error_Buffer_too_small; + } + + /* add length field (length in words) to the multi message */ + if (tfa->convert_dsp32) { + *blobptr++ = (uint8_t)((length / len_word_in_bytes) & 0xff); /* lsb */ + *blobptr++ = (uint8_t)(((length / len_word_in_bytes) & 0xff00) >> 8); /* msb */ + *blobptr++ = 0x0; + *blobptr++ = 0x0; + } else { + *blobptr++ = 0x0; + /* msb */ + *blobptr++ = (uint8_t)(((length / len_word_in_bytes) & 0xff00) >> 8); + /* lsb */ + *blobptr++ = (uint8_t)((length / len_word_in_bytes) & 0xff); + } + memcpy(blobptr, buf, length); + blobptr += length; + total += (length + len_word_in_bytes); + + /* SetRe25 message is always the last message of the multi-msg */ + if (tfa->convert_dsp32) { + if (buf[1] == 0x81 && buf[0] == SB_PARAM_SET_RE25C) + return 1; /* 1 means last message is done! */ + } else { + if (buf[1] == 0x81 && buf[2] == SB_PARAM_SET_RE25C) + return 1; /* 1 means last message is done! */ + } + + return 0; +} diff --git a/sound/soc/codecs/tfa_container.h b/sound/soc/codecs/tfa_container.h new file mode 100644 index 000000000000..bc2286548d48 --- /dev/null +++ b/sound/soc/codecs/tfa_container.h @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFACONTAINER_H_ +#define TFACONTAINER_H_ + +/* static limits */ +#define TFACONT_MAXDEVS (4) /* maximum nr of devices */ +#define TFACONT_MAXPROFS (16) /* maximum nr of profiles */ + +#include "tfa98xx_parameters.h" + +/** +* Pass the container buffer, initialize and allocate internal memory. +* +* @param cnt pointer to the start of the buffer holding the container file +* @param length of the data in bytes +* @return +* - tfa_error_ok if normal +* - tfa_error_container invalid container data +* - tfa_error_bad_param invalid parameter +* +*/ +enum tfa_error tfa_load_cnt(void *cnt, int length); + +/** + * Return the descriptor string + * @param cnt pointer to the container struct + * @param dsc pointer to nxpTfa descriptor + * @return descriptor string + */ +char *tfaContGetString(nxpTfaContainer_t *cnt, nxpTfaDescPtr_t *dsc); + +/** + * Gets the string for the given command type number + * @param type number representing a command + * @return string of a command + */ +char *tfaContGetCommandString(uint32_t type); + +/** + * get the device type from the patch in this devicelist + * - find the patch file for this devidx + * - return the devid from the patch or 0 if not found + * @param cnt pointer to container file + * @param dev_idx device index + * @return descriptor string + */ +int tfa_cnt_get_devid(nxpTfaContainer_t *cnt, int dev_idx); + +/** + * Get the slave for the device if it exists. + * @param tfa the device struct pointer + * @param slave_addr the index of the device + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContGetSlave(struct tfa_device *tfa, uint8_t *slave_addr); + +void tfaContSetSlave(uint8_t slave_addr); + +/** + * Get the index for a skave address. + * @param tfa the device struct pointer + * @return the device index + */ +int tfa_cont_get_idx(struct tfa_device *tfa); + +/** + * Write reg and bitfield items in the devicelist to the target. + * @param tfa the device struct pointer + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteRegsDev(struct tfa_device *tfa); + +/** + * Write reg and bitfield items in the profilelist to the target. + * @param tfa the device struct pointer + * @param prof_idx the profile index + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteRegsProf(struct tfa_device *tfa, int prof_idx); + +/** + * Write a patchfile in the devicelist to the target. + * @param tfa the device struct pointer + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWritePatch(struct tfa_device *tfa); + +/** + * Write all param files in the devicelist to the target. + * @param tfa the device struct pointer + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteFiles(struct tfa_device *tfa); + +/** + * Get sample rate from passed profile index + * @param tfa the device struct pointer + * @param prof_idx the index of the profile + * @return sample rate value + */ +unsigned int tfa98xx_get_profile_sr(struct tfa_device *tfa, unsigned int prof_idx); + +/** + * Get the device name string + * @param cnt the pointer to the container struct + * @param dev_idx the index of the device + * @return device name string or error string if not found + */ +char *tfaContDeviceName(nxpTfaContainer_t *cnt, int dev_idx); + +/** + * Get the application name from the container file application field + * @param tfa the device struct pointer + * @param name the input stringbuffer with size: sizeof(application field)+1 + * @return actual string length + */ +int tfa_cnt_get_app_name(struct tfa_device *tfa, char *name); + +/** + * Get profile index of the calibration profile + * @param tfa the device struct pointer + * @return profile index, -2 if no calibration profile is found or -1 on error + */ +int tfaContGetCalProfile(struct tfa_device *tfa); + +/** + * Is the profile a tap profile ? + * @param tfa the device struct pointer + * @param prof_idx the index of the profile + * @return 1 if the profile is a tap profile or 0 if not + */ +int tfaContIsTapProfile(struct tfa_device *tfa, int prof_idx); + +/** + * Get the name of the profile at certain index for a device in the container file + * @param cnt the pointer to the container struct + * @param dev_idx the index of the device + * @param prof_idx the index of the profile + * @return profile name string or error string if not found + */ +char *tfaContProfileName(nxpTfaContainer_t *cnt, int dev_idx, int prof_idx); + +/** + * Process all items in the profilelist + * NOTE an error return during processing will leave the device muted + * @param tfa the device struct pointer + * @param prof_idx index of the profile + * @param vstep_idx index of the vstep + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteProfile(struct tfa_device *tfa, int prof_idx, int vstep_idx); + +/** + * Specify the speaker configurations (cmd id) (Left, right, both, none) + * @param dev_idx index of the device + * @param configuration name string of the configuration + */ +void tfa98xx_set_spkr_select(int dev_idx, char *configuration); + +enum Tfa98xx_Error tfa_cont_write_filterbank(struct tfa_device *tfa, nxpTfaFilter_t *filter); + +/** + * Write all param files in the profilelist to the target + * this is used during startup when maybe ACS is set + * @param tfa the device struct pointer + * @param prof_idx the index of the profile + * @param vstep_idx the index of the vstep + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteFilesProf(struct tfa_device *tfa, int prof_idx, int vstep_idx); +enum Tfa98xx_Error tfaContWriteFilesVstep(struct tfa_device *tfa, int prof_idx, int vstep_idx); +enum Tfa98xx_Error tfaContWriteDrcFile(struct tfa_device *tfa, int size, uint8_t data[]); + +/** + * Get the device list dsc from the tfaContainer + * @param cont pointer to the tfaContainer + * @param dev_idx the index of the device + * @return device list pointer + */ +nxpTfaDeviceList_t *tfaContGetDevList(nxpTfaContainer_t *cont, int dev_idx); + +/** + * Get the Nth profile for the Nth device + * @param cont pointer to the tfaContainer + * @param dev_idx the index of the device + * @param prof_idx the index of the profile + * @return profile list pointer + */ +nxpTfaProfileList_t *tfaContGetDevProfList(nxpTfaContainer_t *cont, int dev_idx, int prof_idx); + +/** + * Get the number of profiles for device from contaienr + * @param cont pointer to the tfaContainer + * @param dev_idx the index of the device + * @return device list pointer + */ +int tfa_cnt_get_dev_nprof(struct tfa_device *tfa); + + +/** + * Get the Nth livedata for the Nth device + * @param cont pointer to the tfaContainer + * @param dev_idx the index of the device + * @param livedata_idx the index of the livedata + * @return livedata list pointer + */ +nxpTfaLiveDataList_t *tfaContGetDevLiveDataList(nxpTfaContainer_t *cont, int dev_idx, int livedata_idx); + +/** + * Check CRC for container + * @param cont pointer to the tfaContainer + * @return error value 0 on error + */ +int tfaContCrcCheckContainer(nxpTfaContainer_t *cont); + +/** + * Get the device list pointer + * @param cnt pointer to the container struct + * @param dev_idx the index of the device + * @return pointer to device list + */ +nxpTfaDeviceList_t *tfaContDevice(nxpTfaContainer_t *cnt, int dev_idx); + +/** + * Return the pointer to the first profile in a list from the tfaContainer + * @param cont pointer to the tfaContainer + * @return pointer to first profile in profile list + */ +nxpTfaProfileList_t *tfaContGet1stProfList(nxpTfaContainer_t *cont); + +/** + * Return the pointer to the next profile in a list + * @param prof is the pointer to the profile list + * @return profile list pointer + */ +nxpTfaProfileList_t *tfaContNextProfile(nxpTfaProfileList_t *prof); + +/** + * Return the pointer to the first livedata in a list from the tfaContainer + * @param cont pointer to the tfaContainer + * @return pointer to first livedata in profile list + */ +nxpTfaLiveDataList_t *tfaContGet1stLiveDataList(nxpTfaContainer_t *cont); + +/** + * Return the pointer to the next livedata in a list + * @param livedata_idx is the pointer to the livedata list + * @return livedata list pointer + */ +nxpTfaLiveDataList_t *tfaContNextLiveData(nxpTfaLiveDataList_t *livedata_idx); + +/** + * Write a bit field + * @param tfa the device struct pointer + * @param bf bitfield to write + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaRunWriteBitfield(struct tfa_device *tfa, nxpTfaBitfield_t bf); + +/** + * Write a parameter file to the device + * @param tfa the device struct pointer + * @param file filedescriptor pointer + * @param vstep_idx index to vstep + * @param vstep_msg_idx index to vstep message + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteFile(struct tfa_device *tfa, nxpTfaFileDsc_t *file, int vstep_idx, int vstep_msg_idx); + +/** + * Get the max volume step associated with Nth profile for the Nth device + * @param tfa the device struct pointer + * @param prof_idx profile index + * @return the number of vsteps + */ +int tfacont_get_max_vstep(struct tfa_device *tfa, int prof_idx); + +/** + * Get the file contents associated with the device or profile + * Search within the device tree, if not found, search within the profile + * tree. There can only be one type of file within profile or device. + * @param tfa the device struct pointer + * @param prof_idx I2C profile index in the device + * @param type file type + * @return 0 NULL if file type is not found + * @return 1 file contents + */ +nxpTfaFileDsc_t *tfacont_getfiledata(struct tfa_device *tfa, int prof_idx, enum nxpTfaHeaderType type); + +/** + * Dump the contents of the file header + * @param hdr pointer to file header data + */ +void tfaContShowHeader(nxpTfaHeader_t *hdr); + +/** + * Read a bit field + * @param tfa the device struct pointer + * @param bf bitfield to read out + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaRunReadBitfield(struct tfa_device *tfa, nxpTfaBitfield_t *bf); + +/** + * Get hw feature bits from container file + * @param tfa the device struct pointer + * @param hw_feature_register pointer to where hw features are stored + */ +void get_hw_features_from_cnt(struct tfa_device *tfa, int *hw_feature_register); + +/** + * Get sw feature bits from container file + * @param tfa the device struct pointer + * @param sw_feature_register pointer to where sw features are stored + */ +void get_sw_features_from_cnt(struct tfa_device *tfa, int sw_feature_register[2]); + +/** + * Factory trimming for the Boost converter + * check if there is a correction needed + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfa98xx_factory_trimmer(struct tfa_device *tfa); + +/** + * Search for filters settings and if found then write them to the device + * @param tfa the device struct pointer + * @param prof_idx profile to look in + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfa_set_filters(struct tfa_device *tfa, int prof_idx); + +/** + * Get the firmware version from the patch in the container file + * @param tfa the device struct pointer + * @return firmware version + */ +int tfa_cnt_get_patch_version(struct tfa_device *tfa); + +int tfa_tib_dsp_msgmulti(struct tfa_device *tfa, int length, const char *buffer); + +#endif /* TFACONTAINER_H_ */ diff --git a/sound/soc/codecs/tfa_device.h b/sound/soc/codecs/tfa_device.h new file mode 100644 index 000000000000..18151d4142da --- /dev/null +++ b/sound/soc/codecs/tfa_device.h @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +/**\file + * + * The tfa_device interface controls a single I2C device instance by + * referencing to the device specific context provided by means of the + * tfa_device structure pointer. + * Multiple instances of tfa_device structures will be created and maintained + * by the caller. + * + * The API is functionally grouped as: + * - tfa_dev basic codec interface to probe, start/stop and control the device + * - state access to internal MTP storage + * - abstraction for interrupt bits and handling + * - container reading support + */ +#ifndef __TFA_DEVICE_H__ +#define __TFA_DEVICE_H__ + +#include "config.h" + +struct tfa_device; + +/* + * hw/sw feature bit settings in MTP + */ +enum featureSupport { + supportNotSet, /**< default means not set yet */ + supportNo, /**< no support */ + supportYes /**< supported */ +}; +/* + * supported Digital Audio Interfaces bitmap + */ +enum Tfa98xx_DAI { + Tfa98xx_DAI_I2S = 0x01, /**< I2S only */ + Tfa98xx_DAI_TDM = 0x02, /**< TDM, I2S */ + Tfa98xx_DAI_PDM = 0x04, /**< PDM */ +}; + +/* + * device ops function structure + */ +struct tfa_device_ops { + enum Tfa98xx_Error(*dsp_msg)(struct tfa_device *tfa, int length, + const char *buf); + enum Tfa98xx_Error(*dsp_msg_read)(struct tfa_device *tfa, int length, + unsigned char *bytes); + enum Tfa98xx_Error(*reg_read)(struct tfa_device *tfa, + unsigned char subaddress, unsigned short *value); + enum Tfa98xx_Error(*reg_write)(struct tfa_device *tfa, + unsigned char subaddress, unsigned short value); + enum Tfa98xx_Error(*mem_read)(struct tfa_device *tfa, + unsigned int start_offset, int num_words, int *pValues); + enum Tfa98xx_Error(*mem_write)(struct tfa_device *tfa, + unsigned short address, int value, int memtype); + + enum Tfa98xx_Error (*tfa_init)(struct tfa_device *tfa); /**< init typically for loading optimal settings */ + enum Tfa98xx_Error (*dsp_reset)(struct tfa_device *tfa, int state); /**< reset the coolflux dsp */ + enum Tfa98xx_Error (*dsp_system_stable)(struct tfa_device *tfa, int *ready); /**< ready when clocks are stable to allow DSP subsystem access */ + enum Tfa98xx_Error (*dsp_write_tables)(struct tfa_device *tfa, int sample_rate); /**< write the device/type specific delaytables */ + enum Tfa98xx_Error (*auto_copy_mtp_to_iic)(struct tfa_device *tfa); /**< Set auto_copy_mtp_to_iic */ + enum Tfa98xx_Error (*factory_trimmer)(struct tfa_device *tfa); /**< Factory trimming for the Boost converter */ + int (*set_swprof)(struct tfa_device *tfa, unsigned short new_value); /**< Set the sw profile in the struct and the hw register */ + int (*get_swprof)(struct tfa_device *tfa); /**< Get the sw profile from the hw register */ + int(*set_swvstep)(struct tfa_device *tfa, unsigned short new_value); /**< Set the sw vstep in the struct and the hw register */ + int(*get_swvstep)(struct tfa_device *tfa); /**< Get the sw vstep from the hw register */ + int(*get_mtpb)(struct tfa_device *tfa); /**< get status of MTB busy bit*/ + enum Tfa98xx_Error (*set_mute)(struct tfa_device *tfa, int mute); /**< set mute */ + enum Tfa98xx_Error (*faim_protect)(struct tfa_device *tfa, int state); /**< Protect FAIM from being corrupted */ + enum Tfa98xx_Error(*set_osc_powerdown)(struct tfa_device *tfa, int state); /**< Allow to change internal osc. gating settings */ + enum Tfa98xx_Error(*update_lpm)(struct tfa_device *tfa, int state); /**< Allow to change lowpowermode settings */ +}; + +/** + * Device states and modifier flags to allow a device/type independent fine + * grained control of the internal state.\n + * Values below 0x10 are referred to as base states which can be or-ed with + * state modifiers, from 0x10 and higher. + * + */ +enum tfa_state { + TFA_STATE_UNKNOWN, /**< unknown or invalid */ + TFA_STATE_POWERDOWN, /**< PLL in powerdown, Algo is up/warm */ + TFA_STATE_INIT_HW, /**< load I2C/PLL hardware setting (~wait2srcsettings) */ + TFA_STATE_INIT_CF, /**< coolflux HW access possible (~initcf) */ + TFA_STATE_INIT_FW, /**< DSP framework active (~patch loaded) */ + TFA_STATE_OPERATING, /**< Amp and Algo running */ + TFA_STATE_FAULT, /**< An alarm or error occurred */ + TFA_STATE_RESET, /**< I2C reset and ACS set */ + /* --sticky state modifiers-- */ + TFA_STATE_MUTE = 0x10, /**< Algo & Amp mute */ + TFA_STATE_UNMUTE = 0x20, /**< Algo & Amp unmute */ + TFA_STATE_CLOCK_ALWAYS = 0x40, /**< PLL connect to internal oscillator */ + TFA_STATE_CLOCK_AUDIO = 0x80, /**< PLL connect to audio clock (BCK/FS) */ + TFA_STATE_LOW_POWER = 0x100, /**< lowest possible power state */ +}; + +/** + * This is the main tfa device context structure, it will carry all information + * that is needed to handle a single I2C device instance. + * All functions dealing with the device will need access to the fields herein. + */ +struct tfa_device { + int dev_idx; /**< device container index */ + int in_use; + int buffer_size; /**< lowest level max buffer size */ + int has_msg; /**< support direct dsp messaging */ + unsigned char slave_address; /**< I2C slave address (not shifted) */ + unsigned short rev; /**< full revid of this device */ + unsigned char tfa_family; /**< tfa1/tfa2 */ + enum featureSupport supportDrc; + enum featureSupport supportFramework; + enum featureSupport support_saam; + int sw_feature_bits[2]; /**< cached copy of sw feature bits */ + int hw_feature_bits; /**< cached copy of hw feature bits */ + int profile; /**< active profile */ + int vstep; /**< active vstep */ + unsigned char spkr_count; + unsigned char spkr_select; + unsigned char support_tcoef;/**< legacy tfa9887, will be removed */ + enum Tfa98xx_DAI daimap; /**< supported audio interface types */ + int mohm[3]; /**< speaker calibration values in milli ohms -1 is error */ + struct tfa_device_ops dev_ops; + uint16_t interrupt_enable[3]; + uint16_t interrupt_status[3]; + int ext_dsp; /**< respond to external DSP: -1:none, 0:no_dsp, 1:cold, 2:warm */ + int bus; /* TODO fix ext_dsp and bus handling */ + int tfadsp_event; /**< enum tfadsp_event_en is for external registry */ + int verbose; /**< verbosity level for debug print output */ + enum tfa_state state; /**< last known state or-ed with optional state_modifier */ + struct nxpTfaContainer *cnt;/**< the loaded container file */ + struct nxpTfaVolumeStepRegisterInfo *p_regInfo; /**< remember vstep for partial updates */ + int partial_enable; /**< enable partial updates */ + void *data; /**< typically pointing to Linux driver structure owning this device */ + int convert_dsp32; /**< convert 24 bit DSP messages to 32 bit */ + int sync_iv_delay; /**< synchronize I/V delay at cold start */ + int is_probus_device; /**< probus device: device without internal DSP */ + int advance_keys_handling; + int needs_reset; /**< add the reset trigger for SetAlgoParams and SetMBDrc commands */ + struct kmem_cache *cachep; /**< Memory allocator handle */ + char fw_itf_ver[4]; /* Firmware ITF version */ +}; + +/** + * The tfa_dev_probe is called before accessing any device accessing functions. + * Access to the tfa device register 3 is attempted and will record the + * returned id for further use. If no device responds the function will abort. + * The recorded id will by used by the query functions to fill the remaining + * relevant data fields of the device structure. + * Data such as MTP features that requires device access will only be read when + * explicitly called and the result will be then cached in the struct. + * + * A structure pointer passed to this device needs to refer to existing memory + * space allocated by the caller. + * + * @param slave = I2C slave address of the target device (not shifted) + * @param tfa struct = points to memory that holds the context for this device + * instance + * + * @return + * - 0 if the I2C device responded to a read of register address 3\n + * when the device responds but with an unknown id a warning will be printed + * - -1 if no response from the I2C device + * + */ +int tfa_dev_probe(int slave, struct tfa_device *tfa); + +/** + * Start this instance at the profile and vstep as provided. + * The profile and vstep will be loaded first in case the current value differs + * from the requested values. + * Note that this call will not change the mute state of the tfa, which means + * that of this instance was called in muted state the caller will have to + * unmute in order to get audio. + * + * @param tfa struct = pointer to context of this device instance + * @param profile the selected profile to run + * @param vstep the selected vstep to use + * @return tfa_error enum + */ +enum tfa_error tfa_dev_start(struct tfa_device *tfa, int profile, int vstep); + + +/** + * Stop audio for this instance as gracefully as possible. + * Audio will be muted and the PLL will be shutdown together with any other + * device/type specific settings needed to prevent audio artifacts or + * workarounds. + * + * Note that this call will change state of the tfa to mute and powered down. + * + * @param tfa struct = pointer to context of this device instance + * @return tfa_error enum + */ +enum tfa_error tfa_dev_stop(struct tfa_device *tfa); + +/** + * This interface allows a device/type independent fine grained control of the + * internal state of the instance. + * Whenever a base state is requested an attempt is made to actively bring the device + * into this state. However this may depend on external conditions beyond control of + * this software layer. Therefore in case the state cannot be set an erro will + * be returned and the current state remains unchanged. + * The base states, lower values below 0x10, are all mutually exclusive, they higher ones + * can also function as a sticky modifier which means for example that operating + * state could be in either muted or unmuted state. Or in case of init_cf it can be + * internal clock (always) or external audio clock. + * This function is intended to be used for device mute/unmute synchronization + * when called from higher layers. Mostly internal calls will use this to control + * the startup and profile transitions in a device/type independent way. + * + * @param tfa struct = pointer to context of this device instance + * @param state struct = desired device state after function return + * @return tfa_error enum + */ +enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state, + int is_calibration); + +/** + * Retrieve the current state of this instance in an active way. + * The state field in tfa structure will reflect the result unless an error is + * returned. + * Note that the hardware state may change on external events an as such this + * field should be treated as volatile. + * + * @param tfa struct = pointer to context of this device instance + * @return tfa_error enum + * + */ +enum tfa_state tfa_dev_get_state(struct tfa_device *tfa); + + +/*****************************************************************************/ +/*****************************************************************************/ +/** + * MTP support functions + */ +enum tfa_mtp { + TFA_MTP_OTC, /**< */ + TFA_MTP_EX, /**< */ + TFA_MTP_RE25, /**< */ + TFA_MTP_RE25_PRIM, /**< */ + TFA_MTP_RE25_SEC, /**< */ + TFA_MTP_LOCK, /**< */ +}; + +/** + * + */ +int tfa_dev_mtp_get(struct tfa_device *tfa, enum tfa_mtp item); + +/** + * + */ +enum tfa_error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, int value); + + +//irq +/* tfa2 interrupt support + * !!! enum tfa9912_irq !!!*/ +/* + * interrupt bit function to clear + */ +int tfa_irq_clear(struct tfa_device *tfa, int bit); +/* + * return state of irq or -1 if illegal bit + */ +int tfa_irq_get(struct tfa_device *tfa, int bit); +/* + * interrupt bit function that operates on the shadow regs in the handle + */ +int tfa_irq_ena(struct tfa_device *tfa, int bit, int state); +/* + * interrupt bit function that sets the polarity + */ +int tfa_irq_set_pol(struct tfa_device *tfa, int bit, int state); + +/* + * mask interrupts by disabling them + */ +int tfa_irq_mask(struct tfa_device *tfa); +/* + * unmask interrupts by enabling them again + */ +int tfa_irq_unmask(struct tfa_device *tfa); +//cnt read +//debug? + +#endif /* __TFA_DEVICE_H__ */ + diff --git a/sound/soc/codecs/tfa_dsp.c b/sound/soc/codecs/tfa_dsp.c new file mode 100644 index 000000000000..3d02b4264192 --- /dev/null +++ b/sound/soc/codecs/tfa_dsp.c @@ -0,0 +1,4137 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#include "dbgprint.h" +#include "tfa_container.h" +#include "tfa.h" +#include "tfa98xx_tfafieldnames.h" +#include "tfa_internal.h" + + /* handle macro for bitfield */ +#define TFA_MK_BF(reg, pos, len) ((reg<<8)|(pos<<4)|(len-1)) + +/* abstract family for register */ +#define FAM_TFA98XX_CF_CONTROLS (TFA_FAM(tfa, RST) >> 8) +#define FAM_TFA98XX_CF_MEM (TFA_FAM(tfa, MEMA) >> 8) +#define FAM_TFA98XX_MTP0 (TFA_FAM(tfa, MTPOTC) >> 8) +#define FAM_TFA98xx_INT_EN (TFA_FAM(tfa, INTENVDDS) >> 8) + +#define CF_STATUS_I2C_CMD_ACK 0x01 + +/* Defines below are used for irq function (this removed the genregs include) */ +#define TFA98XX_INTERRUPT_ENABLE_REG1 0x48 +#define TFA98XX_INTERRUPT_IN_REG1 0x44 +#define TFA98XX_INTERRUPT_OUT_REG1 0x40 +#define TFA98XX_STATUS_POLARITY_REG1 0x4c +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK 0x2 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MSK 0x1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_POS 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_POS 0 +#define ERR -1 + +void tfanone_ops(struct tfa_device_ops *ops); +void tfa9872_ops(struct tfa_device_ops *ops); +void tfa9874_ops(struct tfa_device_ops *ops); +void tfa9878_ops(struct tfa_device_ops *ops); +void tfa9912_ops(struct tfa_device_ops *ops); +void tfa9888_ops(struct tfa_device_ops *ops); +void tfa9891_ops(struct tfa_device_ops *ops); +void tfa9897_ops(struct tfa_device_ops *ops); +void tfa9896_ops(struct tfa_device_ops *ops); +void tfa9890_ops(struct tfa_device_ops *ops); +void tfa9895_ops(struct tfa_device_ops *ops); +void tfa9894_ops(struct tfa_device_ops *ops); + +#ifndef MIN +#define MIN(A, B) (A < B?A:B) +#endif + +/* retry values */ +#define CFSTABLE_TRIES 10 +#define AMPOFFWAIT_TRIES 50 +#define MTPBWAIT_TRIES 50 +#define MTPEX_WAIT_NTRIES 50 + +/* calibration done executed */ +#define TFA_MTPEX_POS TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_POS /**/ + +int tfa_get_calibration_info(struct tfa_device *tfa, int channel) +{ + return tfa->mohm[channel]; +} + +/* return sign extended tap pattern */ +int tfa_get_tap_pattern(struct tfa_device *tfa) +{ + int value = tfa_get_bf(tfa, TFA9912_BF_CFTAPPAT); + int bitshift; + /* length of bitfield */ + uint8_t field_len = 1 + (TFA9912_BF_CFTAPPAT & 0x0f); + + bitshift = 8 * sizeof(int) - field_len; + /* signextend */ + value = (value << bitshift) >> bitshift; + + return value; +} +/* + * interrupt bit function to clear + */ +int tfa_irq_clear(struct tfa_device *tfa, enum tfa9912_irq bit) +{ + unsigned char reg; + + /* make bitfield enum */ + if (bit == tfa9912_irq_all) { + /* operate on all bits */ + for (reg = TFA98XX_INTERRUPT_IN_REG1; + reg < TFA98XX_INTERRUPT_IN_REG1 + 3; reg++) + reg_write(tfa, reg, 0xffff); /* all bits */ + } else if (bit < tfa9912_irq_max) { + reg = (unsigned char)(TFA98XX_INTERRUPT_IN_REG1 + (bit >> 4)); + reg_write(tfa, reg, 1 << (bit & 0x0f)); /* only this bit */ + } else + return ERR; + + return 0; +} +/* + * return state of irq or -1 if illegal bit + */ +int tfa_irq_get(struct tfa_device *tfa, enum tfa9912_irq bit) +{ + uint16_t value; + int reg, mask; + + if (bit < tfa9912_irq_max) { + /* only this bit */ + reg = TFA98XX_INTERRUPT_OUT_REG1 + (bit >> 4); + mask = 1 << (bit & 0x0f); + reg_read(tfa, (unsigned char)reg, &value); + } else + return ERR; + + return (value & mask) != 0; +} +/* + * interrupt bit function that operates on the shadow regs in the handle + */ + +int tfa_irq_ena(struct tfa_device *tfa, enum tfa9912_irq bit, int state) +{ + uint16_t value, new_value; + int reg = 0, mask; + /* */ + if (bit == tfa9912_irq_all) { + /* operate on all bits */ + for (reg = TFA98XX_INTERRUPT_ENABLE_REG1; reg <= + TFA98XX_INTERRUPT_ENABLE_REG1 + tfa9912_irq_max / 16; reg++) { + /* all bits */ + reg_write(tfa, (unsigned char)reg, state ? 0xffff : 0); + tfa->interrupt_enable[reg - TFA98XX_INTERRUPT_ENABLE_REG1] + = state ? 0xffff : 0; /* all bits */ + } + } else if (bit < tfa9912_irq_max) { + /* only this bit */ + reg = TFA98XX_INTERRUPT_ENABLE_REG1 + (bit >> 4); + mask = 1 << (bit & 0x0f); + reg_read(tfa, (unsigned char)reg, &value); + if (state) //set + new_value = (uint16_t)(value | mask); + else // clear + new_value = value & ~mask; + if (new_value != value) { + reg_write(tfa, (unsigned char)reg, new_value); /* only this bit */ + tfa->interrupt_enable[reg - TFA98XX_INTERRUPT_ENABLE_REG1] + = new_value; + } + } else + return ERR; + + return 0; +} + +/* + * mask interrupts by disabling them + */ +int tfa_irq_mask(struct tfa_device *tfa) +{ + int reg; + + /* operate on all bits */ + for (reg = TFA98XX_INTERRUPT_ENABLE_REG1; reg <= + TFA98XX_INTERRUPT_ENABLE_REG1 + tfa9912_irq_max / 16; reg++) + reg_write(tfa, (unsigned char)reg, 0); + + return 0; +} + +/* + * unmask interrupts by enabling them again + */ +int tfa_irq_unmask(struct tfa_device *tfa) +{ + int reg; + + /* operate on all bits */ + for (reg = TFA98XX_INTERRUPT_ENABLE_REG1; reg <= + TFA98XX_INTERRUPT_ENABLE_REG1 + tfa9912_irq_max / 16; reg++) + reg_write(tfa, (unsigned char)reg, + tfa->interrupt_enable[reg - TFA98XX_INTERRUPT_ENABLE_REG1]); + + return 0; +} + +/* + * interrupt bit function that sets the polarity + */ + +int tfa_irq_set_pol(struct tfa_device *tfa, enum tfa9912_irq bit, int state) +{ + uint16_t value, new_value; + int reg = 0, mask; + + if (bit == tfa9912_irq_all) { + /* operate on all bits */ + for (reg = TFA98XX_STATUS_POLARITY_REG1; reg <= + TFA98XX_STATUS_POLARITY_REG1 + tfa9912_irq_max / 16; reg++) { + /* all bits */ + reg_write(tfa, (unsigned char)reg, state ? 0xffff : 0); + } + } else if (bit < tfa9912_irq_max) { + /* only this bit */ + reg = TFA98XX_STATUS_POLARITY_REG1 + (bit >> 4); + mask = 1 << (bit & 0x0f); + reg_read(tfa, (unsigned char)reg, &value); + if (state) /* Active High */ + new_value = (uint16_t)(value | mask); + else /* Active Low */ + new_value = value & ~mask; + if (new_value != value) { + reg_write(tfa, (unsigned char)reg, new_value); /* only this bit */ + } + } else + return ERR; + + return 0; +} + +/* + * set device info and register device ops + */ +void tfa_set_query_info(struct tfa_device *tfa) +{ + /* invalidate device struct cached values */ + tfa->hw_feature_bits = -1; + tfa->sw_feature_bits[0] = -1; + tfa->sw_feature_bits[1] = -1; + tfa->profile = -1; + tfa->vstep = -1; + /* defaults */ + tfa->is_probus_device = 0; + tfa->advance_keys_handling = 0; /*artf65038*/ + tfa->tfa_family = 1; + tfa->daimap = Tfa98xx_DAI_I2S; /* all others */ + tfa->spkr_count = 1; + tfa->spkr_select = 0; + tfa->support_tcoef = supportYes; + tfa->supportDrc = supportNotSet; + tfa->support_saam = supportNotSet; + /* respond to external DSP: -1:none, 0:no_dsp, 1:cold, 2:warm */ + tfa->ext_dsp = -1; + tfa->bus = 0; + tfa->partial_enable = 0; + tfa->convert_dsp32 = 0; + tfa->sync_iv_delay = 0; + + /* TODO use the getfeatures() for retrieving the features [artf103523] + tfa->supportDrc = supportNotSet;*/ + + switch (tfa->rev & 0xff) { + case 0: /* tfanone : non-i2c external DSP device */ + /* e.g. qc adsp */ + tfa->supportDrc = supportYes; + tfa->tfa_family = 0; + tfa->spkr_count = 0; + tfa->daimap = 0; + tfanone_ops(&tfa->dev_ops); /* register device operations via tfa hal*/ + tfa->bus = 1; + break; + case 0x72: + /* tfa9872 */ + tfa->supportDrc = supportYes; + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->is_probus_device = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9872_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x74: + /* tfa9874 */ + tfa->supportDrc = supportYes; + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->is_probus_device = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9874_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x78: + /* tfa9878 */ + tfa->supportDrc = supportYes; + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->is_probus_device = 1; + tfa->advance_keys_handling = 1; /*artf65038*/ + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9878_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x88: + /* tfa9888 */ + tfa->tfa_family = 2; + tfa->spkr_count = 2; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9888_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x97: + /* tfa9897 */ + tfa->supportDrc = supportNo; + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9897_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x96: + /* tfa9896 */ + tfa->supportDrc = supportNo; + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9896_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x92: + /* tfa9891 */ + tfa->spkr_count = 1; + tfa->daimap = (Tfa98xx_DAI_PDM | Tfa98xx_DAI_I2S); + tfa9891_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x91: + /* tfa9890B */ + tfa->spkr_count = 1; + tfa->daimap = (Tfa98xx_DAI_PDM | Tfa98xx_DAI_I2S); + break; + case 0x80: + case 0x81: + /* tfa9890 */ + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_I2S; + tfa->supportDrc = supportNo; + tfa->supportFramework = supportNo; + tfa9890_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x12: + /* tfa9895 */ + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_I2S; + tfa9895_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x13: + /* tfa9912 */ + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9912_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x94: + /* tfa9894 */ + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9894_ops(&tfa->dev_ops); /* register device operations */ + break; + + default: + pr_err("unknown device type : 0x%02x\n", tfa->rev); + _ASSERT(0); + break; + } +} + +/* + * lookup the device type and return the family type + */ +int tfa98xx_dev2family(int dev_type) +{ + /* only look at the die ID part (lsb byte) */ + switch (dev_type & 0xff) { + case 0x12: + case 0x80: + case 0x81: + case 0x91: + case 0x92: + case 0x97: + case 0x96: + return 1; + case 0x88: + case 0x72: + case 0x13: + case 0x74: + case 0x94: + return 2; + case 0x50: + return 3; + default: + return 0; + } +} + +/* + * return the target address for the filter on this device + + filter_index: + [0..9] reserved for EQ (not deployed, calc. is available) + [10..12] anti-alias filter + [13] integrator filter + + */ +enum Tfa98xx_DMEM tfa98xx_filter_mem(struct tfa_device *tfa, + int filter_index, unsigned short *address, int channel) +{ + enum Tfa98xx_DMEM dmem = -1; + int idx; + unsigned short bq_table[7][4] = { + /* index: 10, 11, 12, 13 */ + {346, 351, 356, 288}, //87 BRA_MAX_MRA4-2_7.00 + {346, 351, 356, 288}, //90 BRA_MAX_MRA6_9.02 + {467, 472, 477, 409}, //95 BRA_MAX_MRA7_10.02 + {406, 411, 416, 348}, //97 BRA_MAX_MRA9_12.01 + {467, 472, 477, 409}, //91 BRA_MAX_MRAA_13.02 + {8832, 8837, 8842, 8847}, //88 part1 + {8853, 8858, 8863, 8868} //88 part2 + /* Since the 88 is stereo we have 2 parts. + * Every index has 5 values except index 13 this one + * has 6 values + */ + }; + + if ((10 <= filter_index) && (filter_index <= 13)) { + dmem = Tfa98xx_DMEM_YMEM; /* for all devices */ + idx = filter_index - 10; + + switch (tfa->rev & 0xff) { // only compare lower byte + case 0x12: + *address = bq_table[2][idx]; + break; + case 0x97: + *address = bq_table[3][idx]; + break; + case 0x96: + *address = bq_table[3][idx]; + break; + case 0x80: + case 0x81: // for the RAM version + case 0x91: + *address = bq_table[1][idx]; + break; + case 0x92: + *address = bq_table[4][idx]; + break; + case 0x88: + /* Channel 1 = primary, 2 = secondary */ + if (channel == 1) + *address = bq_table[5][idx]; + else + *address = bq_table[6][idx]; + break; + case 0x72: + case 0x74: + case 0x13: + default: + /* unsupported case, possibly intermediate version */ + return ERR; + _ASSERT(0); + } + } + return dmem; +} + +/************************ query functions ******************************/ +/** +* return revision +* Used by the LTT +*/ +void tfa98xx_rev(int *major, int *minor, int *revision) +{ + char version_str[] = TFA98XX_API_REV_STR; + sscanf(version_str, "v%d.%d.%d", major, minor, revision); +} + +/** + * tfa_supported_speakers + * returns the number of the supported speaker count + */ +enum Tfa98xx_Error tfa_supported_speakers(struct tfa_device *tfa, + int *spkr_count) +{ + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + else + *spkr_count = tfa->spkr_count; + + return Tfa98xx_Error_Ok; +} + +/* + * tfa98xx_supported_saam + * returns the supportedspeaker as microphone feature + */ +enum Tfa98xx_Error tfa98xx_supported_saam(struct tfa_device *tfa, + enum Tfa98xx_saam *saam) +{ + int features; + enum Tfa98xx_Error error; + + if (tfa->support_saam == supportNotSet) { + error = tfa98xx_dsp_get_hw_feature_bits(tfa, &features); + if (error != Tfa98xx_Error_Ok) + return error; + tfa->support_saam = + (features & 0x8000) ? supportYes : supportNo; /* SAAM is bit15 */ + } + *saam = tfa->support_saam == supportYes ? Tfa98xx_saam : Tfa98xx_saam_none; + + return Tfa98xx_Error_Ok; +} + +/* + * tfa98xx_compare_features + * Obtains features_from_MTP and features_from_cnt + */ +enum Tfa98xx_Error tfa98xx_compare_features(struct tfa_device *tfa, + int features_from_MTP[3], int features_from_cnt[3]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint32_t value; + uint16_t mtpbf; + unsigned char bytes[3 * 2]; + int status; + + tfa98xx_dsp_system_stable(tfa, &status); + if (!status) + return Tfa98xx_Error_NoClock; // Only test when we have a clock. + + /* Set proper MTP location per device: */ + if (tfa->tfa_family == 1) { + mtpbf = 0x850f; /* MTP5 for tfa1,16 bits */ + } else { + mtpbf = 0xf907; /* MTP9 for tfa2, 8 bits */ + } + + /* Read HW features from MTP: */ + value = tfa_read_reg(tfa, mtpbf) & 0xffff; + features_from_MTP[0] = tfa->hw_feature_bits = value; + + /* Read SW features: */ + error = tfa_dsp_cmd_id_write_read(tfa, MODULE_FRAMEWORK, + FW_PAR_ID_GET_FEATURE_INFO, sizeof(bytes), bytes); + if (error != Tfa98xx_Error_Ok) + /* old ROM code may respond with Tfa98xx_Error_RpcParamId */ + return error; + + tfa98xx_convert_bytes2data(sizeof(bytes), bytes, &features_from_MTP[1]); + + /* check if feature bits from MTP match feature bits from cnt file: */ + get_hw_features_from_cnt(tfa, &features_from_cnt[0]); + get_sw_features_from_cnt(tfa, &features_from_cnt[1]); + + return error; +} + +/********************************* device specific ops **********************/ +/* the wrapper for DspReset, in case of full */ +enum Tfa98xx_Error tfa98xx_dsp_reset(struct tfa_device *tfa, int state) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + error = (tfa->dev_ops.dsp_reset)(tfa, state); + + return error; +} + +/* the ops wrapper for tfa98xx_dsp_SystemStable */ +enum Tfa98xx_Error tfa98xx_dsp_system_stable(struct tfa_device *tfa, + int *ready) +{ + return (tfa->dev_ops.dsp_system_stable)(tfa, ready); +} + +/* the ops wrapper for tfa98xx_dsp_system_stable */ +enum Tfa98xx_Error tfa98xx_auto_copy_mtp_to_iic(struct tfa_device *tfa) +{ + return (tfa->dev_ops.auto_copy_mtp_to_iic)(tfa); +} + +/* the ops wrapper for tfa98xx_faim_protect */ +enum Tfa98xx_Error tfa98xx_faim_protect(struct tfa_device *tfa, int state) +{ + return (tfa->dev_ops.faim_protect)(tfa, state); +} + +/* + * bring the device into a state similar to reset + */ +enum Tfa98xx_Error tfa98xx_init(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint16_t value = 0; + + /* reset all i2C registers to default + * Write the register directly to avoid the read in the bitfield function. + * The I2CR bit may overwrite the full register because it is reset anyway. + * This will save a reg read transaction. + */ + TFA_SET_BF_VALUE(tfa, I2CR, 1, &value); + TFA_WRITE_REG(tfa, I2CR, value); + + /* Put DSP in reset */ + tfa98xx_dsp_reset(tfa, 1); /* in pair of tfaRunStartDSP() */ + + /* some other registers must be set for optimal amplifier behaviour + * This is implemented in a file specific for the type number + */ + if (tfa->dev_ops.tfa_init) + error = (tfa->dev_ops.tfa_init)(tfa); + + return error; +} + +enum Tfa98xx_Error tfa98xx_dsp_write_tables(struct tfa_device *tfa, + int sample_rate) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + error = (tfa->dev_ops.dsp_write_tables)(tfa, sample_rate); + + return error; +} + +/** Set internal oscillator into power down mode. +* +* @param[in] tfa device description structure +* @param[in] state new state 0 - oscillator is on, 1 oscillator is off. +* +* @return Tfa98xx_Error_Ok when successfull, error otherwise. +*/ +enum Tfa98xx_Error tfa98xx_set_osc_powerdown(struct tfa_device *tfa, int state) +{ + if (tfa->dev_ops.set_osc_powerdown) { + return tfa->dev_ops.set_osc_powerdown(tfa, state); + } + + return Tfa98xx_Error_Not_Implemented; +} + +/** update low power mode of the device. +* +* @param[in] tfa device description structure +* @param[in] state new state 0 - LPMODE is on, 1 LPMODE is off. +* +* @return Tfa98xx_Error_Ok when successfull, error otherwise. +*/ +enum Tfa98xx_Error tfa98xx_update_lpm(struct tfa_device *tfa, int state) +{ + if (tfa->dev_ops.update_lpm) { + return tfa->dev_ops.update_lpm(tfa, state); + } + + return Tfa98xx_Error_Not_Implemented; +} +/** Check presence of powerswitch=1 in configuration and optimal setting. +* +* @param[in] tfa device description structure +* +* @return -1 when error, 0 or 1 depends on switch settings. +*/ +int tfa98xx_powerswitch_is_enabled(struct tfa_device *tfa) +{ + uint16_t value; + enum Tfa98xx_Error ret; + + if (((tfa->rev & 0xff) == 0x13) || ((tfa->rev & 0xff) == 0x88)) { + ret = reg_read(tfa, 0xc6, &value); + if (ret != Tfa98xx_Error_Ok) { + return ERR; + } + /* + * PLMA5539: Check actual value of powerswitch. TODO: regmap v1.40 + * should make this bit public. + */ + + return (int)(value & (1u << 6)); + } + + return 1; +} + +/********************* new tfa2 ***************************************/ +/* newly added messaging for tfa2 tfa1? */ +enum Tfa98xx_Error tfa98xx_dsp_get_memory(struct tfa_device *tfa, + int memoryType, int offset, int length, unsigned char bytes[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + char msg[4 * 3]; + int nr = 0; + + msg[nr++] = 8; + msg[nr++] = MODULE_FRAMEWORK + 128; + msg[nr++] = FW_PAR_ID_GET_MEMORY; + + msg[nr++] = 0; + msg[nr++] = 0; + msg[nr++] = (char)memoryType; + + msg[nr++] = 0; + msg[nr++] = (offset >> 8) & 0xff; + msg[nr++] = offset & 0xff; + + msg[nr++] = 0; + msg[nr++] = (length >> 8) & 0xff; + msg[nr++] = length & 0xff; + + /* send msg */ + error = dsp_msg(tfa, nr, (char *)msg); + + if (error != Tfa98xx_Error_Ok) + return error; + + /* read the data from the device (length * 3) */ + error = dsp_msg_read(tfa, length * 3, bytes); + + return error; +} + +enum Tfa98xx_Error tfa98xx_dsp_set_memory(struct tfa_device *tfa, + int memoryType, int offset, int length, int value) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int nr = 0; + char msg[5 * 3]; + + msg[nr++] = 8; + msg[nr++] = MODULE_FRAMEWORK + 128; + msg[nr++] = FW_PAR_ID_SET_MEMORY; + + msg[nr++] = 0; + msg[nr++] = 0; + msg[nr++] = (char)memoryType; + + msg[nr++] = 0; + msg[nr++] = (offset >> 8) & 0xff; + msg[nr++] = offset & 0xff; + + msg[nr++] = 0; + msg[nr++] = (length >> 8) & 0xff; + msg[nr++] = length & 0xff; + + msg[nr++] = (value >> 16) & 0xff; + msg[nr++] = (value >> 8) & 0xff; + msg[nr++] = value & 0xff; + + /* send msg */ + error = dsp_msg(tfa, nr, (char *)msg); + + return error; +} +/****************************** calibration support **************************/ +/* + * get/set the mtp with user controllable values + * + * check if the relevant clocks are available + */ +enum Tfa98xx_Error tfa98xx_get_mtp(struct tfa_device *tfa, uint16_t *value) +{ + int status; + int result; + + /* not possible if PLL in powerdown */ + if (TFA_GET_BF(tfa, PWDN)) { + pr_debug("PLL in powerdown\n"); + return Tfa98xx_Error_NoClock; + } + + tfa98xx_dsp_system_stable(tfa, &status); + if (status == 0) { + pr_debug("PLL not running\n"); + return Tfa98xx_Error_NoClock; + } + + result = TFA_READ_REG(tfa, MTP0); + if (result < 0) { + return -result; + } + *value = (uint16_t)result; + + return Tfa98xx_Error_Ok; +} + +/* + * lock or unlock KEY2 + * lock = 1 will lock + * lock = 0 will unlock + * + * note that on return all the hidden key will be off + */ +void tfa98xx_key2(struct tfa_device *tfa, int lock) +{ + /* unhide lock registers */ + reg_write(tfa, (tfa->tfa_family == 1) ? 0x40 : 0x0F, 0x5A6B); + /* lock/unlock key2 MTPK */ + TFA_WRITE_REG(tfa, MTPKEY2, lock ? 0 : 0x5A); + /* unhide lock registers */ + if (!tfa->advance_keys_handling) /*artf65038*/ + reg_write(tfa, (tfa->tfa_family == 1) ? 0x40 : 0x0F, 0); +} +void tfa2_manual_mtp_cpy(struct tfa_device *tfa, uint16_t reg_row_to_keep, + uint16_t reg_row_to_set, uint8_t row)///MCH_TO_TEST +{ + uint16_t value; + int loop = 0; + enum Tfa98xx_Error error; + /* Assure FAIM is enabled (enable it when neccesery) */ + if (tfa->is_probus_device) { + error = tfa98xx_faim_protect(tfa, 1); + if (tfa->verbose) { + pr_debug("FAIM enabled (err:%d).\n", error); + } + } + reg_read(tfa, (unsigned char)reg_row_to_keep, &value); + if (!row) { + reg_write(tfa, 0xA7, value); + reg_write(tfa, 0xA8, reg_row_to_set); + } else { + reg_write(tfa, 0xA7, reg_row_to_set); + reg_write(tfa, 0xA8, value); + } + reg_write(tfa, 0xA3, 0x10 | row); + if (tfa->is_probus_device) { + /* Assure FAIM is enabled (enable it when neccesery) */ + for (loop = 0; loop < 100 /*x10ms*/; loop++) { + msleep_interruptible(10); /* wait 10ms to avoid busload */ + if (tfa_dev_get_mtpb(tfa) == 0) + break; + } + error = tfa98xx_faim_protect(tfa, 0); + if (tfa->verbose) { + pr_debug("FAIM disabled (err:%d).\n", error); + } + } +} + +enum Tfa98xx_Error tfa98xx_set_mtp(struct tfa_device *tfa, uint16_t value, + uint16_t mask) +{ + unsigned short mtp_old, mtp_new; + int loop, status; + enum Tfa98xx_Error error; + + error = tfa98xx_get_mtp(tfa, &mtp_old); + + if (error != Tfa98xx_Error_Ok) + return error; + + mtp_new = (value & mask) | (mtp_old & ~mask); + + if (mtp_old == mtp_new) /* no change */ { + if (tfa->verbose) + pr_info("No change in MTP. Value not written! \n"); + return Tfa98xx_Error_Ok; + } + error = tfa98xx_update_lpm(tfa, 1); + if (error) { + return error; + } + /* Assure FAIM is enabled (enable it when neccesery) */ + error = tfa98xx_faim_protect(tfa, 1); + if (error) { + return error; + } + if (tfa->verbose) { + pr_debug("MTP clock enabled.\n"); + } + + /* assure that the clock is up, else we can't write MTP */ + error = tfa98xx_dsp_system_stable(tfa, &status); + if (error) { + return error; + } + if (status == 0) { + return Tfa98xx_Error_NoClock; + } + + tfa98xx_key2(tfa, 0); /* unlock */ + TFA_WRITE_REG(tfa, MTP0, mtp_new); /* write to i2c shadow reg */ + /* CIMTP=1 start copying all the data from i2c regs_mtp to mtp*/ + if (tfa->tfa_family == 2) + tfa2_manual_mtp_cpy(tfa, 0xF1, mtp_new, 0); + else + TFA_SET_BF(tfa, CIMTP, 1); + /* wait until MTP write is done */ + error = Tfa98xx_Error_StateTimedOut; + for (loop = 0; loop < 100 /*x10ms*/; loop++) { + msleep_interruptible(10); /* wait 10ms to avoid busload */ + if (tfa_dev_get_mtpb(tfa) == 0) { + error = Tfa98xx_Error_Ok; + break; + } + } + tfa98xx_key2(tfa, 1); /* lock */ + /* MTP setting failed due to timeout ?*/ + if (error) { + tfa98xx_faim_protect(tfa, 0); + return error; + } + + /* Disable the FAIM, if this is neccessary */ + error = tfa98xx_faim_protect(tfa, 0); + if (error) { + return error; + } + if (tfa->verbose) { + pr_debug("MTP clock disabled.\n"); + } + error = tfa98xx_update_lpm(tfa, 0); + if (error) { + return error; + } + return error; +} +/* + * clear mtpex + * set ACS + * start tfa + */ +int tfa_calibrate(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error; + + /* clear mtpex */ + error = tfa98xx_set_mtp(tfa, 0, TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK); + if (error) + return error; + + /* set RST=1 to put the DSP in Reset */ + TFA_SET_BF(tfa, RST, 1); + + /* set ACS/coldboot state */ + error = tfaRunColdboot(tfa, 1); + + /* start tfa by playing */ + return error; +} + +static short twos(short x) +{ + return (x < 0) ? x + 512 : x; +} + +void tfa98xx_set_exttemp(struct tfa_device *tfa, short ext_temp) +{ + if ((-256 <= ext_temp) && (ext_temp <= 255)) { + /* make twos complement */ + pr_debug("Using ext temp %d C\n", twos(ext_temp)); + TFA_SET_BF(tfa, TROS, 1); + TFA_SET_BF(tfa, EXTTS, twos(ext_temp)); + } else { + pr_debug("Clearing ext temp settings\n"); + TFA_SET_BF(tfa, TROS, 0); + } +} +short tfa98xx_get_exttemp(struct tfa_device *tfa) +{ + short ext_temp = (short)TFA_GET_BF(tfa, EXTTS); + return twos(ext_temp); +} + +/******************* tfa simple bitfield interfacing *************************/ +/* convenience functions */ +enum Tfa98xx_Error tfa98xx_set_volume_level(struct tfa_device *tfa, + unsigned short vol) +{ + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + if (vol > 255) /* restricted to 8 bits */ + vol = 255; + + /* 0x00 -> 0.0 dB + * 0x01 -> -0.5 dB + * ... + * 0xFE -> -127dB + * 0xFF -> muted + */ + + /* volume value is in the top 8 bits of the register */ + return -TFA_SET_BF(tfa, VOL, (uint16_t)vol); +} + +static enum Tfa98xx_Error +tfa98xx_set_mute_tfa2(struct tfa_device *tfa, enum Tfa98xx_Mute mute) +{ + enum Tfa98xx_Error error; + + if (tfa->dev_ops.set_mute == NULL) + return Tfa98xx_Error_Not_Supported; + + switch (mute) { + case Tfa98xx_Mute_Off: + error = tfa->dev_ops.set_mute(tfa, 0); + TFA_SET_BF(tfa, AMPE, 1); + break; + case Tfa98xx_Mute_Amplifier: + case Tfa98xx_Mute_Digital: + error = tfa->dev_ops.set_mute(tfa, 1); + TFA_SET_BF(tfa, AMPE, 0); + break; + default: + return Tfa98xx_Error_Bad_Parameter; + } + + return error; +} + +static enum Tfa98xx_Error +tfa98xx_set_mute_tfa1(struct tfa_device *tfa, enum Tfa98xx_Mute mute) +{ + enum Tfa98xx_Error error; + unsigned short audioctrl_value; + unsigned short sysctrl_value; + int value; + + value = TFA_READ_REG(tfa, CFSM); /* audio control register */ + if (value < 0) + return -value; + audioctrl_value = (unsigned short)value; + value = TFA_READ_REG(tfa, AMPE); /* system control register */ + if (value < 0) + return -value; + sysctrl_value = (unsigned short)value; + + switch (mute) { + case Tfa98xx_Mute_Off: + /* previous state can be digital or amplifier mute, + * clear the cf_mute and set the enbl_amplifier bits + * + * To reduce PLOP at power on it is needed to switch the + * amplifier on with the DCDC in follower mode + * (enbl_boost = 0 ?). + * This workaround is also needed when toggling the + * powerdown bit! + */ + TFA_SET_BF_VALUE(tfa, CFSM, 0, &audioctrl_value); + TFA_SET_BF_VALUE(tfa, AMPE, 1, &sysctrl_value); + TFA_SET_BF_VALUE(tfa, DCA, 1, &sysctrl_value); + break; + case Tfa98xx_Mute_Digital: + /* expect the amplifier to run */ + /* set the cf_mute bit */ + TFA_SET_BF_VALUE(tfa, CFSM, 1, &audioctrl_value); + /* set the enbl_amplifier bit */ + TFA_SET_BF_VALUE(tfa, AMPE, 1, &sysctrl_value); + /* clear active mode */ + TFA_SET_BF_VALUE(tfa, DCA, 0, &sysctrl_value); + break; + case Tfa98xx_Mute_Amplifier: + /* clear the cf_mute bit */ + TFA_SET_BF_VALUE(tfa, CFSM, 0, &audioctrl_value); + /* clear the enbl_amplifier bit and active mode */ + TFA_SET_BF_VALUE(tfa, AMPE, 0, &sysctrl_value); + TFA_SET_BF_VALUE(tfa, DCA, 0, &sysctrl_value); + break; + default: + return Tfa98xx_Error_Bad_Parameter; + } + + error = -TFA_WRITE_REG(tfa, CFSM, audioctrl_value); + if (error) + return error; + error = -TFA_WRITE_REG(tfa, AMPE, sysctrl_value); + return error; +} + +enum Tfa98xx_Error + tfa98xx_set_mute(struct tfa_device *tfa, enum Tfa98xx_Mute mute) +{ + if (tfa->in_use == 0) { + pr_err("device is not opened \n"); + return Tfa98xx_Error_NotOpen; + } + + if (tfa->tfa_family == 1) + return tfa98xx_set_mute_tfa1(tfa, mute); + else + return tfa98xx_set_mute_tfa2(tfa, mute); +} + +/****************** patching ***********************************************/ +static enum Tfa98xx_Error +tfa98xx_process_patch_file(struct tfa_device *tfa, int length, + const unsigned char *bytes) +{ + unsigned short size; + int index = 0; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + while (index < length) { + size = bytes[index] + bytes[index + 1] * 256; + index += 2; + if ((index + size) > length) { + /* outside the buffer, error in the input data */ + return Tfa98xx_Error_Bad_Parameter; + } + + if (size > tfa->buffer_size) { + /* too big, must fit buffer */ + return Tfa98xx_Error_Bad_Parameter; + } + + error = tfa98xx_write_raw(tfa, size, &bytes[index]); + if (error != Tfa98xx_Error_Ok) + break; + index += size; + } + return error; +} + + + +/* the patch contains a header with the following + * IC revision register: 1 byte, 0xFF means don't care + * XMEM address to check: 2 bytes, big endian, 0xFFFF means don't care + * XMEM value to expect: 3 bytes, big endian + */ +static enum Tfa98xx_Error +tfa98xx_check_ic_rom_version(struct tfa_device *tfa, + const unsigned char patchheader[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short checkrev, revid; + unsigned char lsb_revid; + unsigned short checkaddress; + int checkvalue; + int value = 0; + int status; + checkrev = patchheader[0]; + lsb_revid = tfa->rev & 0xff; /* only compare lower byte */ + + if ((checkrev != 0xFF) && (checkrev != lsb_revid)) + return Tfa98xx_Error_Not_Supported; + + checkaddress = (patchheader[1] << 8) + patchheader[2]; + checkvalue = + (patchheader[3] << 16) + (patchheader[4] << 8) + patchheader[5]; + if (checkaddress != 0xFFFF) { + /* before reading XMEM, check if we can access the DSP */ + error = tfa98xx_dsp_system_stable(tfa, &status); + if (error == Tfa98xx_Error_Ok) { + if (!status) { + /* DSP subsys not running */ + error = Tfa98xx_Error_DSP_not_running; + } + } + /* read register to check the correct ROM version */ + if (error == Tfa98xx_Error_Ok) { + error = mem_read(tfa, checkaddress, 1, &value); + } + if (error == Tfa98xx_Error_Ok) { + if (value != checkvalue) { + pr_err("patch file romid type check failed [0x%04x]: \ + expected 0x%02x, actual 0x%02x\n", + checkaddress, value, checkvalue); + error = Tfa98xx_Error_Not_Supported; + } + } + } else { /* == 0xffff */ + /* check if the revid subtype is in there */ + if (checkvalue != 0xFFFFFF && checkvalue != 0) { + revid = patchheader[5] << 8 | patchheader[0]; /* full revid */ + if (revid != tfa->rev) { + pr_err("patch file device type check failed: expected 0x%02x, actual 0x%02x\n", + tfa->rev, revid); + return Tfa98xx_Error_Not_Supported; + } + } + } + + return error; +} + + +#define PATCH_HEADER_LENGTH 6 +enum Tfa98xx_Error + tfa_dsp_patch(struct tfa_device *tfa, int patchLength, + const unsigned char *patchBytes) +{ + enum Tfa98xx_Error error; + int status; + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + if (patchLength < PATCH_HEADER_LENGTH) + return Tfa98xx_Error_Bad_Parameter; + + error = tfa98xx_check_ic_rom_version(tfa, patchBytes); + if (Tfa98xx_Error_Ok != error) { + return error; + } + tfa98xx_dsp_system_stable(tfa, &status); + if (!status) + return Tfa98xx_Error_NoClock; // Only test when we have a clock. + /******MCH_TO_TEST**************/ + if (error == Tfa98xx_Error_Ok) { + error = tfaRunColdboot(tfa, 1); + if (error) + return Tfa98xx_Error_DSP_not_running; + } + /**************************/ + error = + tfa98xx_process_patch_file(tfa, patchLength - PATCH_HEADER_LENGTH, + patchBytes + PATCH_HEADER_LENGTH); + + return error; +} + +/****************** end patching *****************************************/ + +TFA_INTERNAL enum Tfa98xx_Error +tfa98xx_wait_result(struct tfa_device *tfa, int wait_retry_count) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int cf_status; /* the contents of the CF_STATUS register */ + int tries = 0; + do { + cf_status = TFA_GET_BF(tfa, ACK); + if (cf_status < 0) + error = -cf_status; + tries++; + } + // i2c_cmd_ack + /* don't wait forever, DSP is pretty quick to respond (< 1ms) */ + while ((error == Tfa98xx_Error_Ok) && + ((cf_status & CF_STATUS_I2C_CMD_ACK) == 0) && (tries < wait_retry_count)); + + if (tries >= wait_retry_count) { + /* something wrong with communication with DSP */ + error = Tfa98xx_Error_DSP_not_running; + } + return error; +} + +/* + * * support functions for data conversion + */ + /** + convert memory bytes to signed 24 bit integers + input: bytes contains "num_bytes" byte elements + output: data contains "num_bytes/3" int24 elements + */ +void tfa98xx_convert_bytes2data(int num_bytes, const unsigned char bytes[], + int data[]) +{ + int i; /* index for data */ + int k; /* index for bytes */ + int d; + int num_data = num_bytes / 3; + _ASSERT((num_bytes % 3) == 0); + for (i = 0, k = 0; i < num_data; ++i, k += 3) { + d = (bytes[k] << 16) | (bytes[k + 1] << 8) | (bytes[k + 2]); + _ASSERT(d >= 0); + _ASSERT(d < (1 << 24)); /* max 24 bits in use */ + if (bytes[k] & 0x80) /* sign bit was set */ + d = -((1 << 24) - d); + + data[i] = d; + } +} + + +/** + convert signed 32 bit integers to 24 bit aligned bytes + input: data contains "num_data" int elements + output: bytes contains "3 * num_data" byte elements +*/ +void tfa98xx_convert_data2bytes(int num_data, const int data[], + unsigned char bytes[]) +{ + int i; /* index for data */ + int k; /* index for bytes */ + int d; + /* note: cannot just take the lowest 3 bytes from the 32 bit + * integer, because also need to take care of clipping any + * value > 2&23 */ + for (i = 0, k = 0; i < num_data; ++i, k += 3) { + if (data[i] >= 0) + d = MIN(data[i], (1 << 23) - 1); + else { + /* 2's complement */ + d = (1 << 24) - MIN(-data[i], 1 << 23); + } + _ASSERT(d >= 0); + _ASSERT(d < (1 << 24)); /* max 24 bits in use */ + bytes[k] = (d >> 16) & 0xFF; /* MSB */ + bytes[k + 1] = (d >> 8) & 0xFF; + bytes[k + 2] = (d) & 0xFF; /* LSB */ + } +} + +/* + * DSP RPC message support functions + * depending on framework to be up and running + * need base i2c of memaccess (tfa1=0x70/tfa2=0x90) + */ + + + /* write dsp messages in function tfa_dsp_msg() */ + /* note the 'old' write_parameter() was more efficient because all + * i2c was in one burst transaction + */ + + /* + * TODO properly handle bitfields: state should be restored! + * (now it will change eg dmesg field to xmem) + */ +enum Tfa98xx_Error tfa_dsp_msg_write(struct tfa_device *tfa, int length, + const char *buffer) +{ + int offset = 0; + /* XMEM word size */ + int chunk_size = ROUND_DOWN(tfa->buffer_size, 3); + int remaining_bytes = length; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint16_t cfctl; + int value; + + value = TFA_READ_REG(tfa, DMEM); + if (value < 0) { + error = -value; + return error; + } + cfctl = (uint16_t)value; + /* assume no I2C errors from here */ + /* set cf ctl to DMEM */ + TFA_SET_BF_VALUE(tfa, DMEM, (uint16_t)Tfa98xx_DMEM_XMEM, &cfctl); + TFA_SET_BF_VALUE(tfa, AIF, 0, &cfctl); /* set to autoincrement */ + TFA_WRITE_REG(tfa, DMEM, cfctl); + + /* xmem[1] is start of message + * direct write to register to save cycles avoiding read-modify-write + */ + TFA_WRITE_REG(tfa, MADD, 1); + + /* due to autoincrement in cf_ctrl, next write will happen at + * the next address */ + while ((error == Tfa98xx_Error_Ok) && (remaining_bytes > 0)) { + if (remaining_bytes < chunk_size) + chunk_size = remaining_bytes; + /* else chunk_size remains at initialize value above */ + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, + chunk_size, (const unsigned char *)buffer + offset); + remaining_bytes -= chunk_size; + offset += chunk_size; + } + + /* notify the DSP */ + if (error == Tfa98xx_Error_Ok) { + /* cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */ + /* set the cf_req1 and cf_int bit */ + TFA_SET_BF_VALUE(tfa, REQCMD, 0x01, &cfctl); /* bit 0 */ + TFA_SET_BF_VALUE(tfa, CFINT, 1, &cfctl); + error = -TFA_WRITE_REG(tfa, CFINT, cfctl); + } + + return error; +} + +enum Tfa98xx_Error tfa_dsp_msg_write_id(struct tfa_device *tfa, int length, + const char *buffer, uint8_t cmdid[3]) +{ + int offset = 0; + int chunk_size = ROUND_DOWN(tfa->buffer_size, 3); /* XMEM word size */ + int remaining_bytes = length; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint16_t cfctl; + int value; + + value = TFA_READ_REG(tfa, DMEM); + if (value < 0) { + error = -value; + return error; + } + cfctl = (uint16_t)value; + /* assume no I2C errors from here */ + /* set cf ctl to DMEM */ + TFA_SET_BF_VALUE(tfa, DMEM, (uint16_t)Tfa98xx_DMEM_XMEM, &cfctl); + TFA_SET_BF_VALUE(tfa, AIF, 0, &cfctl); /* set to autoincrement */ + TFA_WRITE_REG(tfa, DMEM, cfctl); + + /* xmem[1] is start of message + * direct write to register to save cycles avoiding read-modify-write + */ + TFA_WRITE_REG(tfa, MADD, 1); + + /* write cmd-id */ + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, 3, + (const unsigned char *)cmdid); + + /* due to autoincrement in cf_ctrl, next write will happen at + * the next address */ + while ((error == Tfa98xx_Error_Ok) && (remaining_bytes > 0)) { + if (remaining_bytes < chunk_size) + chunk_size = remaining_bytes; + /* else chunk_size remains at initialize value above */ + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, + chunk_size, (const unsigned char *)buffer + offset); + remaining_bytes -= chunk_size; + offset += chunk_size; + } + + /* notify the DSP */ + if (error == Tfa98xx_Error_Ok) { + /* cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */ + /* set the cf_req1 and cf_int bit */ + TFA_SET_BF_VALUE(tfa, REQCMD, 0x01, &cfctl); /* bit 0 */ + TFA_SET_BF_VALUE(tfa, CFINT, 1, &cfctl); + error = -TFA_WRITE_REG(tfa, CFINT, cfctl); + } + + return error; +} + +/* +* status function used by tfa_dsp_msg() to retrieve command/msg status: +* return a <0 status of the DSP did not ACK. +*/ +enum Tfa98xx_Error tfa_dsp_msg_status(struct tfa_device *tfa, int *pRpcStatus) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + error = tfa98xx_wait_result(tfa, 2); /* 2 is only one try */ + if (error == Tfa98xx_Error_DSP_not_running) { + *pRpcStatus = -1; + return Tfa98xx_Error_Ok; + } else if (error != Tfa98xx_Error_Ok) + return error; + + error = tfa98xx_check_rpc_status(tfa, pRpcStatus); + + return error; +} + +const char *tfa98xx_get_i2c_status_id_string(int status) +{ + const char *p_id_str; + + switch (status) { + case Tfa98xx_DSP_Not_Running: + p_id_str = "No response from DSP"; + break; + case Tfa98xx_I2C_Req_Done: + p_id_str = "Ok"; + break; + case Tfa98xx_I2C_Req_Busy: + p_id_str = "Request is being processed"; + break; + case Tfa98xx_I2C_Req_Invalid_M_ID: + p_id_str = "Provided M-ID does not fit in valid rang [0..2]"; + break; + case Tfa98xx_I2C_Req_Invalid_P_ID: + p_id_str = "Provided P-ID is not valid in the given M-ID context"; + break; + case Tfa98xx_I2C_Req_Invalid_CC: + p_id_str = "Invalid channel configuration bits (SC|DS|DP|DC) combination"; + break; + case Tfa98xx_I2C_Req_Invalid_Seq: + p_id_str = "Invalid sequence of commands, in case the DSP expects some \ + commands in a specific order"; + break; + case Tfa98xx_I2C_Req_Invalid_Param: + p_id_str = "Generic error, invalid parameter"; + break; + case Tfa98xx_I2C_Req_Buffer_Overflow: + p_id_str = "I2C buffer has overflowed: host has sent too many \ + parameters, memory integrity is not guaranteed"; + break; + case Tfa98xx_I2C_Req_Calib_Busy: + p_id_str = "Calibration not completed"; + break; + case Tfa98xx_I2C_Req_Calib_Failed: + p_id_str = "Calibration failed"; + break; + + default: + p_id_str = "Unspecified error"; + } + + return p_id_str; +} + +enum Tfa98xx_Error tfa_dsp_msg_read(struct tfa_device *tfa, int length, + unsigned char *bytes) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int burst_size; /* number of words per burst size */ + int bytes_per_word = 3; + int num_bytes; + int offset = 0; + unsigned short start_offset = 2; /* msg starts @xmem[2] ,[1]=cmd */ + + if (length > TFA2_MAX_PARAM_SIZE) + return Tfa98xx_Error_Bad_Parameter; + + TFA_SET_BF(tfa, DMEM, (uint16_t)Tfa98xx_DMEM_XMEM); + error = -TFA_WRITE_REG(tfa, MADD, start_offset); + if (error != Tfa98xx_Error_Ok) + return error; + + num_bytes = length; /* input param */ + while (num_bytes > 0) { + burst_size = ROUND_DOWN(tfa->buffer_size, bytes_per_word); + if (num_bytes < burst_size) + burst_size = num_bytes; + error = tfa98xx_read_data(tfa, FAM_TFA98XX_CF_MEM, burst_size, + bytes + offset); + if (error != Tfa98xx_Error_Ok) + return error; + + num_bytes -= burst_size; + offset += burst_size; + } + + return error; +} + +enum Tfa98xx_Error dsp_msg(struct tfa_device *tfa, int length24, + const char *buf24) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int lastmessage = 0; + uint8_t *blob; + int i; + int *intbuf = NULL; + char *buf = (char *)buf24; + int length = length24; + + if (tfa->convert_dsp32) { + int idx = 0; + + length = 4 * length24 / 3; + intbuf = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + buf = (char *)intbuf; + + /* convert 24 bit DSP messages to a 32 bit integer */ + for (i = 0; i < length24; i += 3) { + int tmp = (buf24[i] << 16) + (buf24[i + 1] << 8) + buf24[i + 2]; + /* Sign extend to 32-bit from 24-bit */ + intbuf[idx++] = ((int32_t)tmp << 8) >> 8; + } + } + + /* Only create multi-msg when the dsp is cold */ + if (tfa->ext_dsp == 1) { + /* Creating the multi-msg */ + error = tfa_tib_dsp_msgmulti(tfa, length, buf); + if (error == Tfa98xx_Error_Fail) + return Tfa98xx_Error_Fail; + + /* if the buffer is full we need to send the existing message + * and add the current message + */ + if (error == Tfa98xx_Error_Buffer_too_small) { + int len; + + /* (a) send the existing (full) message */ + blob = kmalloc(64 * 1024, GFP_KERNEL); // max length is 64k + len = tfa_tib_dsp_msgmulti(tfa, -1, (const char *)blob); + if (tfa->verbose) { + pr_debug("Multi-message buffer full. Sending multi-message,\ + length=%d \n", len); + } + if (tfa->has_msg == 0) /* via i2c */ { + /* Send tot the target selected */ + error = (tfa->dev_ops.dsp_msg)(tfa, len, (const char *)blob); + } else { /* via msg hal */ + error = tfa98xx_write_dsp(tfa, len, (const char *)blob); + } + kfree(blob); + + /* (b) add the current DSP message to a new multi-message */ + error = tfa_tib_dsp_msgmulti(tfa, length, buf); + if (error == Tfa98xx_Error_Fail) { + return Tfa98xx_Error_Fail; + } + } + + lastmessage = error; + + /* When the lastmessage is done we can send the multi-msg to the target */ + if (lastmessage == 1) { + + /* Get the full multi-msg data */ + blob = kmalloc(64 * 1024, GFP_KERNEL); //max length is 64k + length = tfa_tib_dsp_msgmulti(tfa, -1, (const char *)blob); + + if (tfa->verbose) + pr_debug("Last message for the multi-message received.\ + Multi-message length=%d \n", length); + + if (tfa->has_msg == 0) /* via i2c */ { + /* Send tot the target selected */ + error = (tfa->dev_ops.dsp_msg)(tfa, length, (const char *)blob); + } else { /* via msg hal */ + error = tfa98xx_write_dsp(tfa, length, (const char *)blob); + } + + kfree(blob); /* Free the kmalloc blob */ + lastmessage = 0; /* reset to be able to re-start */ + } + } else { + if (tfa->has_msg == 0) /* via i2c */ { + error = (tfa->dev_ops.dsp_msg)(tfa, length, buf); + } else { /* via msg hal */ + error = tfa98xx_write_dsp(tfa, length, (const char *)buf); + } + } + + if (error != Tfa98xx_Error_Ok) + /* Get actual error code from softDSP */ + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); + + /* DSP verbose has argument 0x04 */ + if ((tfa->verbose & 0x04) != 0) { + pr_debug("DSP w [%d]: ", length); + for (i = 0; i < length; i++) + pr_debug("0x%02x ", (uint8_t)buf[i]); + pr_debug("\n"); + } + + if (tfa->convert_dsp32) { + kmem_cache_free(tfa->cachep, intbuf); + } + + return error; +} + +enum Tfa98xx_Error dsp_msg_read(struct tfa_device *tfa, int length24, unsigned char *bytes24) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int i; + int length = length24; + unsigned char *bytes = bytes24; + + if (tfa->convert_dsp32) { + length = 4 * length24 / 3; + bytes = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + } + + if (tfa->has_msg == 0) /* via i2c */ { + error = (tfa->dev_ops.dsp_msg_read)(tfa, length, bytes); + } else { /* via msg hal */ + error = tfa98xx_read_dsp(tfa, length, bytes); + } + + if (error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + /* DSP verbose has argument 0x04 */ + if ((tfa->verbose & 0x04) != 0) { + pr_debug("DSP R [%d]: ", length); + for (i = 0; i < length; i++) + pr_debug("0x%02x ", (uint8_t)bytes[i]); + pr_debug("\n"); + } + + if (tfa->convert_dsp32) { + int idx = 0; + + /* convert 32 bit LE to 24 bit BE */ + for (i = 0; i < length; i += 4) { + bytes24[idx++] = bytes[i + 2]; + bytes24[idx++] = bytes[i + 1]; + bytes24[idx++] = bytes[i + 0]; + } + + kmem_cache_free(tfa->cachep, bytes); + } + + return error; +} + +enum Tfa98xx_Error reg_read(struct tfa_device *tfa, unsigned char subaddress, unsigned short *value) +{ + enum Tfa98xx_Error error; + + error = (tfa->dev_ops.reg_read)(tfa, subaddress, value); + if (error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + return error; +} + +enum Tfa98xx_Error reg_write(struct tfa_device *tfa, unsigned char subaddress, unsigned short value) +{ + enum Tfa98xx_Error error; + + error = (tfa->dev_ops.reg_write)(tfa, subaddress, value); + if (error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + return error; +} + +enum Tfa98xx_Error mem_read(struct tfa_device *tfa, unsigned int start_offset, int num_words, int *pValues) +{ + enum Tfa98xx_Error error; + + error = (tfa->dev_ops.mem_read)(tfa, start_offset, num_words, pValues); + if (error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + return error; +} + +enum Tfa98xx_Error mem_write(struct tfa_device *tfa, unsigned short address, int value, int memtype) +{ + enum Tfa98xx_Error error; + + error = (tfa->dev_ops.mem_write)(tfa, address, value, memtype); + if (error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + return error; +} + + +/* + * write/read raw msg functions : + * the buffer is provided in little endian format, each word occupying 3 bytes, length is in bytes. + * The functions will return immediately and do not not wait for DSP reponse. + */ +#define MAX_WORDS (300) +enum Tfa98xx_Error tfa_dsp_msg(struct tfa_device *tfa, int length, const char *buf) +{ + enum Tfa98xx_Error error; + int tries, rpc_status = Tfa98xx_I2C_Req_Done; + + /* write the message and notify the DSP */ + error = tfa_dsp_msg_write(tfa, length, buf); + if (error != Tfa98xx_Error_Ok) + return error; + + /* get the result from the DSP (polling) */ + for (tries = TFA98XX_WAITRESULT_NTRIES; tries > 0; tries--) { + error = tfa_dsp_msg_status(tfa, &rpc_status); + if (error == Tfa98xx_Error_Ok && rpc_status == Tfa98xx_I2C_Req_Done) + break; + /* If the rpc status is a specific error we want to know it. + * If it is busy or not running it should retry + */ + if (rpc_status != Tfa98xx_I2C_Req_Busy && rpc_status != Tfa98xx_DSP_Not_Running) + break; + } + + if (rpc_status != Tfa98xx_I2C_Req_Done) { + /* DSP RPC call returned an error */ + error = (enum Tfa98xx_Error) (rpc_status + Tfa98xx_Error_RpcBase); + pr_debug("DSP msg status: %d (%s)\n", rpc_status, tfa98xx_get_i2c_status_id_string(rpc_status)); + } + return error; +} + +/** + * write/read raw msg functions: + * the buffer is provided in little endian format, each word occupying 3 bytes, length is in bytes. + * The functions will return immediately and do not not wait for DSP reponse. + * An ID is added to modify the command-ID + */ +enum Tfa98xx_Error tfa_dsp_msg_id(struct tfa_device *tfa, int length, const char *buf, uint8_t cmdid[3]) +{ + enum Tfa98xx_Error error; + int tries, rpc_status = Tfa98xx_I2C_Req_Done; + + /* write the message and notify the DSP */ + error = tfa_dsp_msg_write_id(tfa, length, buf, cmdid); + if (error != Tfa98xx_Error_Ok) + return error; + + /* get the result from the DSP (polling) */ + for (tries = TFA98XX_WAITRESULT_NTRIES; tries > 0; tries--) { + error = tfa_dsp_msg_status(tfa, &rpc_status); + if (error == Tfa98xx_Error_Ok && rpc_status == Tfa98xx_I2C_Req_Done) + break; + } + + if (rpc_status != Tfa98xx_I2C_Req_Done) { + /* DSP RPC call returned an error */ + error = (enum Tfa98xx_Error) (rpc_status + Tfa98xx_Error_RpcBase); + pr_debug("DSP msg status: %d (%s)\n", rpc_status, tfa98xx_get_i2c_status_id_string(rpc_status)); + } + return error; +} + +/* read the return code for the RPC call */ +TFA_INTERNAL enum Tfa98xx_Error +tfa98xx_check_rpc_status(struct tfa_device *tfa, int *pRpcStatus) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + /* the value to sent to the * CF_CONTROLS register: cf_req=00000000, + * cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */ + unsigned short cf_ctrl = 0x0002; + /* memory address to be accessed (0: Status, 1: ID, 2: parameters) */ + unsigned short cf_mad = 0x0000; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + if (pRpcStatus == NULL) + return Tfa98xx_Error_Bad_Parameter; + + /* 1) write DMEM=XMEM to the DSP XMEM */ + { + /* minimize the number of I2C transactions by making use of the autoincrement in I2C */ + unsigned char buffer[4]; + /* first the data for CF_CONTROLS */ + buffer[0] = (unsigned char)((cf_ctrl >> 8) & 0xFF); + buffer[1] = (unsigned char)(cf_ctrl & 0xFF); + /* write the contents of CF_MAD which is the subaddress following CF_CONTROLS */ + buffer[2] = (unsigned char)((cf_mad >> 8) & 0xFF); + buffer[3] = (unsigned char)(cf_mad & 0xFF); + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_CONTROLS, sizeof(buffer), buffer); + } + if (error == Tfa98xx_Error_Ok) { + /* read 1 word (24 bit) from XMEM */ + error = tfa98xx_dsp_read_mem(tfa, 0, 1, pRpcStatus); + } + + return error; +} + +/***************************** xmem only **********************************/ +enum Tfa98xx_Error + tfa98xx_dsp_read_mem(struct tfa_device *tfa, + unsigned int start_offset, int num_words, int *pValues) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned char *bytes; + int burst_size; /* number of words per burst size */ + const int bytes_per_word = 3; + int dmem; + int num_bytes; + int *p; + + bytes = (unsigned char *)kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (bytes == NULL) + return Tfa98xx_Error_Fail; + + /* If no offset is given, assume XMEM! */ + if (((start_offset >> 16) & 0xf) > 0) + dmem = (start_offset >> 16) & 0xf; + else + dmem = Tfa98xx_DMEM_XMEM; + + /* Remove offset from adress */ + start_offset = start_offset & 0xffff; + num_bytes = num_words * bytes_per_word; + p = pValues; + + TFA_SET_BF(tfa, DMEM, (uint16_t)dmem); + error = -TFA_WRITE_REG(tfa, MADD, (unsigned short)start_offset); + if (error != Tfa98xx_Error_Ok) + goto tfa98xx_dsp_read_mem_exit; + + for (; num_bytes > 0;) { + burst_size = ROUND_DOWN(tfa->buffer_size, bytes_per_word); + if (num_bytes < burst_size) + burst_size = num_bytes; + + _ASSERT(burst_size <= sizeof(bytes)); + error = tfa98xx_read_data(tfa, FAM_TFA98XX_CF_MEM, burst_size, bytes); + if (error != Tfa98xx_Error_Ok) + goto tfa98xx_dsp_read_mem_exit; + + tfa98xx_convert_bytes2data(burst_size, bytes, p); + + num_bytes -= burst_size; + p += burst_size / bytes_per_word; + } + +tfa98xx_dsp_read_mem_exit: + kmem_cache_free(tfa->cachep, bytes); + + return error; +} + + +enum Tfa98xx_Error + tfa98xx_dsp_write_mem_word(struct tfa_device *tfa, unsigned short address, int value, int memtype) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned char bytes[3]; + + TFA_SET_BF(tfa, DMEM, (uint16_t)memtype); + + error = -TFA_WRITE_REG(tfa, MADD, address); + if (error != Tfa98xx_Error_Ok) + return error; + + tfa98xx_convert_data2bytes(1, &value, bytes); + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, 3, bytes); + + return error; +} + +enum Tfa98xx_Error tfa_cont_write_filterbank(struct tfa_device *tfa, nxpTfaFilter_t *filter) +{ + unsigned char biquad_index; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + for (biquad_index = 0; biquad_index < 10; biquad_index++) { + if (filter[biquad_index].enabled) { + error = tfa_dsp_cmd_id_write(tfa, MODULE_BIQUADFILTERBANK, + biquad_index + 1, //start @1 + sizeof(filter[biquad_index].biquad.bytes), + filter[biquad_index].biquad.bytes); + } else { + error = Tfa98xx_DspBiquad_Disable(tfa, biquad_index + 1); + } + if (error) + return error; + + } + + return error; +} + +enum Tfa98xx_Error + Tfa98xx_DspBiquad_Disable(struct tfa_device *tfa, int biquad_index) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int coeff_buffer[BIQUAD_COEFF_SIZE]; + unsigned char bytes[3 + BIQUAD_COEFF_SIZE * 3]; + int nr = 0; + + if (biquad_index > TFA98XX_BIQUAD_NUM) + return Tfa98xx_Error_Bad_Parameter; + if (biquad_index < 1) + return Tfa98xx_Error_Bad_Parameter; + + /* make opcode */ + bytes[nr++] = 0; + bytes[nr++] = MODULE_BIQUADFILTERBANK + 128; + bytes[nr++] = (unsigned char)biquad_index; + + + /* set in correct order and format for the DSP */ + coeff_buffer[0] = (int)-8388608; /* -1.0f */ + coeff_buffer[1] = 0; + coeff_buffer[2] = 0; + coeff_buffer[3] = 0; + coeff_buffer[4] = 0; + coeff_buffer[5] = 0; + + /* convert to packed 24 */ + tfa98xx_convert_data2bytes(BIQUAD_COEFF_SIZE, coeff_buffer, &bytes[nr]); + nr += BIQUAD_COEFF_SIZE * 3; + + error = dsp_msg(tfa, nr, (char *)bytes); + + return error; +} + +/* wrapper for dsp_msg that adds opcode */ +enum Tfa98xx_Error tfa_dsp_cmd_id_write(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + const unsigned char data[]) +{ + enum Tfa98xx_Error error; + unsigned char *buffer; + int nr = 0; + + buffer = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (buffer == NULL) + return Tfa98xx_Error_Fail; + + buffer[nr++] = tfa->spkr_select; + buffer[nr++] = module_id + 128; + buffer[nr++] = param_id; + + memcpy(&buffer[nr], data, num_bytes); + nr += num_bytes; + + error = dsp_msg(tfa, nr, (char *)buffer); + + kmem_cache_free(tfa->cachep, buffer); + + return error; +} + +/* wrapper for dsp_msg that adds opcode */ +/* this is as the former tfa98xx_dsp_get_param() */ +enum Tfa98xx_Error tfa_dsp_cmd_id_write_read(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + unsigned char data[]) +{ + enum Tfa98xx_Error error; + unsigned char buffer[3]; + int nr = 0; + + if (num_bytes <= 0) { + pr_debug("Error: The number of READ bytes is smaller or equal to 0! \n"); + return Tfa98xx_Error_Fail; + } + + if ((tfa->is_probus_device) && (tfa->cnt->ndev == 1) && + (param_id == SB_PARAM_GET_RE25C || + param_id == SB_PARAM_GET_LSMODEL || + param_id == SB_PARAM_GET_ALGO_PARAMS)) { + /* Modifying the ID for GetRe25C */ + buffer[nr++] = 4; + } else { + buffer[nr++] = tfa->spkr_select; + } + buffer[nr++] = module_id + 128; + buffer[nr++] = param_id; + + error = dsp_msg(tfa, nr, (char *)buffer); + if (error != Tfa98xx_Error_Ok) + return error; + + /* read the data from the dsp */ + error = dsp_msg_read(tfa, num_bytes, data); + return error; +} + +/* wrapper for dsp_msg that adds opcode and 3 bytes required for coefs */ +enum Tfa98xx_Error tfa_dsp_cmd_id_coefs(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + unsigned char data[]) +{ + enum Tfa98xx_Error error; + unsigned char buffer[2 * 3]; + int nr = 0; + + buffer[nr++] = tfa->spkr_select; + buffer[nr++] = module_id + 128; + buffer[nr++] = param_id; + + buffer[nr++] = 0; + buffer[nr++] = 0; + buffer[nr++] = 0; + + error = dsp_msg(tfa, nr, (char *)buffer); + if (error != Tfa98xx_Error_Ok) + return error; + + /* read the data from the dsp */ + error = dsp_msg_read(tfa, num_bytes, data); + + return error; +} + +/* wrapper for dsp_msg that adds opcode and 3 bytes required for MBDrcDynamics */ +enum Tfa98xx_Error tfa_dsp_cmd_id_MBDrc_dynamics(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int index_subband, + int num_bytes, unsigned char data[]) +{ + enum Tfa98xx_Error error; + unsigned char buffer[2 * 3]; + int nr = 0; + + buffer[nr++] = tfa->spkr_select; + buffer[nr++] = module_id + 128; + buffer[nr++] = param_id; + + buffer[nr++] = 0; + buffer[nr++] = 0; + buffer[nr++] = (unsigned char)index_subband; + + error = dsp_msg(tfa, nr, (char *)buffer); + if (error != Tfa98xx_Error_Ok) + return error; + + /* read the data from the dsp */ + error = dsp_msg_read(tfa, num_bytes, data); + + return error; +} + +enum Tfa98xx_Error + tfa98xx_dsp_write_preset(struct tfa_device *tfa, int length, + const unsigned char *p_preset_bytes) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + if (p_preset_bytes != NULL) { + /* by design: keep the data opaque and no + * interpreting/calculation */ + error = tfa_dsp_cmd_id_write(tfa, MODULE_SPEAKERBOOST, + SB_PARAM_SET_PRESET, length, + p_preset_bytes); + } else { + error = Tfa98xx_Error_Bad_Parameter; + } + return error; +} + +/* + * get features from MTP + */ +enum Tfa98xx_Error + tfa98xx_dsp_get_hw_feature_bits(struct tfa_device *tfa, int *features) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint32_t value; + uint16_t mtpbf; + + /* return the cache data if it's valid */ + if (tfa->hw_feature_bits != -1) { + *features = tfa->hw_feature_bits; + } else { + /* for tfa1 check if we have clock */ + if (tfa->tfa_family == 1) { + int status; + tfa98xx_dsp_system_stable(tfa, &status); + if (!status) { + get_hw_features_from_cnt(tfa, features); + /* skip reading MTP: */ + return (*features == -1) ? Tfa98xx_Error_Fail : Tfa98xx_Error_Ok; + } + mtpbf = 0x850f; /* MTP5 for tfa1,16 bits */ + } else + mtpbf = 0xf907; /* MTP9 for tfa2, 8 bits */ + value = tfa_read_reg(tfa, mtpbf) & 0xffff; + *features = tfa->hw_feature_bits = value; + } + + return error; +} + +enum Tfa98xx_Error + tfa98xx_dsp_get_sw_feature_bits(struct tfa_device *tfa, int features[2]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + const int byte_size = 2 * 3; + unsigned char bytes[2 * 3]; + + /* return the cache data if it's valid */ + if (tfa->sw_feature_bits[0] != -1) { + features[0] = tfa->sw_feature_bits[0]; + features[1] = tfa->sw_feature_bits[1]; + } else { + /* for tfa1 check if we have clock */ + if (tfa->tfa_family == 1) { + int status; + tfa98xx_dsp_system_stable(tfa, &status); + if (!status) { + get_sw_features_from_cnt(tfa, features); + /* skip reading MTP: */ + return (features[0] == -1) ? Tfa98xx_Error_Fail : Tfa98xx_Error_Ok; + } + } + error = tfa_dsp_cmd_id_write_read(tfa, MODULE_FRAMEWORK, + FW_PAR_ID_GET_FEATURE_INFO, byte_size, bytes); + + if (error != Tfa98xx_Error_Ok) { + /* old ROM code may respond with Tfa98xx_Error_RpcParamId */ + return error; + } + + tfa98xx_convert_bytes2data(byte_size, bytes, features); + } + return error; +} + +enum Tfa98xx_Error tfa98xx_dsp_get_state_info(struct tfa_device *tfa, unsigned char bytes[], unsigned int *statesize) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int bSupportFramework = 0; + unsigned int stateSize = 9; + + err = tfa98xx_dsp_support_framework(tfa, &bSupportFramework); + if (err == Tfa98xx_Error_Ok) { + if (bSupportFramework) { + err = tfa_dsp_cmd_id_write_read(tfa, MODULE_FRAMEWORK, + FW_PARAM_GET_STATE, 3 * stateSize, bytes); + } else { + /* old ROM code, ask SpeakerBoost and only do first portion */ + stateSize = 8; + err = tfa_dsp_cmd_id_write_read(tfa, MODULE_SPEAKERBOOST, + SB_PARAM_GET_STATE, 3 * stateSize, bytes); + } + } + + *statesize = stateSize; + + return err; +} + +enum Tfa98xx_Error tfa98xx_dsp_support_drc(struct tfa_device *tfa, int *pbSupportDrc) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + *pbSupportDrc = 0; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + if (tfa->supportDrc != supportNotSet) { + *pbSupportDrc = (tfa->supportDrc == supportYes); + } else { + int featureBits[2]; + + error = tfa98xx_dsp_get_sw_feature_bits(tfa, featureBits); + if (error == Tfa98xx_Error_Ok) { + /* easy case: new API available */ + /* bit=0 means DRC enabled */ + *pbSupportDrc = (featureBits[0] & FEATURE1_DRC) == 0; + } else if (error == Tfa98xx_Error_RpcParamId) { + /* older ROM code, doesn't support it */ + *pbSupportDrc = 0; + error = Tfa98xx_Error_Ok; + } + /* else some other error, return transparently */ + /* pbSupportDrc only changed when error == Tfa98xx_Error_Ok */ + + if (error == Tfa98xx_Error_Ok) { + tfa->supportDrc = *pbSupportDrc ? supportYes : supportNo; + } + } + return error; +} + +enum Tfa98xx_Error + tfa98xx_dsp_support_framework(struct tfa_device *tfa, int *pbSupportFramework) +{ + int featureBits[2] = { 0, 0 }; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + _ASSERT(pbSupportFramework != 0); + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + if (tfa->supportFramework != supportNotSet) { + if (tfa->supportFramework == supportNo) + *pbSupportFramework = 0; + else + *pbSupportFramework = 1; + } else { + error = tfa98xx_dsp_get_sw_feature_bits(tfa, featureBits); + if (error == Tfa98xx_Error_Ok) { + *pbSupportFramework = 1; + tfa->supportFramework = supportYes; + } else { + *pbSupportFramework = 0; + tfa->supportFramework = supportNo; + error = Tfa98xx_Error_Ok; + } + } + + /* *pbSupportFramework only changed when error == Tfa98xx_Error_Ok */ + return error; +} + +enum Tfa98xx_Error + tfa98xx_dsp_write_speaker_parameters(struct tfa_device *tfa, + int length, const unsigned char *p_speaker_bytes) +{ + enum Tfa98xx_Error error; + int bSupportDrc; + + if (p_speaker_bytes != NULL) { + /* by design: keep the data opaque and no + * interpreting/calculation */ + /* Use long WaitResult retry count */ + error = tfa_dsp_cmd_id_write( + tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_LSMODEL, length, + p_speaker_bytes); + } else { + error = Tfa98xx_Error_Bad_Parameter; + } + + if (error != Tfa98xx_Error_Ok) + return error; + + error = tfa98xx_dsp_support_drc(tfa, &bSupportDrc); + if (error != Tfa98xx_Error_Ok) + return error; + + if (bSupportDrc) { + /* Need to set AgcGainInsert back to PRE, + * as the SetConfig forces it to POST */ + uint8_t bytes[3] = { 0, 0, 0 }; + + error = tfa_dsp_cmd_id_write(tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_AGCINS, + 3, + bytes); + } + + return error; +} + +enum Tfa98xx_Error + tfa98xx_dsp_write_config(struct tfa_device *tfa, int length, + const unsigned char *p_config_bytes) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int bSupportDrc; + + error = tfa_dsp_cmd_id_write(tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_CONFIG, length, + p_config_bytes); + if (error != Tfa98xx_Error_Ok) + return error; + + error = tfa98xx_dsp_support_drc(tfa, &bSupportDrc); + if (error != Tfa98xx_Error_Ok) + return error; + + if (bSupportDrc) { + /* Need to set AgcGainInsert back to PRE, + * as the SetConfig forces it to POST */ + uint8_t bytes[3] = { 0, 0, 0 }; + + error = tfa_dsp_cmd_id_write(tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_AGCINS, + 3, + bytes); + } + + return error; +} + +/* load all the parameters for the DRC settings from a file */ +enum Tfa98xx_Error tfa98xx_dsp_write_drc(struct tfa_device *tfa, + int length, const unsigned char *p_drc_bytes) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + if (p_drc_bytes != NULL) { + error = tfa_dsp_cmd_id_write(tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_DRC, length, + p_drc_bytes); + + } else { + error = Tfa98xx_Error_Bad_Parameter; + } + return error; +} + +enum Tfa98xx_Error tfa98xx_powerdown(struct tfa_device *tfa, int powerdown) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + error = TFA_SET_BF(tfa, PWDN, (uint16_t)powerdown); + + if (powerdown) { + /* Workaround for ticket PLMA5337 */ + if (tfa->tfa_family == 2) { + TFA_SET_BF_VOLATILE(tfa, AMPE, 0); + } + } + + return error; +} + +enum Tfa98xx_Error + tfa98xx_select_mode(struct tfa_device *tfa, enum Tfa98xx_Mode mode) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + if (error == Tfa98xx_Error_Ok) { + switch (mode) { + + default: + error = Tfa98xx_Error_Bad_Parameter; + } + } + + return error; +} + +int tfa_set_bf(struct tfa_device *tfa, const uint16_t bf, const uint16_t value) +{ + enum Tfa98xx_Error err; + uint16_t regvalue, msk, oldvalue; + + /* + * bitfield enum: + * - 0..3 : len + * - 4..7 : pos + * - 8..15 : address + */ + uint8_t len = bf & 0x0f; + uint8_t pos = (bf >> 4) & 0x0f; + uint8_t address = (bf >> 8) & 0xff; + + err = reg_read(tfa, address, ®value); + if (err) { + pr_err("Error getting bf :%d \n", -err); + return -err; + } + + oldvalue = regvalue; + msk = ((1 << (len + 1)) - 1) << pos; + regvalue &= ~msk; + regvalue |= value << pos; + + /* Only write when the current register value is not the same as the new value */ + if (oldvalue != regvalue) { + err = reg_write(tfa, address, regvalue); + if (err) { + pr_err("Error setting bf :%d \n", -err); + return -err; + } + } + + return 0; +} + +int tfa_set_bf_volatile(struct tfa_device *tfa, const uint16_t bf, const uint16_t value) +{ + enum Tfa98xx_Error err; + uint16_t regvalue, msk; + + /* + * bitfield enum: + * - 0..3 : len + * - 4..7 : pos + * - 8..15 : address + */ + uint8_t len = bf & 0x0f; + uint8_t pos = (bf >> 4) & 0x0f; + uint8_t address = (bf >> 8) & 0xff; + + err = reg_read(tfa, address, ®value); + if (err) { + pr_err("Error getting bf :%d \n", -err); + return -err; + } + + msk = ((1 << (len + 1)) - 1) << pos; + regvalue &= ~msk; + regvalue |= value << pos; + + err = reg_write(tfa, address, regvalue); + if (err) { + pr_err("Error setting bf :%d \n", -err); + return -err; + } + + return 0; +} + +int tfa_get_bf(struct tfa_device *tfa, const uint16_t bf) +{ + enum Tfa98xx_Error err; + uint16_t regvalue, msk; + uint16_t value; + + /* + * bitfield enum: + * - 0..3 : len + * - 4..7 : pos + * - 8..15 : address + */ + uint8_t len = bf & 0x0f; + uint8_t pos = (bf >> 4) & 0x0f; + uint8_t address = (bf >> 8) & 0xff; + + err = reg_read(tfa, address, ®value); + if (err) { + pr_err("Error getting bf :%d \n", -err); + return -err; + } + + msk = ((1 << (len + 1)) - 1) << pos; + regvalue &= msk; + value = regvalue >> pos; + + return value; +} + +int tfa_set_bf_value(const uint16_t bf, const uint16_t bf_value, uint16_t *p_reg_value) +{ + uint16_t regvalue, msk; + + /* + * bitfield enum: + * - 0..3 : len + * - 4..7 : pos + * - 8..15 : address + */ + uint8_t len = bf & 0x0f; + uint8_t pos = (bf >> 4) & 0x0f; + + regvalue = *p_reg_value; + + msk = ((1 << (len + 1)) - 1) << pos; + regvalue &= ~msk; + regvalue |= bf_value << pos; + + *p_reg_value = regvalue; + + return 0; +} + +uint16_t tfa_get_bf_value(const uint16_t bf, const uint16_t reg_value) +{ + uint16_t msk, value; + + /* + * bitfield enum: + * - 0..3 : len + * - 4..7 : pos + * - 8..15 : address + */ + uint8_t len = bf & 0x0f; + uint8_t pos = (bf >> 4) & 0x0f; + + msk = ((1 << (len + 1)) - 1) << pos; + value = (reg_value & msk) >> pos; + + return value; +} + + +int tfa_write_reg(struct tfa_device *tfa, const uint16_t bf, const uint16_t reg_value) +{ + enum Tfa98xx_Error err; + + /* bitfield enum - 8..15 : address */ + uint8_t address = (bf >> 8) & 0xff; + + err = reg_write(tfa, address, reg_value); + if (err) + return -err; + + return 0; +} + +int tfa_read_reg(struct tfa_device *tfa, const uint16_t bf) +{ + enum Tfa98xx_Error err; + uint16_t regvalue; + + /* bitfield enum - 8..15 : address */ + uint8_t address = (bf >> 8) & 0xff; + + err = reg_read(tfa, address, ®value); + if (err) + return -err; + + return regvalue; +} + +/* + * powerup the coolflux subsystem and wait for it + */ +enum Tfa98xx_Error tfa_cf_powerup(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int tries, status; + + /* power on the sub system */ + TFA_SET_BF_VOLATILE(tfa, PWDN, 0); + + // wait until everything is stable, in case clock has been off + if (tfa->verbose) + pr_info("Waiting for DSP system stable...\n"); + for (tries = CFSTABLE_TRIES; tries > 0; tries--) { + err = tfa98xx_dsp_system_stable(tfa, &status); + _ASSERT(err == Tfa98xx_Error_Ok); + if (status) + break; + else + msleep_interruptible(10); /* wait 10ms to avoid busload */ + } + if (tries == 0) {// timedout + pr_err("DSP subsystem start timed out\n"); + return Tfa98xx_Error_StateTimedOut; + } + + return err; +} + +/* + * Enable/Disable the I2S output for TFA1 devices + * without TDM interface + */ +static enum Tfa98xx_Error tfa98xx_aec_output(struct tfa_device *tfa, int enable) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if ((tfa->daimap & Tfa98xx_DAI_TDM) == Tfa98xx_DAI_TDM) + return err; + + if (tfa->tfa_family == 1) + err = -tfa_set_bf(tfa, TFA1_BF_I2SDOE, (enable != 0)); + else { + pr_err("I2SDOE on unsupported family\n"); + err = Tfa98xx_Error_Not_Supported; + } + + return err; +} + +/* + * Print the current state of the hardware manager + * Device manager status information, man_state from TFA9888_N1B_I2C_regmap_V12 + */ +int is_94_N2_device(struct tfa_device *tfa) +{ + return ((((tfa->rev) & 0xff) == 0x94) && (((tfa->rev >> 8) & 0xff) > 0x1a)); +} +enum Tfa98xx_Error show_current_state(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int manstate = -1; + + if (tfa->tfa_family == 2 && tfa->verbose) { + if (is_94_N2_device(tfa)) + manstate = tfa_get_bf(tfa, TFA9894N2_BF_MANSTATE); + else + manstate = TFA_GET_BF(tfa, MANSTATE); + if (manstate < 0) + return -manstate; + + pr_debug("Current HW manager state: "); + + switch (manstate) { + case 0: + pr_debug("power_down_state \n"); + break; + case 1: + pr_debug("wait_for_source_settings_state \n"); + break; + case 2: + pr_debug("connnect_pll_input_state \n"); + break; + case 3: + pr_debug("disconnect_pll_input_state \n"); + break; + case 4: + pr_debug("enable_pll_state \n"); + break; + case 5: + pr_debug("enable_cgu_state \n"); + break; + case 6: + pr_debug("init_cf_state \n"); + break; + case 7: + pr_debug("enable_amplifier_state \n"); + break; + case 8: + pr_debug("alarm_state \n"); + break; + case 9: + pr_debug("operating_state \n"); + break; + case 10: + pr_debug("mute_audio_state \n"); + break; + case 11: + pr_debug("disable_cgu_pll_state \n"); + break; + default: + pr_debug("Unable to find current state \n"); + break; + } + } + + return err; +} + +enum Tfa98xx_Error tfaGetFwApiVersion(struct tfa_device *tfa, unsigned char *pFirmwareVersion) +{ + enum Tfa98xx_Error err = 0; + char cmd_buf[4]; + int cmd_len, res_len; + + if (tfa == NULL) + return Tfa98xx_Error_Bad_Parameter; + if (!tfa->is_probus_device) { + err = mem_read(tfa, FW_VAR_API_VERSION, 1, (int *)pFirmwareVersion); + if (err) { + pr_debug("%s Error: Unable to get API Version from DSP \n", __FUNCTION__); + return err; + } + } else { + cmd_len = 0x03; + + /* GetAPI: Command is 0x00 0x80 0xFE */ + cmd_buf[0] = 0x00; + cmd_buf[1] = 0x80; + cmd_buf[2] = 0xFE; + + /* Write the command.*/ + + err = tfa98xx_write_dsp(tfa, cmd_len, (const char *)cmd_buf); + + /* Read the API Value.*/ + if (err == 0) { + res_len = 3; + err = tfa98xx_read_dsp(tfa, res_len, (unsigned char *)pFirmwareVersion); + + } + } + return err; + +} + + +/* + * start the speakerboost algorithm + * this implies a full system startup when the system was not already started + * + */ +enum Tfa98xx_Error tfaRunSpeakerBoost(struct tfa_device *tfa, int force, int profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int value; + + if (force) { + err = tfaRunColdStartup(tfa, profile); + if (err) + return err; + } + + /* Returns 1 when device is "cold" and 0 when device is warm */ + value = tfa_is_cold(tfa); + + pr_debug("Startup of device [%s] is a %sstart\n", tfaContDeviceName(tfa->cnt, tfa->dev_idx), value ? "cold" : "warm"); + /* cold start and not tap profile */ + if (value) { + /* Run startup and write all files */ + err = tfaRunSpeakerStartup(tfa, force, profile); + if (err) + return err; + + /* Save the current profile and set the vstep to 0 */ + /* This needs to be overwriten even in CF bypass */ + tfa_dev_set_swprof(tfa, (unsigned short)profile); + tfa_dev_set_swvstep(tfa, 0); + + /* Synchonize I/V delay on 96/97 at cold start */ + if ((tfa->tfa_family == 1) && (tfa->daimap == Tfa98xx_DAI_TDM)) + tfa->sync_iv_delay = 1; + } + + return err; +} + +enum Tfa98xx_Error tfaRunSpeakerStartup(struct tfa_device *tfa, int force, int profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if (!force) { // in case of force CF already runnning + err = tfaRunStartup(tfa, profile); + PRINT_ASSERT(err); + if (err) + return err; + + /* Startup with CF in bypass then return here */ + if (tfa_cf_enabled(tfa) == 0) + return err; + + /* respond to external DSP: -1:none, 0:no_dsp, 1:cold, 2:warm */ + if (tfa->ext_dsp == -1) { + err = tfaRunStartDSP(tfa); + if (err) + return err; + } + } + + /* Set auto_copy_mtp_to_iic (bit 5 of A3) to 1 */ + tfa98xx_auto_copy_mtp_to_iic(tfa); + + err = tfaGetFwApiVersion(tfa, (unsigned char *)&tfa->fw_itf_ver[0]); + if (err) { + pr_debug("[%s] cannot get FWAPI error = %d \n", __FUNCTION__, err); + return err; + } + /* write all the files from the device list */ + err = tfaContWriteFiles(tfa); + if (err) { + pr_debug("[%s] tfaContWriteFiles error = %d \n", __FUNCTION__, err); + return err; + } + + /* write all the files from the profile list (use volumstep 0) */ + err = tfaContWriteFilesProf(tfa, profile, 0); + if (err) { + pr_debug("[%s] tfaContWriteFilesProf error = %d \n", __FUNCTION__, err); + return err; + } + + return err; +} + +/* + * Run calibration + */ +enum Tfa98xx_Error tfaRunSpeakerCalibration(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int calibrateDone; + + /* return if there is no audio running */ + if ((tfa->tfa_family == 2) && TFA_GET_BF(tfa, NOCLK)) + return Tfa98xx_Error_NoClock; + + /* When MTPOTC is set (cal=once) unlock key2 */ + if (TFA_GET_BF(tfa, MTPOTC) == 1) { + tfa98xx_key2(tfa, 0); + } + + /* await calibration, this should return ok */ + err = tfaRunWaitCalibration(tfa, &calibrateDone); + if (err == Tfa98xx_Error_Ok) { + err = tfa_dsp_get_calibration_impedance(tfa); + PRINT_ASSERT(err); + } + + /* When MTPOTC is set (cal=once) re-lock key2 */ + if (TFA_GET_BF(tfa, MTPOTC) == 1) { + tfa98xx_key2(tfa, 1); + } + + return err; +} + +enum Tfa98xx_Error tfaRunColdboot(struct tfa_device *tfa, int state) +{ +#define CF_CONTROL 0x8100 + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int tries = 10; + + /* repeat set ACS bit until set as requested */ + while (state != TFA_GET_BF(tfa, ACS)) { + /* set colstarted in CF_CONTROL to force ACS */ + err = mem_write(tfa, CF_CONTROL, state, Tfa98xx_DMEM_IOMEM); + PRINT_ASSERT(err); + + if (tries-- == 0) { + pr_debug("coldboot (ACS) did not %s\n", state ? "set" : "clear"); + return Tfa98xx_Error_Other; + } + } + + return err; +} + + + +/* + * load the patch if any + * else tell no loaded + */ +static enum Tfa98xx_Error tfa_run_load_patch(struct tfa_device *tfa) +{ + return tfaContWritePatch(tfa); +} + +/* + * this will load the patch witch will implicitly start the DSP + * if no patch is available the DPS is started immediately + */ +enum Tfa98xx_Error tfaRunStartDSP(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + err = tfa_run_load_patch(tfa); + if (err) { /* patch load is fatal so return immediately*/ + return err; + } + + /* Clear count_boot, should be reset to 0 before the DSP reset is released */ + err = mem_write(tfa, 512, 0, Tfa98xx_DMEM_XMEM); + PRINT_ASSERT(err); + + /* Reset DSP once for sure after initializing */ + if (err == Tfa98xx_Error_Ok) { + err = tfa98xx_dsp_reset(tfa, 0); + PRINT_ASSERT(err); + } + + /* Sample rate is needed to set the correct tables */ + err = tfa98xx_dsp_write_tables(tfa, TFA_GET_BF(tfa, AUDFS)); + PRINT_ASSERT(err); + + return err; +} + +/* + * start the clocks and wait until the AMP is switching + * on return the DSP sub system will be ready for loading + */ +enum Tfa98xx_Error tfaRunStartup(struct tfa_device *tfa, int profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + int i, noinit = 0, audfs = 0, fractdel = 0; + + if (dev == NULL) + return Tfa98xx_Error_Fail; + + if (dev->bus) /* no i2c device, do nothing */ + return Tfa98xx_Error_Ok; + + /* process the device list to see if the user implemented the noinit */ + for (i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscNoInit) { + noinit = 1; + break; + } + } + + if (!noinit) { + /* Read AUDFS & FRACTDEL prior to (re)init. */ + audfs = TFA_GET_BF(tfa, AUDFS); + fractdel = TFA_GET_BF(tfa, FRACTDEL); + /* load the optimal TFA98XX in HW settings */ + err = tfa98xx_init(tfa); + PRINT_ASSERT(err); + + /* Restore audfs & fractdel after coldboot, so we can calibrate with correct fs setting. + * in case something else was given in cnt file, profile below will apply this. */ + TFA_SET_BF(tfa, AUDFS, audfs); + TFA_SET_BF(tfa, FRACTDEL, fractdel); + } else { + pr_debug("\nWarning: No init keyword found in the cnt file. Init is skipped! \n"); + } + + /* I2S settings to define the audio input properties + * these must be set before the subsys is up */ + // this will run the list until a non-register item is encountered + err = tfaContWriteRegsDev(tfa); // write device register settings + PRINT_ASSERT(err); + // also write register the settings from the default profile + // NOTE we may still have ACS=1 so we can switch sample rate here + err = tfaContWriteRegsProf(tfa, profile); + PRINT_ASSERT(err); + + /* Factory trimming for the Boost converter */ + tfa98xx_factory_trimmer(tfa); + + /* Go to the initCF state */ + tfa_dev_set_state(tfa, TFA_STATE_INIT_CF, strstr(tfaContProfileName(tfa->cnt, tfa->dev_idx, profile), ".cal") != NULL); + + err = show_current_state(tfa); + + return err; +} + +/* + * run the startup/init sequence and set ACS bit + */ +enum Tfa98xx_Error tfaRunColdStartup(struct tfa_device *tfa, int profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + err = tfaRunStartup(tfa, profile); + PRINT_ASSERT(err); + if (err) + return err; + + if (!tfa->is_probus_device) { + /* force cold boot */ + err = tfaRunColdboot(tfa, 1); // set ACS + PRINT_ASSERT(err); + if (err) + return err; + } + + /* start */ + err = tfaRunStartDSP(tfa); + PRINT_ASSERT(err); + + return err; +} + +/* + * + */ +enum Tfa98xx_Error tfaRunMute(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int status; + int tries = 0; + + /* signal the TFA98XX to mute */ + if (tfa->tfa_family == 1) { + err = tfa98xx_set_mute(tfa, Tfa98xx_Mute_Amplifier); + + if (err == Tfa98xx_Error_Ok) { + /* now wait for the amplifier to turn off */ + do { + status = TFA_GET_BF(tfa, SWS); + if (status != 0) + msleep_interruptible(10); /* wait 10ms to avoid busload */ + else + break; + tries++; + } while (tries < AMPOFFWAIT_TRIES); + + + if (tfa->verbose) + pr_debug("-------------------- muted --------------------\n"); + + /*The amplifier is always switching*/ + if (tries == AMPOFFWAIT_TRIES) + return Tfa98xx_Error_Other; + } + } + + return err; +} +/* + * + */ +enum Tfa98xx_Error tfaRunUnmute(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + /* signal the TFA98XX to mute */ + err = tfa98xx_set_mute(tfa, Tfa98xx_Mute_Off); + + if (tfa->verbose) + pr_debug("-------------------unmuted ------------------\n"); + + return err; +} + +static void individual_calibration_results(struct tfa_device *tfa) +{ + int value_P, value_S; + + /* Read the calibration result in xmem (529=primary channel) (530=secondary channel) */ + mem_read(tfa, 529, 1, &value_P); + mem_read(tfa, 530, 1, &value_S); + + if (value_P != 1 && value_S != 1) + pr_debug("Calibration failed on both channels! \n"); + else if (value_P != 1) { + pr_debug("Calibration failed on Primary (Left) channel! \n"); + TFA_SET_BF_VOLATILE(tfa, SSLEFTE, 0); /* Disable the sound for the left speaker */ + } else if (value_S != 1) { + pr_debug("Calibration failed on Secondary (Right) channel! \n"); + TFA_SET_BF_VOLATILE(tfa, SSRIGHTE, 0); /* Disable the sound for the right speaker */ + } + + TFA_SET_BF_VOLATILE(tfa, AMPINSEL, 0); /* Set amplifier input to TDM */ + TFA_SET_BF_VOLATILE(tfa, SBSL, 1); +} + +/* + * wait for calibrateDone + */ +enum Tfa98xx_Error tfaRunWaitCalibration(struct tfa_device *tfa, int *calibrateDone) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int tries = 0, mtp_busy = 1, tries_mtp_busy = 0; + + *calibrateDone = 0; + + /* in case of calibrate once wait for MTPEX */ + if (TFA_GET_BF(tfa, MTPOTC)) { + // Check if MTP_busy is clear! + while (tries_mtp_busy < MTPBWAIT_TRIES) { + mtp_busy = tfa_dev_get_mtpb(tfa); + if (mtp_busy == 1) + msleep_interruptible(10); /* wait 10ms to avoid busload */ + else + break; + tries_mtp_busy++; + } + + if (tries_mtp_busy < MTPBWAIT_TRIES) { + /* Because of the msleep TFA98XX_API_WAITRESULT_NTRIES is way to long! + * Setting this to 25 will take it atleast 25*50ms = 1.25 sec + */ + while ((*calibrateDone == 0) && (tries < MTPEX_WAIT_NTRIES)) { + *calibrateDone = TFA_GET_BF(tfa, MTPEX); + if (*calibrateDone == 1) + break; + msleep_interruptible(50); /* wait 50ms to avoid busload */ + tries++; + } + + if (tries >= MTPEX_WAIT_NTRIES) { + tries = TFA98XX_API_WAITRESULT_NTRIES; + } + } else { + pr_err("MTP bussy after %d tries\n", MTPBWAIT_TRIES); + } + } + + /* poll xmem for calibrate always + * calibrateDone = 0 means "calibrating", + * calibrateDone = -1 (or 0xFFFFFF) means "fails" + * calibrateDone = 1 means calibration done + */ + while ((*calibrateDone != 1) && (tries < TFA98XX_API_WAITRESULT_NTRIES)) { + err = mem_read(tfa, TFA_FW_XMEM_CALIBRATION_DONE, 1, calibrateDone); + if (*calibrateDone == -1) + break; + tries++; + } + + if (*calibrateDone != 1) { + pr_err("Calibration failed! \n"); + err = Tfa98xx_Error_Bad_Parameter; + } else if (tries == TFA98XX_API_WAITRESULT_NTRIES) { + pr_debug("Calibration has timedout! \n"); + err = Tfa98xx_Error_StateTimedOut; + } else if (tries_mtp_busy == 1000) { + pr_err("Calibrate Failed: MTP_busy stays high! \n"); + err = Tfa98xx_Error_StateTimedOut; + } + + /* Give reason why calibration failed! */ + if (err != Tfa98xx_Error_Ok) { + if ((tfa->tfa_family == 2) && (TFA_GET_BF(tfa, REFCKSEL) == 1)) { + pr_err("Unable to calibrate the device with the internal clock! \n"); + } + } + + /* Check which speaker calibration failed. Only for 88C */ + if ((err != Tfa98xx_Error_Ok) && ((tfa->rev & 0x0FFF) == 0xc88)) { + individual_calibration_results(tfa); + } + + return err; +} + +/* + * tfa_dev_start will only do the basics: Going from powerdown to operating or a profile switch. + * for calibrating or akoustic shock handling use the tfa98xxCalibration function. + */ +enum tfa_error tfa_dev_start(struct tfa_device *tfa, int next_profile, int vstep) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int active_profile = -1; + + /* Get currentprofile */ + active_profile = tfa_dev_get_swprof(tfa); + if (active_profile == 0xff) + active_profile = -1; + /* TfaRun_SpeakerBoost implies un-mute */ + pr_debug("Active_profile:%s, next_profile:%s\n", + tfaContProfileName(tfa->cnt, tfa->dev_idx, active_profile), + tfaContProfileName(tfa->cnt, tfa->dev_idx, next_profile)); + + err = show_current_state(tfa); + + if (tfa->tfa_family == 1) { /* TODO move this to ini file */ + /* Enable I2S output on TFA1 devices without TDM */ + err = tfa98xx_aec_output(tfa, 1); + if (err != Tfa98xx_Error_Ok) + goto error_exit; + } + + if (tfa->bus != 0) { /* non i2c */ +#ifndef __KERNEL__ + tfadsp_fw_start(tfa, next_profile, vstep); +#endif /* __KERNEL__ */ + } else { + /* Check if we need coldstart or ACS is set */ + err = tfaRunSpeakerBoost(tfa, 0, next_profile); + if (err != Tfa98xx_Error_Ok) + goto error_exit; + + /* Make sure internal oscillator is running for DSP devices (non-dsp and max1 this is no-op) */ + tfa98xx_set_osc_powerdown(tfa, 0); + + /* Go to the Operating state */ + tfa_dev_set_state(tfa, TFA_STATE_OPERATING | TFA_STATE_MUTE, 0); + } + active_profile = tfa_dev_get_swprof(tfa); + + /* Profile switching */ + if ((next_profile != active_profile && active_profile >= 0)) { + err = tfaContWriteProfile(tfa, next_profile, vstep); + if (err != Tfa98xx_Error_Ok) + goto error_exit; + } + + /* If the profile contains the .standby suffix go to powerdown + * else we should be in operating state + */ + if (strstr(tfaContProfileName(tfa->cnt, tfa->dev_idx, next_profile), ".standby") != NULL) { + tfa_dev_set_swprof(tfa, (unsigned short)next_profile); + tfa_dev_set_swvstep(tfa, (unsigned short)vstep); + goto error_exit; + } + + err = show_current_state(tfa); + + if ((TFA_GET_BF(tfa, CFE) != 0) && (vstep != tfa->vstep) && (vstep != -1)) { + err = tfaContWriteFilesVstep(tfa, next_profile, vstep); + if (err != Tfa98xx_Error_Ok) + goto error_exit; + } + + + /* Always search and apply filters after a startup */ + err = tfa_set_filters(tfa, next_profile); + if (err != Tfa98xx_Error_Ok) + goto error_exit; + + tfa_dev_set_swprof(tfa, (unsigned short)next_profile); + tfa_dev_set_swvstep(tfa, (unsigned short)vstep); + + /* PLMA5539: Gives information about current setting of powerswitch */ + if (tfa->verbose) { + if (!tfa98xx_powerswitch_is_enabled(tfa)) + pr_info("Device start without powerswitch enabled!\n"); + } + +error_exit: + show_current_state(tfa); + + return err; +} + +enum tfa_error tfa_dev_stop(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + /* mute */ + tfaRunMute(tfa); + + /* Make sure internal oscillator is not running for DSP devices (non-dsp and max1 this is no-op) */ + tfa98xx_set_osc_powerdown(tfa, 1); + + /* powerdown CF */ + err = tfa98xx_powerdown(tfa, 1); + if (err != Tfa98xx_Error_Ok) + return err; + + /* disable I2S output on TFA1 devices without TDM */ + err = tfa98xx_aec_output(tfa, 0); + + return err; +} + +/* + * int registers and coldboot dsp + */ +int tfa_reset(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int state = -1; + int retry_cnt = 0; + + /* Check device state. Print warning if reset is done from other state than powerdown (when verbose) */ + state = tfa_dev_get_state(tfa); + if (tfa->verbose) { + if (((tfa->tfa_family == 1) && state != TFA_STATE_RESET) || + ((tfa->tfa_family == 2) && state != TFA_STATE_POWERDOWN)) { + pr_info("WARNING: Device reset should be performed in POWERDOWN state\n"); + } + } + + /* Split TFA1 behavior from TFA2*/ + if (tfa->tfa_family == 1) { + err = TFA_SET_BF(tfa, I2CR, 1); + if (err) + return err; + err = tfa98xx_powerdown(tfa, 0); + if (err) + return err; + err = tfa_cf_powerup(tfa); + if (err) + return err; + err = tfaRunColdboot(tfa, 1); + if (err) + return err; + err = TFA_SET_BF(tfa, I2CR, 1); + } else { + /* Probus devices needs extra protection to ensure proper reset + behavior, this step is valid only in state other than powerdown */ + if (tfa->is_probus_device && state != TFA_STATE_POWERDOWN) { + err = TFA_SET_BF_VOLATILE(tfa, AMPE, 0); + if (err) + return err; + err = tfa98xx_powerdown(tfa, 1); + if (err) + return err; + } + + err = TFA_SET_BF_VOLATILE(tfa, I2CR, 1); + if (err) + return err; + + /* Restore MANSCONF to POR state */ + err = TFA_SET_BF_VOLATILE(tfa, MANSCONF, 0); + if (err) + return err; + + /* Probus devices HW are already reseted here, + Last step is to send init message to softDSP */ + if (tfa->is_probus_device) { + if (tfa->ext_dsp > 0) { + err = tfa98xx_init_dsp(tfa); + /* ext_dsp status from warm to cold after reset */ + if (tfa->ext_dsp == 2) { + tfa->ext_dsp = 1; + } + } + } else { + /* Restore MANCOLD to POR state */ + TFA_SET_BF_VOLATILE(tfa, MANCOLD, 1); + + /* Coolflux has to be powered on to ensure proper ACS + bit state */ + + /* Powerup CF to access CF io */ + err = tfa98xx_powerdown(tfa, 0); + if (err) + return err; + + /* For clock */ + err = tfa_cf_powerup(tfa); + if (err) + return err; + + /* Force cold boot */ + err = tfaRunColdboot(tfa, 1); /* Set ACS */ + if (err) + return err; + + /* Set PWDN = 1, this will transfer device into powerdown state */ + err = TFA_SET_BF_VOLATILE(tfa, PWDN, 1); + if (err) + return err; + + /* 88 needs SBSL on top of PWDN bit to start transition, + for 92 and 94 this doesn't matter */ + err = TFA_SET_BF_VOLATILE(tfa, SBSL, 1); + if (err) + return err; + + /* Powerdown state should be reached within 1ms */ + for (retry_cnt = 0; retry_cnt < TFA98XX_WAITRESULT_NTRIES; retry_cnt++) { + if (is_94_N2_device(tfa)) + state = tfa_get_bf(tfa, TFA9894N2_BF_MANSTATE); + else + state = TFA_GET_BF(tfa, MANSTATE); + if (state < 0) { + return err; + } + + /* Check for MANSTATE=Powerdown (0) */ + if (state == 0) + break; + msleep_interruptible(2); + } + + /* Reset all I2C registers to default values, + now device state is consistent, same as after powerup */ + err = TFA_SET_BF(tfa, I2CR, 1); + } + } + + return err; +} + +/* + * Write all the bytes specified by num_bytes and data + */ +enum Tfa98xx_Error + tfa98xx_write_data(struct tfa_device *tfa, + unsigned char subaddress, int num_bytes, + const unsigned char data[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + /* subaddress followed by data */ + const int bytes2write = num_bytes + 1; + unsigned char *write_data; + + if (num_bytes > TFA2_MAX_PARAM_SIZE) + return Tfa98xx_Error_Bad_Parameter; + + write_data = (unsigned char *)kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (write_data == NULL) + return Tfa98xx_Error_Fail; + + write_data[0] = subaddress; + memcpy(&write_data[1], data, num_bytes); + + error = tfa98xx_write_raw(tfa, bytes2write, write_data); + + kmem_cache_free(tfa->cachep, write_data); + return error; +} + +/* + * fill the calibration value as milli ohms in the struct + * + * assume that the device has been calibrated + */ +enum Tfa98xx_Error tfa_dsp_get_calibration_impedance(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned char bytes[3 * 2] = { 0 }; + int nr_bytes, i, data[2], calibrateDone, spkr_count = 0, cal_idx = 0; + unsigned int scaled_data; + int tries = 0; + + error = tfa_supported_speakers(tfa, &spkr_count); + + if (tfa_dev_mtp_get(tfa, TFA_MTP_OTC)) { + pr_debug("Getting calibration values from MTP\n"); + + if ((tfa->rev & 0xFF) == 0x88) { + for (i = 0; i < spkr_count; i++) { + if (i == 0) + tfa->mohm[i] = tfa_dev_mtp_get(tfa, TFA_MTP_RE25_PRIM); + else + tfa->mohm[i] = tfa_dev_mtp_get(tfa, TFA_MTP_RE25_SEC); + } + } else { + tfa->mohm[0] = tfa_dev_mtp_get(tfa, TFA_MTP_RE25); + } + } else { + pr_debug("Getting calibration values from Speakerboost\n"); + + /* Make sure the calibrateDone bit is set before getting the values from speakerboost! + * This does not work for 72 (because the dsp cannot set this bit) + */ + if (!tfa->is_probus_device) { + /* poll xmem for calibrate always + * calibrateDone = 0 means "calibrating", + * calibrateDone = -1 (or 0xFFFFFF) means "fails" + * calibrateDone = 1 means calibration done + */ + calibrateDone = 0; + while ((calibrateDone != 1) && (tries < TFA98XX_API_WAITRESULT_NTRIES)) { + error = mem_read(tfa, TFA_FW_XMEM_CALIBRATION_DONE, 1, &calibrateDone); + if (calibrateDone == 1) + break; + tries++; + } + + if (calibrateDone != 1) { + pr_err("Calibration failed! \n"); + error = Tfa98xx_Error_Bad_Parameter; + } else if (tries == TFA98XX_API_WAITRESULT_NTRIES) { + pr_debug("Calibration has timedout! \n"); + error = Tfa98xx_Error_StateTimedOut; + } + } + /* SoftDSP interface differs from hw-dsp interfaces */ + if (tfa->is_probus_device && tfa->cnt->ndev > 1) { + spkr_count = tfa->cnt->ndev; + } + + nr_bytes = spkr_count * 3; + error = tfa_dsp_cmd_id_write_read(tfa, MODULE_SPEAKERBOOST, SB_PARAM_GET_RE25C, nr_bytes, bytes); + if (error == Tfa98xx_Error_Ok) { + tfa98xx_convert_bytes2data(nr_bytes, bytes, data); + + for (i = 0; i < spkr_count; i++) { + + /* for probus devices, calibration values coming from soft-dsp speakerboost, + are ordered in a different way. Re-align to standard representation. */ + cal_idx = i; + if ((tfa->is_probus_device && tfa->dev_idx >= 1)) { + cal_idx = 0; + } + + /* signed data has a limit of 30 Ohm */ + scaled_data = data[i]; + + if (tfa->tfa_family == 2) + tfa->mohm[cal_idx] = (scaled_data * 1000) / TFA2_FW_ReZ_SCALE; + else + tfa->mohm[cal_idx] = (scaled_data * 1000) / TFA1_FW_ReZ_SCALE; + } + } + } + + return error; +} + +/* start count from 1, 0 is invalid */ +int tfa_dev_get_swprof(struct tfa_device *tfa) +{ + return (tfa->dev_ops.get_swprof)(tfa); +} + +int tfa_dev_set_swprof(struct tfa_device *tfa, unsigned short new_value) +{ + return (tfa->dev_ops.set_swprof)(tfa, new_value + 1); +} + +/* same value for all channels + * start count from 1, 0 is invalid */ +int tfa_dev_get_swvstep(struct tfa_device *tfa) +{ + return (tfa->dev_ops.get_swvstep)(tfa); +} + +int tfa_dev_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + return (tfa->dev_ops.set_swvstep)(tfa, new_value + 1); +} + +/* + function overload for MTPB + */ +int tfa_dev_get_mtpb(struct tfa_device *tfa) +{ + return (tfa->dev_ops.get_mtpb)(tfa); +} + +int tfa_is_cold(struct tfa_device *tfa) +{ + int value; + + /* + * check for cold boot status + */ + if (tfa->is_probus_device) { + if (tfa->ext_dsp > 0) { + if (tfa->ext_dsp == 2) + value = 0; // warm + else /* no dsp or cold */ + value = 1; // cold + } else { + value = (TFA_GET_BF(tfa, MANSCONF) == 0); + } + } else { + value = TFA_GET_BF(tfa, ACS); + } + + return value; +} + +int tfa_needs_reset(struct tfa_device *tfa) +{ + int value; + + /* checks if the DSP commands SetAlgoParams and SetMBDrc + * need a DSP reset (now: at coldstart or during calibration) + */ + if (tfa_is_cold(tfa) == 1 || tfa->needs_reset == 1) + value = 1; + else + value = 0; + + return value; +} + +int tfa_cf_enabled(struct tfa_device *tfa) +{ + int value; + + /* For 72 there is no CF */ + if (tfa->is_probus_device) { + value = (tfa->ext_dsp != 0); + } else { + value = TFA_GET_BF(tfa, CFE); + } + + return value; +} + +#define NR_COEFFS 6 +#define NR_BIQUADS 28 +#define BQ_SIZE (3 * NR_COEFFS) +#define DSP_MSG_OVERHEAD 27 + +#pragma pack (push, 1) +struct dsp_msg_all_coeff { + uint8_t select_eq[3]; + uint8_t biquad[NR_BIQUADS][NR_COEFFS][3]; +}; +#pragma pack (pop) + +/* number of biquads for each equalizer */ +static const int eq_biquads[] = { + 10, 10, 2, 2, 2, 2 +}; + +#define NR_EQ (int)(sizeof(eq_biquads) / sizeof(int)) + +enum Tfa98xx_Error dsp_partial_coefficients(struct tfa_device *tfa, uint8_t *prev, uint8_t *next) +{ + uint8_t bq, eq; + int eq_offset; + int new_cost, old_cost; + uint32_t eq_biquad_mask[NR_EQ]; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + struct dsp_msg_all_coeff *data1 = (struct dsp_msg_all_coeff *)prev; + struct dsp_msg_all_coeff *data2 = (struct dsp_msg_all_coeff *)next; + + old_cost = DSP_MSG_OVERHEAD + 3 + sizeof(struct dsp_msg_all_coeff); + new_cost = 0; + + eq_offset = 0; + for (eq = 0; eq < NR_EQ; eq++) { + uint8_t *eq1 = &data1->biquad[eq_offset][0][0]; + uint8_t *eq2 = &data2->biquad[eq_offset][0][0]; + + eq_biquad_mask[eq] = 0; + + if (memcmp(eq1, eq2, BQ_SIZE*eq_biquads[eq]) != 0) { + int nr_bq = 0; + int bq_sz, eq_sz; + + for (bq = 0; bq < eq_biquads[eq]; bq++) { + uint8_t *bq1 = &eq1[bq*BQ_SIZE]; + uint8_t *bq2 = &eq2[bq*BQ_SIZE]; + + if (memcmp(bq1, bq2, BQ_SIZE) != 0) { + eq_biquad_mask[eq] |= (1 << bq); + nr_bq++; + } + } + + bq_sz = (2 * 3 + BQ_SIZE) * nr_bq; + eq_sz = 2 * 3 + BQ_SIZE * eq_biquads[eq]; + + /* dsp message i2c transaction overhead */ + bq_sz += DSP_MSG_OVERHEAD * nr_bq; + eq_sz += DSP_MSG_OVERHEAD; + + if (bq_sz >= eq_sz) { + eq_biquad_mask[eq] = 0xffffffff; + + new_cost += eq_sz; + + } else { + new_cost += bq_sz; + } + } + pr_debug("eq_biquad_mask[%d] = 0x%.8x\n", eq, eq_biquad_mask[eq]); + + eq_offset += eq_biquads[eq]; + } + + pr_debug("cost for writing all coefficients = %d\n", old_cost); + pr_debug("cost for writing changed coefficients = %d\n", new_cost); + + if (new_cost >= old_cost) { + const int buffer_sz = 3 + sizeof(struct dsp_msg_all_coeff); + uint8_t *buffer; + + buffer = kmalloc(buffer_sz, GFP_KERNEL); + if (buffer == NULL) + return Tfa98xx_Error_Fail; + + /* cmd id */ + buffer[0] = 0x00; + buffer[1] = 0x82; + buffer[2] = 0x00; + + /* parameters */ + memcpy(&buffer[3], data2, sizeof(struct dsp_msg_all_coeff)); + + err = dsp_msg(tfa, buffer_sz, (const char *)buffer); + + kfree(buffer); + if (err) + return err; + + } else { + eq_offset = 0; + for (eq = 0; eq < NR_EQ; eq++) { + uint8_t *eq2 = &data2->biquad[eq_offset][0][0]; + + if (eq_biquad_mask[eq] == 0xffffffff) { + const int msg_sz = 6 + BQ_SIZE * eq_biquads[eq]; + uint8_t *msg; + + msg = kmalloc(msg_sz, GFP_KERNEL); + if (msg == NULL) + return Tfa98xx_Error_Fail; + + /* cmd id */ + msg[0] = 0x00; + msg[1] = 0x82; + msg[2] = 0x00; + + /* select eq and bq */ + msg[3] = 0x00; + msg[4] = eq + 1; + msg[5] = 0x00; /* all biquads */ + + /* biquad parameters */ + memcpy(&msg[6], eq2, BQ_SIZE * eq_biquads[eq]); + + err = dsp_msg(tfa, msg_sz, (const char *)msg); + + kfree(msg); + if (err) + return err; + + } else if (eq_biquad_mask[eq] != 0) { + for (bq = 0; bq < eq_biquads[eq]; bq++) { + + if (eq_biquad_mask[eq] & (1 << bq)) { + uint8_t *bq2 = &eq2[bq*BQ_SIZE]; + const int msg_sz = 6 + BQ_SIZE; + uint8_t *msg; + + msg = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (msg == NULL) + return Tfa98xx_Error_Fail; + + /* cmd id */ + msg[0] = 0x00; + msg[1] = 0x82; + msg[2] = 0x00; + + /* select eq and bq*/ + msg[3] = 0x00; + msg[4] = eq + 1; + msg[5] = bq + 1; + + /* biquad parameters */ + memcpy(&msg[6], bq2, BQ_SIZE); + + err = dsp_msg(tfa, msg_sz, (const char *)msg); + + kmem_cache_free(tfa->cachep, msg); + if (err) + return err; + } + } + } + eq_offset += eq_biquads[eq]; + } + } + + return err; +} + +/* fill context info */ +int tfa_dev_probe(int slave, struct tfa_device *tfa) +{ + uint16_t rev; + + tfa->slave_address = (unsigned char)slave; + + /* read revid via low level hal, register 3 */ + if (tfa98xx_read_register16(tfa, 3, &rev) != Tfa98xx_Error_Ok) { + PRINT("\nError: Unable to read revid from slave:0x%02x \n", slave); + return ERR; + } + + tfa->rev = rev; + tfa->dev_idx = -1; + tfa->state = TFA_STATE_UNKNOWN; + tfa->p_regInfo = NULL; + + tfa_set_query_info(tfa); + + tfa->in_use = 1; + + return 0; +} + +enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state, int is_calibration) +{ + enum tfa_error err = tfa_error_ok; + int loop = 50, ready = 0; + int count; + + /* Base states */ + /* Do not change the order of setting bits as this is important! */ + switch (state & 0x0f) { + case TFA_STATE_POWERDOWN: /* PLL in powerdown, Algo up */ + break; + case TFA_STATE_INIT_HW: /* load I2C/PLL hardware setting (~wait2srcsettings) */ + break; + case TFA_STATE_INIT_CF: /* coolflux HW access possible (~initcf) */ + /* Start with SBSL=0 to stay in initCF state */ + if (!tfa->is_probus_device) + TFA_SET_BF(tfa, SBSL, 0); + + /* We want to leave Wait4SrcSettings state for max2 */ + if (tfa->tfa_family == 2) + TFA_SET_BF(tfa, MANSCONF, 1); + + /* And finally set PWDN to 0 to leave powerdown state */ + TFA_SET_BF(tfa, PWDN, 0); + + /* Make sure the DSP is running! */ + do { + err = tfa98xx_dsp_system_stable(tfa, &ready); + if (err != tfa_error_ok) + return err; + if (ready) + break; + } while (loop--); + if (((!tfa->is_probus_device) && (is_calibration)) || ((tfa->rev & 0xff) == 0x13)) { + /* Enable FAIM when clock is stable, to avoid MTP corruption */ + err = tfa98xx_faim_protect(tfa, 1); + if (tfa->verbose) { + pr_debug("FAIM enabled (err:%d).\n", err); + } + } + break; + case TFA_STATE_INIT_FW: /* DSP framework active (~patch loaded) */ + break; + case TFA_STATE_OPERATING: /* Amp and Algo running */ + /* Depending on our previous state we need to set 3 bits */ + TFA_SET_BF(tfa, PWDN, 0); /* Coming from state 0 */ + TFA_SET_BF(tfa, MANSCONF, 1); /* Coming from state 1 */ + if (!tfa->is_probus_device) + TFA_SET_BF(tfa, SBSL, 1); /* Coming from state 6 */ + else + TFA_SET_BF(tfa, AMPE, 1); /* No SBSL for probus device, we set AMPE to 1 */ + + /* + * Disable MTP clock to protect memory. + * However in case of calibration wait for DSP! (This should be case only during calibration). + */ + if (TFA_GET_BF(tfa, MTPOTC) == 1 && tfa->tfa_family == 2) { + count = MTPEX_WAIT_NTRIES * 4; /* Calibration takes a lot of time */ + while ((TFA_GET_BF(tfa, MTPEX) != 1) && count) { + msleep_interruptible(10); + count--; + } + } + if (((!tfa->is_probus_device) && (is_calibration)) || ((tfa->rev & 0xff) == 0x13)) { + err = tfa98xx_faim_protect(tfa, 0); + if (tfa->verbose) { + pr_debug("FAIM disabled (err:%d).\n", err); + } + } + /* Synchonize I/V delay on 96/97 at cold start */ + if (tfa->sync_iv_delay) { + if (tfa->verbose) + pr_debug("syncing I/V delay for %x\n", + (tfa->rev & 0xff)); + + /* wait for ACS to be cleared */ + count = 10; + while ((TFA_GET_BF(tfa, ACS) == 1) && + (count-- > 0)) { + msleep_interruptible(1); + } + + tfa98xx_dsp_reset(tfa, 1); + tfa98xx_dsp_reset(tfa, 0); + tfa->sync_iv_delay = 0; + } + break; + case TFA_STATE_FAULT: /* An alarm or error occurred */ + break; + case TFA_STATE_RESET: /* I2C reset and ACS set */ + tfa98xx_init(tfa); + break; + default: + if (state & 0x0f) + return tfa_error_bad_param; + } + + /* state modifiers */ + + if (state & TFA_STATE_MUTE) + tfa98xx_set_mute(tfa, Tfa98xx_Mute_Amplifier); + + if (state & TFA_STATE_UNMUTE) + tfa98xx_set_mute(tfa, Tfa98xx_Mute_Off); + + tfa->state = state; + + return tfa_error_ok; +} + +enum tfa_state tfa_dev_get_state(struct tfa_device *tfa) +{ + int cold = 0; + int manstate; + + /* different per family type */ + if (tfa->tfa_family == 1) { + cold = TFA_GET_BF(tfa, ACS); + if (cold && TFA_GET_BF(tfa, PWDN)) + tfa->state = TFA_STATE_RESET; + else if (!cold && TFA_GET_BF(tfa, SWS)) + tfa->state = TFA_STATE_OPERATING; + } else /* family 2 */ { + if (is_94_N2_device(tfa)) + manstate = tfa_get_bf(tfa, TFA9894N2_BF_MANSTATE); + else + manstate = TFA_GET_BF(tfa, MANSTATE); + switch (manstate) { + case 0: + tfa->state = TFA_STATE_POWERDOWN; + break; + case 8: /* if dsp reset if off assume framework is running */ + tfa->state = TFA_GET_BF(tfa, RST) ? TFA_STATE_INIT_CF : TFA_STATE_INIT_FW; + break; + case 9: + tfa->state = TFA_STATE_OPERATING; + break; + default: + break; + } + } + + return tfa->state; +} + +int tfa_dev_mtp_get(struct tfa_device *tfa, enum tfa_mtp item) +{ + int value = 0; + + switch (item) { + case TFA_MTP_OTC: + value = TFA_GET_BF(tfa, MTPOTC); + break; + case TFA_MTP_EX: + value = TFA_GET_BF(tfa, MTPEX); + break; + case TFA_MTP_RE25: + case TFA_MTP_RE25_PRIM: + if (tfa->tfa_family == 2) { + if ((tfa->rev & 0xFF) == 0x88) + value = TFA_GET_BF(tfa, R25CL); + else if ((tfa->rev & 0xFF) == 0x13) + value = tfa_get_bf(tfa, TFA9912_BF_R25C); + else + value = TFA_GET_BF(tfa, R25C); + } else { + reg_read(tfa, 0x83, (unsigned short *)&value); + } + break; + case TFA_MTP_RE25_SEC: + if ((tfa->rev & 0xFF) == 0x88) { + value = TFA_GET_BF(tfa, R25CR); + } else { + pr_debug("Error: Current device has no secondary Re25 channel \n"); + } + break; + case TFA_MTP_LOCK: + break; + } + + return value; +} + +enum tfa_error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, int value) +{ + enum tfa_error err = tfa_error_ok; + + switch (item) { + case TFA_MTP_OTC: + err = tfa98xx_set_mtp(tfa, (uint16_t)value, TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MSK); + break; + case TFA_MTP_EX: + err = tfa98xx_set_mtp(tfa, (uint16_t)value, TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK); + break; + case TFA_MTP_RE25: + case TFA_MTP_RE25_PRIM: + if (tfa->tfa_family == 2) { + tfa98xx_key2(tfa, 0); /* unlock */ + if ((tfa->rev & 0xFF) == 0x88) + TFA_SET_BF(tfa, R25CL, (uint16_t)value); + else { + if (tfa->is_probus_device == 1 && TFA_GET_BF(tfa, MTPOTC) == 1) + tfa2_manual_mtp_cpy(tfa, 0xF4, value, 2); + TFA_SET_BF(tfa, R25C, (uint16_t)value); + } + tfa98xx_key2(tfa, 1); /* lock */ + } + break; + case TFA_MTP_RE25_SEC: + if ((tfa->rev & 0xFF) == 0x88) { + TFA_SET_BF(tfa, R25CR, (uint16_t)value); + } else { + pr_debug("Error: Current device has no secondary Re25 channel \n"); + err = tfa_error_bad_param; + } + break; + case TFA_MTP_LOCK: + break; + } + + return err; +} + +int tfa_get_pga_gain(struct tfa_device *tfa) +{ + return TFA_GET_BF(tfa, SAAMGAIN); +} + +int tfa_set_pga_gain(struct tfa_device *tfa, uint16_t value) +{ + + return TFA_SET_BF(tfa, SAAMGAIN, value); +} + +int tfa_get_noclk(struct tfa_device *tfa) +{ + return TFA_GET_BF(tfa, NOCLK); +} + + +enum Tfa98xx_Error tfa_status(struct tfa_device *tfa) +{ + int value; + uint16_t val; + + /* + * check IC status bits: cold start + * and DSP watch dog bit to re init + */ + value = TFA_READ_REG(tfa, VDDS); /* STATUSREG */ + if (value < 0) + return -value; + val = (uint16_t)value; + + /* pr_debug("SYS_STATUS0: 0x%04x\n", val); */ + if (TFA_GET_BF_VALUE(tfa, ACS, val) || + TFA_GET_BF_VALUE(tfa, WDS, val)) { + + if (TFA_GET_BF_VALUE(tfa, ACS, val)) + pr_err("ERROR: ACS\n"); + if (TFA_GET_BF_VALUE(tfa, WDS, val)) + pr_err("ERROR: WDS\n"); + + return Tfa98xx_Error_DSP_not_running; + } + + if (TFA_GET_BF_VALUE(tfa, SPKS, val)) + pr_err("ERROR: SPKS\n"); + if (!TFA_GET_BF_VALUE(tfa, SWS, val)) + pr_err("ERROR: SWS\n"); + + /* Check secondary errors */ + if (!TFA_GET_BF_VALUE(tfa, CLKS, val) || + !TFA_GET_BF_VALUE(tfa, UVDS, val) || + !TFA_GET_BF_VALUE(tfa, OVDS, val) || + !TFA_GET_BF_VALUE(tfa, OTDS, val) || + !TFA_GET_BF_VALUE(tfa, PLLS, val) || + (!(tfa->daimap & Tfa98xx_DAI_TDM) && + !TFA_GET_BF_VALUE(tfa, VDDS, val))) + pr_err("Misc errors detected: STATUS_FLAG0 = 0x%x\n", val); + + if ((tfa->daimap & Tfa98xx_DAI_TDM) && (tfa->tfa_family == 2)) { + value = TFA_READ_REG(tfa, TDMERR); /* STATUS_FLAGS1 */ + if (value < 0) + return -value; + val = (uint16_t)value; + if (TFA_GET_BF_VALUE(tfa, TDMERR, val) || + TFA_GET_BF_VALUE(tfa, TDMLUTER, val)) + pr_err("TDM related errors: STATUS_FLAG1 = 0x%x\n", val); + } + + return Tfa98xx_Error_Ok; +} + +int tfa_plop_noise_interrupt(struct tfa_device *tfa, int profile, int vstep) +{ + enum Tfa98xx_Error err; + int no_clk = 0; + + /* Remove sticky bit by reading it once */ + TFA_GET_BF(tfa, NOCLK); + + /* No clock detected */ + if (tfa_irq_get(tfa, tfa9912_irq_stnoclk)) { + no_clk = TFA_GET_BF(tfa, NOCLK); + + /* Detect for clock is lost! (clock is not stable) */ + if (no_clk == 1) { + /* Clock is lost. Set I2CR to remove POP noise */ + pr_info("No clock detected. Resetting the I2CR to avoid pop on 72! \n"); + err = tfa_dev_start(tfa, profile, vstep); + if (err != Tfa98xx_Error_Ok) { + pr_err("Error loading i2c registers (tfa_dev_start), err=%d\n", err); + } else { + pr_info("Setting i2c registers after I2CR succesfull\n"); + tfa_dev_set_state(tfa, TFA_STATE_UNMUTE, 0); + } + + /* Remove sticky bit by reading it once */ + tfa_get_noclk(tfa); + + /* This is only for SAAM on the 72. + Since the NOCLK interrupt is only enabled for 72 this is the place + However: Not tested yet! But also does not harm normal flow! + */ + if (strstr(tfaContProfileName(tfa->cnt, tfa->dev_idx, profile), ".saam")) { + pr_info("Powering down from a SAAM profile, workaround PLMA4766 used! \n"); + TFA_SET_BF(tfa, PWDN, 1); + TFA_SET_BF(tfa, AMPE, 0); + TFA_SET_BF(tfa, SAMMODE, 0); + } + } + + /* If clk is stable set polarity to check for LOW (no clock)*/ + tfa_irq_set_pol(tfa, tfa9912_irq_stnoclk, (no_clk == 0)); + + /* clear interrupt */ + tfa_irq_clear(tfa, tfa9912_irq_stnoclk); + } + + /* return no_clk to know we called tfa_dev_start */ + return no_clk; +} + +void tfa_lp_mode_interrupt(struct tfa_device *tfa) +{ + const int irq_stclp0 = 36; /* FIXME: this 72 interrupt does not excist for 9912 */ + int lp0, lp1; + + if (tfa_irq_get(tfa, irq_stclp0)) { + lp0 = TFA_GET_BF(tfa, LP0); + if (lp0 > 0) { + pr_info("lowpower mode 0 detected\n"); + } else { + pr_info("lowpower mode 0 not detected\n"); + } + + tfa_irq_set_pol(tfa, irq_stclp0, (lp0 == 0)); + + /* clear interrupt */ + tfa_irq_clear(tfa, irq_stclp0); + } + + if (tfa_irq_get(tfa, tfa9912_irq_stclpr)) { + lp1 = TFA_GET_BF(tfa, LP1); + if (lp1 > 0) { + pr_info("lowpower mode 1 detected\n"); + } else { + pr_info("lowpower mode 1 not detected\n"); + } + + tfa_irq_set_pol(tfa, tfa9912_irq_stclpr, (lp1 == 0)); + + /* clear interrupt */ + tfa_irq_clear(tfa, tfa9912_irq_stclpr); + } +} diff --git a/sound/soc/codecs/tfa_dsp_fw.h b/sound/soc/codecs/tfa_dsp_fw.h new file mode 100644 index 000000000000..dd48949c53ab --- /dev/null +++ b/sound/soc/codecs/tfa_dsp_fw.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA98XX_INTERNALS_H +#define TFA98XX_INTERNALS_H + +#include "config.h" + +#include "tfa_service.h" //TODO cleanup for enum Tfa98xx_Status_ID + +/** + * Return a text version of the firmware status ID code + * @param status the given status ID code + * @return the firmware status ID string + */ +const char *tfadsp_fw_status_string(enum Tfa98xx_Status_ID status); +int tfadsp_fw_start(struct tfa_device *tfa, int prof_idx, int vstep_idx); +int tfadsp_fw_get_api_version(struct tfa_device *tfa, uint8_t *buffer); +#define FW_MAXTAG 150 +int tfadsp_fw_get_tag(struct tfa_device *tfa, uint8_t *buffer); +int tfadsp_fw_get_status_change(struct tfa_device *tfa, uint8_t *buffer); +int tfadsp_fw_set_re25(struct tfa_device *tfa, int prim, int sec); +int tfadsp_fw_get_re25(struct tfa_device *tfa, uint8_t *buffer); + +/* + * the order matches the ACK bits order in TFA98XX_CF_STATUS + */ +enum tfa_fw_event { /* not all available on each device */ + tfa_fw_i2c_cmd_ack, + tfa_fw_reset_start, + tfa_fw_short_on_mips, + tfa_fw_soft_mute_ready, + tfa_fw_volume_ready, + tfa_fw_error_damage, + tfa_fw_calibrate_done, + tfa_fw_max +}; + +/* the following type mappings are compiler specific */ +#define subaddress_t unsigned char + +/* module Ids */ +#define MODULE_FRAMEWORK 0 +#define MODULE_SPEAKERBOOST 1 +#define MODULE_BIQUADFILTERBANK 2 +#define MODULE_TAPTRIGGER 5 +#define MODULE_SETRE 9 + +/* RPC commands */ +/* SET */ +#define FW_PAR_ID_SET_MEMORY 0x03 +#define FW_PAR_ID_SET_SENSES_DELAY 0x04 +#define FW_PAR_ID_SETSENSESCAL 0x05 +#define FW_PAR_ID_SET_INPUT_SELECTOR 0x06 +#define FW_PAR_ID_SET_OUTPUT_SELECTOR 0x08 +#define FW_PAR_ID_SET_PROGRAM_CONFIG 0x09 +#define FW_PAR_ID_SET_GAINS 0x0A +#define FW_PAR_ID_SET_MEMTRACK 0x0B +#define FW_PAR_ID_SET_FWKUSECASE 0x11 +#define TFA1_FW_PAR_ID_SET_CURRENT_DELAY 0x03 +#define TFA1_FW_PAR_ID_SET_CURFRAC_DELAY 0x06 +/* GET */ +#define FW_PAR_ID_GET_MEMORY 0x83 +#define FW_PAR_ID_GLOBAL_GET_INFO 0x84 +#define FW_PAR_ID_GET_FEATURE_INFO 0x85 +#define FW_PAR_ID_GET_MEMTRACK 0x8B +#define FW_PAR_ID_GET_TAG 0xFF +#define FW_PAR_ID_GET_API_VERSION 0xFE +#define FW_PAR_ID_GET_STATUS_CHANGE 0x8D + +/* Load a full model into SpeakerBoost. */ +/* SET */ +#define SB_PARAM_SET_ALGO_PARAMS 0x00 +#define SB_PARAM_SET_LAGW 0x01 +#define SB_PARAM_SET_ALGO_PARAMS_WITHOUT_RESET 0x02 +#define SB_PARAM_SET_RE25C 0x05 +#define SB_PARAM_SET_LSMODEL 0x06 +#define SB_PARAM_SET_MBDRC 0x07 +#define SB_PARAM_SET_MBDRC_WITHOUT_RESET 0x08 +#define SB_PARAM_SET_EXCURSION_FILTERS 0x0A +#define SB_PARAM_SET_DRC 0x0F +/* GET */ +#define SB_PARAM_GET_ALGO_PARAMS 0x80 +#define SB_PARAM_GET_LAGW 0x81 +#define SB_PARAM_GET_RE25C 0x85 +#define SB_PARAM_GET_LSMODEL 0x86 +#define SB_PARAM_GET_MBDRC 0x87 +#define SB_PARAM_GET_MBDRC_DYNAMICS 0x89 +#define SB_PARAM_GET_EXCURSION_FILTERS 0x8A +#define SB_PARAM_GET_TAG 0xFF + +#define SB_PARAM_SET_EQ 0x0A /* 2 Equaliser Filters. */ +#define SB_PARAM_SET_PRESET 0x0D /* Load a preset */ +#define SB_PARAM_SET_CONFIG 0x0E /* Load a config */ +#define SB_PARAM_SET_AGCINS 0x10 +#define SB_PARAM_SET_CURRENT_DELAY 0x03 +#define SB_PARAM_GET_STATE 0xC0 +#define SB_PARAM_GET_XMODEL 0xC1 /* Gets current Excursion Model. */ +#define SB_PARAM_GET_XMODEL_COEFFS 0x8C /* Get coefficients for XModel */ +#define SB_PARAM_GET_EXCURSION_FILTERS 0x8A /* Get excursion filters */ +#define SB_PARAM_SET_EXCURSION_FILTERS 0x0A /* Set excursion filters */ + +/* SET: TAPTRIGGER */ +#define TAP_PARAM_SET_ALGO_PARAMS 0x01 +#define TAP_PARAM_SET_DECIMATION_PARAMS 0x02 + +/* GET: TAPTRIGGER*/ +#define TAP_PARAM_GET_ALGO_PARAMS 0x81 +#define TAP_PARAM_GET_TAP_RESULTS 0x84 + +/* sets the speaker calibration impedance (@25 degrees celsius) */ +#define SB_PARAM_SET_RE0 0x89 + +#define BFB_PAR_ID_SET_COEFS 0x00 +#define BFB_PAR_ID_GET_COEFS 0x80 +#define BFB_PAR_ID_GET_CONFIG 0x81 + +/* for compatibility */ +#define FW_PARAM_GET_STATE FW_PAR_ID_GLOBAL_GET_INFO +#define FW_PARAM_GET_FEATURE_BITS FW_PAR_ID_GET_FEATURE_BITS + +/* RPC Status results */ +#define STATUS_OK 0 +#define STATUS_INVALID_MODULE_ID 2 +#define STATUS_INVALID_PARAM_ID 3 +#define STATUS_INVALID_INFO_ID 4 + +/* the maximum message length in the communication with the DSP */ +#define TFA2_MAX_PARAM_SIZE (507*3) /* TFA2 */ +#define TFA1_MAX_PARAM_SIZE (145*3) /* TFA1 */ + +#define ROUND_DOWN(a, n) (((a)/(n))*(n)) + +/* feature bits */ +#define FEATURE1_TCOEF 0x100 /* bit8 set means tCoefA expected */ +#define FEATURE1_DRC 0x200 /* bit9 NOT set means DRC expected */ + +/* DSP firmware xmem defines */ +#define TFA1_FW_XMEM_CALIBRATION_DONE 231 +#define TFA2_FW_XMEM_CALIBRATION_DONE 516 +#define TFA1_FW_XMEM_COUNT_BOOT 0xa1 +#define TFA2_FW_XMEM_COUNT_BOOT 512 +#define TFA2_FW_XMEM_CMD_COUNT 520 + +/* note that the following defs rely on the handle variable */ +#define TFA_FW_XMEM_CALIBRATION_DONE TFA_FAM_FW(tfa, XMEM_CALIBRATION_DONE) +#define TFA_FW_XMEM_COUNT_BOOT TFA_FAM_FW(tfa, XMEM_COUNT_BOOT) +#define TFA_FW_XMEM_CMD_COUNT TFA_FAM_FW(tfa, XMEM_CMD_COUNT) + +#define TFA2_FW_ReZ_SCALE 65536 +#define TFA1_FW_ReZ_SCALE 16384 + +#endif /* TFA98XX_INTERNALS_H */ diff --git a/sound/soc/codecs/tfa_ext.h b/sound/soc/codecs/tfa_ext.h new file mode 100644 index 000000000000..5ded093de4f8 --- /dev/null +++ b/sound/soc/codecs/tfa_ext.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA_SRC_TFA_EXT_H_ +#define TFA_SRC_TFA_EXT_H_ + +#include "tfa_device.h" + +/* + * events + */ +/** Maximum value for enumerator */ +#define LVM_MAXENUM (0xffff) +/** +This enum type specifies the different events that may trigger a callback. +*/ +enum tfadsp_event_en { + TFADSP_CMD_ACK = 1, /**< Command handling is completed */ + TFADSP_SOFT_MUTE_READY = 8, /**< Muting completed */ + TFADSP_VOLUME_READY = 16, /**< Volume change completed */ + TFADSP_DAMAGED_SPEAKER = 32, /**< Damaged speaker was detected */ + TFADSP_CALIBRATE_DONE = 64, /**< Calibration is completed */ + TFADSP_SPARSESIG_DETECTED = 128, /**< Sparse signal detected */ + TFADSP_CMD_READY = 256, /**< Ready to receive commands */ + TFADSP_EXT_PWRUP = 0x8000,/**< DSP API has started, powered up */ + TFADSP_EXT_PWRDOWN = 0x8001,/**< DSP API stopped, power down */ + TFADSP_EVENT_DUMMY = LVM_MAXENUM +} ; + +typedef int (*tfa_event_handler_t)(struct tfa_device *tfa, enum tfadsp_event_en tfadsp_event); +typedef int (*dsp_send_message_t)(struct tfa_device *tfa, int length, const char *buf); +typedef int (*dsp_read_message_t)(struct tfa_device *tfa, int length, char *buf); +typedef int (*dsp_write_reg_t)(struct tfa_device *tfa, unsigned char subaddress, unsigned short value); + +int tfa_ext_register(dsp_write_reg_t tfa_write_reg, dsp_send_message_t tfa_send_message, dsp_read_message_t tfa_read_message, tfa_event_handler_t *tfa_event_handler); + +#endif /* TFA_SRC_TFA_EXT_H_ */ diff --git a/sound/soc/codecs/tfa_init.c b/sound/soc/codecs/tfa_init.c new file mode 100644 index 000000000000..1ced553714ab --- /dev/null +++ b/sound/soc/codecs/tfa_init.c @@ -0,0 +1,1783 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#include "dbgprint.h" +#include "tfa_service.h" +#include "tfa_internal.h" +#include "tfa_container.h" +#include "tfa98xx_tfafieldnames.h" + + /* The CurrentSense4 registers are not in the datasheet */ +#define TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF (1<<2) +#define TFA98XX_CURRENTSENSE4 0x49 + +/***********************************************************************************/ +/* GLOBAL (Defaults) */ +/***********************************************************************************/ +static enum Tfa98xx_Error no_overload_function_available(struct tfa_device *tfa, int not_used) +{ + (void)tfa; + (void)not_used; + + return Tfa98xx_Error_Ok; +} + +static enum Tfa98xx_Error no_overload_function_available2(struct tfa_device *tfa) +{ + (void)tfa; + + return Tfa98xx_Error_Ok; +} + +/* tfa98xx_dsp_system_stable +* return: *ready = 1 when clocks are stable to allow DSP subsystem access +*/ +static enum Tfa98xx_Error tfa_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short status; + int value; + + /* check the contents of the STATUS register */ + value = TFA_READ_REG(tfa, AREFS); + if (value < 0) { + error = -value; + *ready = 0; + _ASSERT(error); /* an error here can be fatal */ + return error; + } + status = (unsigned short)value; + + /* check AREFS and CLKS: not ready if either is clear */ + *ready = !((TFA_GET_BF_VALUE(tfa, AREFS, status) == 0) + || (TFA_GET_BF_VALUE(tfa, CLKS, status) == 0)); + + return error; +} + +/* tfa98xx_toggle_mtp_clock + * Allows to stop clock for MTP/FAim needed for PLMA5505 */ +static enum Tfa98xx_Error tfa_faim_protect(struct tfa_device *tfa, int state) +{ + (void)tfa; + (void)state; + + return Tfa98xx_Error_Ok; +} + +/** Set internal oscillator into power down mode. + * + * This function is a worker for tfa98xx_set_osc_powerdown(). + * + * @param[in] tfa device description structure + * @param[in] state new state 0 - oscillator is on, 1 oscillator is off. + * + * @return Tfa98xx_Error_Ok when successfull, error otherwise. + */ +static enum Tfa98xx_Error tfa_set_osc_powerdown(struct tfa_device *tfa, int state) +{ + /* This function has no effect in general case, only for tfa9912 */ + (void)tfa; + (void)state; + + return Tfa98xx_Error_Ok; +} +static enum Tfa98xx_Error tfa_update_lpm(struct tfa_device *tfa, int state) +{ + /* This function has no effect in general case, only for tfa9912 */ + (void)tfa; + (void)state; + + return Tfa98xx_Error_Ok; +} +static enum Tfa98xx_Error tfa_dsp_reset(struct tfa_device *tfa, int state) +{ + /* generic function */ + TFA_SET_BF_VOLATILE(tfa, RST, (uint16_t)state); + + return Tfa98xx_Error_Ok; +} + +int tfa_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int mtpk, active_value = tfa->profile; + + /* Also set the new value in the struct */ + tfa->profile = new_value - 1; + + /* for TFA1 devices */ + /* it's in MTP shadow, so unlock if not done already */ + mtpk = TFA_GET_BF(tfa, MTPK); /* get current key */ + TFA_SET_BF_VOLATILE(tfa, MTPK, 0x5a); + TFA_SET_BF_VOLATILE(tfa, SWPROFIL, new_value); /* set current profile */ + TFA_SET_BF_VOLATILE(tfa, MTPK, (uint16_t)mtpk); /* restore key */ + + return active_value; +} + +static int tfa_get_swprofile(struct tfa_device *tfa) +{ + return TFA_GET_BF(tfa, SWPROFIL) - 1; +} + +static int tfa_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + int mtpk, active_value = tfa->vstep; + + /* Also set the new value in the struct */ + tfa->vstep = new_value - 1; + + /* for TFA1 devices */ + /* it's in MTP shadow, so unlock if not done already */ + mtpk = TFA_GET_BF(tfa, MTPK); /* get current key */ + TFA_SET_BF_VOLATILE(tfa, MTPK, 0x5a); + TFA_SET_BF_VOLATILE(tfa, SWVSTEP, new_value); /* set current vstep */ + TFA_SET_BF_VOLATILE(tfa, MTPK, (uint16_t)mtpk); /* restore key */ + + return active_value; +} + +static int tfa_get_swvstep(struct tfa_device *tfa) +{ + int value = 0; + /* Set the new value in the hw register */ + value = TFA_GET_BF(tfa, SWVSTEP); + + /* Also set the new value in the struct */ + tfa->vstep = value - 1; + + return value - 1; /* invalid if 0 */ +} + +static int tfa_get_mtpb(struct tfa_device *tfa) +{ + + int value = 0; + + /* Set the new value in the hw register */ + value = TFA_GET_BF(tfa, MTPB); + + return value; +} + +static enum Tfa98xx_Error +tfa_set_mute_nodsp(struct tfa_device *tfa, int mute) +{ + (void)tfa; + (void)mute; + + return Tfa98xx_Error_Ok; +} + +void set_ops_defaults(struct tfa_device_ops *ops) +{ + /* defaults */ + ops->reg_read = tfa98xx_read_register16; + ops->reg_write = tfa98xx_write_register16; + ops->mem_read = tfa98xx_dsp_read_mem; + ops->mem_write = tfa98xx_dsp_write_mem_word; + ops->dsp_msg = tfa_dsp_msg; + ops->dsp_msg_read = tfa_dsp_msg_read; + ops->dsp_write_tables = no_overload_function_available; + ops->dsp_reset = tfa_dsp_reset; + ops->dsp_system_stable = tfa_dsp_system_stable; + ops->auto_copy_mtp_to_iic = no_overload_function_available2; + ops->factory_trimmer = no_overload_function_available2; + ops->set_swprof = tfa_set_swprofile; + ops->get_swprof = tfa_get_swprofile; + ops->set_swvstep = tfa_set_swvstep; + ops->get_swvstep = tfa_get_swvstep; + ops->get_mtpb = tfa_get_mtpb; + ops->set_mute = tfa_set_mute_nodsp; + ops->faim_protect = tfa_faim_protect; + ops->set_osc_powerdown = tfa_set_osc_powerdown; + ops->update_lpm = tfa_update_lpm; +} + +/***********************************************************************************/ +/* no TFA + * external DSP SB instance */ + /***********************************************************************************/ +static short tfanone_swvstep, swprof; //TODO emulate in hal plugin +static enum Tfa98xx_Error tfanone_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + (void)tfa; /* suppress warning */ + *ready = 1; /* assume always ready */ + + return Tfa98xx_Error_Ok; +} + +static int tfanone_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + swprof = new_value; + + return active_value; +} + +static int tfanone_get_swprofile(struct tfa_device *tfa) +{ + (void)tfa; /* suppress warning */ + return swprof; +} + +static int tfanone_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + /* Set the new value in the struct */ + tfa->vstep = new_value - 1; + + /* Set the new value in the hw register */ + tfanone_swvstep = new_value; + + return new_value; +} + +static int tfanone_get_swvstep(struct tfa_device *tfa) +{ + (void)tfa; /* suppress warning */ + return tfanone_swvstep; +} + +void tfanone_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->dsp_system_stable = tfanone_dsp_system_stable; + ops->set_swprof = tfanone_set_swprofile; + ops->get_swprof = tfanone_get_swprofile; + ops->set_swvstep = tfanone_set_swvstep; + ops->get_swvstep = tfanone_get_swvstep; + +} + +/***********************************************************************************/ +/* TFA9912 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9912_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Fail; + + if (tfa) { + if (status == 0 || status == 1) { + ret = -(tfa_set_bf(tfa, TFA9912_BF_SSFAIME, (uint16_t)status)); + } + } + + return ret; +} + +static enum Tfa98xx_Error tfa9912_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock keys to write settings */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + + /* The optimal settings */ + if (tfa->rev == 0x1a13) { + + /* ----- generated code start ----- */ + /* ----- version 1.43 ----- */ + reg_write(tfa, 0x00, 0x0255); //POR=0x0245 + reg_write(tfa, 0x01, 0x838a); //POR=0x83ca + reg_write(tfa, 0x02, 0x2dc8); //POR=0x2828 + reg_write(tfa, 0x05, 0x762a); //POR=0x766a + reg_write(tfa, 0x22, 0x543c); //POR=0x545c + reg_write(tfa, 0x26, 0x0100); //POR=0x0010 + reg_write(tfa, 0x51, 0x0000); //POR=0x0080 + reg_write(tfa, 0x52, 0x551c); //POR=0x1afc + reg_write(tfa, 0x53, 0x003e); //POR=0x001e + reg_write(tfa, 0x61, 0x000c); //POR=0x0018 + reg_write(tfa, 0x63, 0x0a96); //POR=0x0a9a + reg_write(tfa, 0x65, 0x0a82); //POR=0x0a8b + reg_write(tfa, 0x66, 0x0701); //POR=0x0700 + reg_write(tfa, 0x6c, 0x00d5); //POR=0x02d5 + reg_write(tfa, 0x70, 0x26f8); //POR=0x06e0 + reg_write(tfa, 0x71, 0x3074); //POR=0x2074 + reg_write(tfa, 0x75, 0x4484); //POR=0x4585 + reg_write(tfa, 0x76, 0x72ea); //POR=0x54a2 + reg_write(tfa, 0x83, 0x0716); //POR=0x0617 + reg_write(tfa, 0x89, 0x0013); //POR=0x0014 + reg_write(tfa, 0xb0, 0x4c08); //POR=0x4c00 + reg_write(tfa, 0xc6, 0x004e); //POR=0x000e /* PLMA5539: Please make sure bit 6 is always on! */ + /* ----- generated code end ----- */ + + /* PLMA5505: MTP key open makes vulanable for MTP corruption */ + tfa9912_faim_protect(tfa, 0); + } else { + pr_info("Warning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + } + + return error; +} + +static enum Tfa98xx_Error tfa9912_factory_trimmer(struct tfa_device *tfa) +{ + unsigned short currentValue, delta; + int result; + + /* Factory trimming for the Boost converter */ + /* check if there is a correction needed */ + result = TFA_GET_BF(tfa, DCMCCAPI); + if (result) { + /* Get currentvalue of DCMCC and the Delta value */ + currentValue = (unsigned short)TFA_GET_BF(tfa, DCMCC); + delta = (unsigned short)TFA_GET_BF(tfa, USERDEF); + + /* check the sign bit (+/-) */ + result = TFA_GET_BF(tfa, DCMCCSB); + if (result == 0) { + /* Do not exceed the maximum value of 15 */ + if (currentValue + delta < 15) { + TFA_SET_BF_VOLATILE(tfa, DCMCC, currentValue + delta); + if (tfa->verbose) + pr_debug("Max coil current is set to: %d \n", currentValue + delta); + } else { + TFA_SET_BF_VOLATILE(tfa, DCMCC, 15); + if (tfa->verbose) + pr_debug("Max coil current is set to: 15 \n"); + } + } else if (result == 1) { + /* Do not exceed the minimum value of 0 */ + if (currentValue - delta > 0) { + TFA_SET_BF_VOLATILE(tfa, DCMCC, currentValue - delta); + if (tfa->verbose) + pr_debug("Max coil current is set to: %d \n", currentValue - delta); + } else { + TFA_SET_BF_VOLATILE(tfa, DCMCC, 0); + if (tfa->verbose) + pr_debug("Max coil current is set to: 0 \n"); + } + } + } + + return Tfa98xx_Error_Ok; +} + +static enum Tfa98xx_Error tfa9912_auto_copy_mtp_to_iic(struct tfa_device *tfa) +{ + /* Set auto_copy_mtp_to_iic (bit 5 of A3) to 1. Workaround for 72, 88 and 9912/9892(see PLMA5290) */ + return reg_write(tfa, 0xA3, 0x20); +} + +static int tfa9912_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9912_BF_SWPROFIL, new_value); + + return active_value; +} + +static int tfa9912_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9912_BF_SWPROFIL) - 1; +} + +static int tfa9912_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + /* Set the new value in the struct */ + tfa->vstep = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9912_BF_SWVSTEP, new_value); + + return new_value; +} + +static int tfa9912_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9912_BF_SWVSTEP) - 1; +} + +static enum Tfa98xx_Error +tfa9912_set_mute(struct tfa_device *tfa, int mute) +{ + tfa_set_bf(tfa, TFA9912_BF_CFSM, (const uint16_t)mute); + + return Tfa98xx_Error_Ok; +} + +/* Maksimum value for combination of boost_voltage and vout calibration offset (see PLMA5322, PLMA5528). */ +#define TFA9912_VBOOST_MAX 57 +#define TFA9912_CALIBR_BOOST_MAX 63 +#define TFA9912_DCDCCNT6_REG (TFA9912_BF_DCVOF >> 8) +#define TFA9912_CALIBR_REG 0xf1 + +static uint16_t tfa9912_vboost_fixup(struct tfa_device *tfa, uint16_t dcdc_cnt6) +{ + unsigned short cal_offset; + unsigned short boost_v_1st, boost_v_2nd; + uint16_t new_dcdc_cnt6; + + /* Get current calibr_vout_offset, this register is not supported by bitfields */ + reg_read(tfa, TFA9912_CALIBR_REG, &cal_offset); + cal_offset = (cal_offset & 0x001f); + new_dcdc_cnt6 = dcdc_cnt6; + + /* Get current boost_volatage values */ + boost_v_1st = tfa_get_bf_value(TFA9912_BF_DCVOF, new_dcdc_cnt6); + boost_v_2nd = tfa_get_bf_value(TFA9912_BF_DCVOS, new_dcdc_cnt6); + + /* Check boost voltages */ + if (boost_v_1st > TFA9912_VBOOST_MAX) + boost_v_1st = TFA9912_VBOOST_MAX; + + if (boost_v_2nd > TFA9912_VBOOST_MAX) + boost_v_2nd = TFA9912_VBOOST_MAX; + + /* Recalculate values, max for the sum is TFA9912_CALIBR_BOOST_MAX */ + if (boost_v_1st + cal_offset > TFA9912_CALIBR_BOOST_MAX) + boost_v_1st = TFA9912_CALIBR_BOOST_MAX - cal_offset; + + if (boost_v_2nd + cal_offset > TFA9912_CALIBR_BOOST_MAX) + boost_v_2nd = TFA9912_CALIBR_BOOST_MAX - cal_offset; + + tfa_set_bf_value(TFA9912_BF_DCVOF, boost_v_1st, &new_dcdc_cnt6); + tfa_set_bf_value(TFA9912_BF_DCVOS, boost_v_2nd, &new_dcdc_cnt6); + + /* Change register value only when it's neccesary */ + if (new_dcdc_cnt6 != dcdc_cnt6) { + if (tfa->verbose) + pr_debug("tfa9912: V boost fixup applied. Old 0x%04x, new 0x%04x\n", + dcdc_cnt6, new_dcdc_cnt6); + dcdc_cnt6 = new_dcdc_cnt6; + } + + return dcdc_cnt6; +} + +/* PLMA5322, PLMA5528 - Limit values of DCVOS and DCVOF to range specified in datasheet. */ +enum Tfa98xx_Error tfa9912_reg_write(struct tfa_device *tfa, unsigned char subaddress, unsigned short value) +{ + if (subaddress == TFA9912_DCDCCNT6_REG) { + /* Correct V boost (first and secondary) to ensure 12V is not exceeded. */ + value = tfa9912_vboost_fixup(tfa, value); + } + + return tfa98xx_write_register16(tfa, subaddress, value); +} + +/** Set internal oscillator into power down mode for TFA9912. +* +* This function is a worker for tfa98xx_set_osc_powerdown(). +* +* @param[in] tfa device description structure +* @param[in] state new state 0 - oscillator is on, 1 oscillator is off. +* +* @return Tfa98xx_Error_Ok when successfull, error otherwise. +*/ +static enum Tfa98xx_Error tfa9912_set_osc_powerdown(struct tfa_device *tfa, int state) +{ + if (state == 1 || state == 0) { + return -tfa_set_bf(tfa, TFA9912_BF_MANAOOSC, (uint16_t)state); + } + + return Tfa98xx_Error_Bad_Parameter; +} +/** update low power mode of the device. +* +* @param[in] tfa device description structure +* @param[in] state State of the low power mode1 detector control +* 0 - low power mode1 detector control enabled, +* 1 - low power mode1 detector control disabled(low power mode is also disabled). +* +* @return Tfa98xx_Error_Ok when successfull, error otherwise. +*/ +static enum Tfa98xx_Error tfa9912_update_lpm(struct tfa_device *tfa, int state) +{ + if (state == 1 || state == 0) { + return -tfa_set_bf(tfa, TFA9912_BF_LPM1DIS, (uint16_t)state); + } + return Tfa98xx_Error_Bad_Parameter; +} + +void tfa9912_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9912_specific; + /* PLMA5322, PLMA5528 - Limits values of DCVOS and DCVOF. */ + ops->reg_write = tfa9912_reg_write; + ops->factory_trimmer = tfa9912_factory_trimmer; + ops->auto_copy_mtp_to_iic = tfa9912_auto_copy_mtp_to_iic; + ops->set_swprof = tfa9912_set_swprofile; + ops->get_swprof = tfa9912_get_swprofile; + ops->set_swvstep = tfa9912_set_swvstep; + ops->get_swvstep = tfa9912_get_swvstep; + ops->set_mute = tfa9912_set_mute; + ops->faim_protect = tfa9912_faim_protect; + ops->set_osc_powerdown = tfa9912_set_osc_powerdown; + ops->update_lpm = tfa9912_update_lpm; +} + +/***********************************************************************************/ +/* TFA9872 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9872_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint16_t MANAOOSC = 0x0140; /* version 17 */ + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock key 1 and 2 */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + tfa98xx_key2(tfa, 0); + + switch (tfa->rev) { + case 0x1a72: + case 0x2a72: + /* ----- generated code start ----- */ + /* ----- version 26 ----- */ + reg_write(tfa, 0x00, 0x1801); //POR=0x0001 + reg_write(tfa, 0x02, 0x2dc8); //POR=0x2028 + reg_write(tfa, 0x20, 0x0890); //POR=0x2890 + reg_write(tfa, 0x22, 0x043c); //POR=0x045c + reg_write(tfa, 0x51, 0x0000); //POR=0x0080 + reg_write(tfa, 0x52, 0x1a1c); //POR=0x7ae8 + reg_write(tfa, 0x58, 0x161c); //POR=0x101c + reg_write(tfa, 0x61, 0x0198); //POR=0x0000 + reg_write(tfa, 0x65, 0x0a8b); //POR=0x0a9a + reg_write(tfa, 0x70, 0x07f5); //POR=0x06e6 + reg_write(tfa, 0x74, 0xcc84); //POR=0xd823 + reg_write(tfa, 0x82, 0x01ed); //POR=0x000d + reg_write(tfa, 0x83, 0x0014); //POR=0x0013 + reg_write(tfa, 0x84, 0x0021); //POR=0x0020 + reg_write(tfa, 0x85, 0x0001); //POR=0x0003 + /* ----- generated code end ----- */ + break; + case 0x1b72: + case 0x2b72: + case 0x3b72: + /* ----- generated code start ----- */ + /* ----- version 25.00 ----- */ + reg_write(tfa, 0x02, 0x2dc8); //POR=0x2828 + reg_write(tfa, 0x20, 0x0890); //POR=0x2890 + reg_write(tfa, 0x22, 0x043c); //POR=0x045c + reg_write(tfa, 0x23, 0x0001); //POR=0x0003 + reg_write(tfa, 0x51, 0x0000); //POR=0x0080 + reg_write(tfa, 0x52, 0x5a1c); //POR=0x7a08 + reg_write(tfa, 0x61, 0x0198); //POR=0x0000 + reg_write(tfa, 0x63, 0x0a9a); //POR=0x0a93 + reg_write(tfa, 0x65, 0x0a82); //POR=0x0a8d + reg_write(tfa, 0x6f, 0x01e3); //POR=0x02e4 + reg_write(tfa, 0x70, 0x06fd); //POR=0x06e6 + reg_write(tfa, 0x71, 0x307e); //POR=0x207e + reg_write(tfa, 0x74, 0xcc84); //POR=0xd913 + reg_write(tfa, 0x75, 0x1132); //POR=0x118a + reg_write(tfa, 0x82, 0x01ed); //POR=0x000d + reg_write(tfa, 0x83, 0x001a); //POR=0x0013 + /* ----- generated code end ----- */ + break; + default: + pr_info("\nWarning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + break; + } + + /* Turn off the osc1m to save power: PLMA4928 */ + error = tfa_set_bf(tfa, MANAOOSC, 1); + + /* Bypass OVP by setting bit 3 from register 0xB0 (bypass_ovp=1): PLMA5258 */ + error = reg_read(tfa, 0xB0, &value); + value |= 1 << 3; + error = reg_write(tfa, 0xB0, value); + + return error; +} + +static enum Tfa98xx_Error tfa9872_auto_copy_mtp_to_iic(struct tfa_device *tfa) +{ + /* Set auto_copy_mtp_to_iic (bit 5 of A3) to 1. Workaround for 72 and 88 (see PLMA5290) */ + return reg_write(tfa, 0xA3, 0x20); +} + +static int tfa9872_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9872_BF_SWPROFIL, new_value); + + return active_value; +} + +static int tfa9872_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9872_BF_SWPROFIL) - 1; +} + +static int tfa9872_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + + /* Set the new value in the struct */ + tfa->vstep = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9872_BF_SWVSTEP, new_value); + + return new_value; +} + +static int tfa9872_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9872_BF_SWVSTEP) - 1; +} + +void tfa9872_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9872_specific; + ops->auto_copy_mtp_to_iic = tfa9872_auto_copy_mtp_to_iic; + ops->set_swprof = tfa9872_set_swprofile; + ops->get_swprof = tfa9872_get_swprofile; + ops->set_swvstep = tfa9872_set_swvstep; + ops->get_swvstep = tfa9872_get_swvstep; + ops->set_mute = tfa_set_mute_nodsp; +} + +/***********************************************************************************/ +/* TFA9874 */ +/***********************************************************************************/ + +static enum Tfa98xx_Error tfa9874_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Ok; + /* 0b = FAIM protection enabled 1b = FAIM protection disabled*/ + ret = tfa_set_bf_volatile(tfa, TFA9874_BF_OPENMTP, (uint16_t)(status)); + return ret; +} + + +static enum Tfa98xx_Error tfa9874_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock key 1 and 2 */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + tfa98xx_key2(tfa, 0); + + switch (tfa->rev) { + case 0x0a74: /* Initial revision ID */ + /* ----- generated code start ----- */ + /* V25 */ + reg_write(tfa, 0x02, 0x22a8); //POR=0x25c8 + reg_write(tfa, 0x51, 0x0020); //POR=0x0000 + reg_write(tfa, 0x52, 0x57dc); //POR=0x56dc + reg_write(tfa, 0x58, 0x16a4); //POR=0x1614 + reg_write(tfa, 0x61, 0x0110); //POR=0x0198 + reg_write(tfa, 0x66, 0x0701); //POR=0x0700 + reg_write(tfa, 0x6f, 0x00a3); //POR=0x01a3 + reg_write(tfa, 0x70, 0x07f8); //POR=0x06f8 + reg_write(tfa, 0x73, 0x0007); //POR=0x0005 + reg_write(tfa, 0x74, 0x5068); //POR=0xcc80 + reg_write(tfa, 0x75, 0x0d28); //POR=0x1138 + reg_write(tfa, 0x83, 0x0594); //POR=0x061a + reg_write(tfa, 0x84, 0x0001); //POR=0x0021 + reg_write(tfa, 0x85, 0x0001); //POR=0x0003 + reg_write(tfa, 0x88, 0x0000); //POR=0x0002 + reg_write(tfa, 0xc4, 0x2001); //POR=0x0001 + /* ----- generated code end ----- */ + break; + case 0x0b74: + /* ----- generated code start ----- */ + /* V1.6 */ + reg_write(tfa, 0x02, 0x22a8); //POR=0x25c8 + reg_write(tfa, 0x51, 0x0020); //POR=0x0000 + reg_write(tfa, 0x52, 0x57dc); //POR=0x56dc + reg_write(tfa, 0x58, 0x16a4); //POR=0x1614 + reg_write(tfa, 0x61, 0x0110); //POR=0x0198 + reg_write(tfa, 0x66, 0x0701); //POR=0x0700 + reg_write(tfa, 0x6f, 0x00a3); //POR=0x01a3 + reg_write(tfa, 0x70, 0x07f8); //POR=0x06f8 + reg_write(tfa, 0x73, 0x0047); //POR=0x0045 + reg_write(tfa, 0x74, 0x5068); //POR=0xcc80 + reg_write(tfa, 0x75, 0x0d28); //POR=0x1138 + reg_write(tfa, 0x83, 0x0595); //POR=0x061a + reg_write(tfa, 0x84, 0x0001); //POR=0x0021 + reg_write(tfa, 0x85, 0x0001); //POR=0x0003 + reg_write(tfa, 0x88, 0x0000); //POR=0x0002 + reg_write(tfa, 0xc4, 0x2001); //POR=0x0001 + /* ----- generated code end ----- */ + break; + case 0x0c74: + /* ----- generated code start ----- */ + /* V1.16 */ + reg_write(tfa, 0x02, 0x22c8); //POR=0x25c8 + reg_write(tfa, 0x52, 0x57dc); //POR=0x56dc + reg_write(tfa, 0x53, 0x003e); //POR=0x001e + reg_write(tfa, 0x56, 0x0400); //POR=0x0600 + reg_write(tfa, 0x61, 0x0110); //POR=0x0198 + reg_write(tfa, 0x6f, 0x00a5); //POR=0x01a3 + reg_write(tfa, 0x70, 0x07f8); //POR=0x06f8 + reg_write(tfa, 0x73, 0x0047); //POR=0x0045 + reg_write(tfa, 0x74, 0x5098); //POR=0xcc80 + reg_write(tfa, 0x75, 0x8d28); //POR=0x1138 + reg_write(tfa, 0x80, 0x0000); //POR=0x0003 + reg_write(tfa, 0x83, 0x0799); //POR=0x061a + reg_write(tfa, 0x84, 0x0081); //POR=0x0021 + /* ----- generated code end ----- */ + break; + default: + pr_info("\nWarning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + break; + } + + return error; +} + +static int tfa9874_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9874_BF_SWPROFIL, new_value); + + return active_value; +} + +static int tfa9874_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9874_BF_SWPROFIL) - 1; +} + +static int tfa9874_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + + /* Set the new value in the struct */ + tfa->vstep = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9874_BF_SWVSTEP, new_value); + + return new_value; +} + +static int tfa9874_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9874_BF_SWVSTEP) - 1; +} + +/* tfa98xx_dsp_system_stable +* return: *ready = 1 when clocks are stable to allow DSP subsystem access +*/ +static enum Tfa98xx_Error tfa9874_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + /* check CLKS: ready if set */ + *ready = tfa_get_bf(tfa, TFA9874_BF_CLKS) == 1; + + return error; +} + +static int tfa9874_get_mtpb(struct tfa_device *tfa) +{ + + int value; + value = tfa_get_bf(tfa, TFA9874_BF_MTPB); + return value; +} + +void tfa9874_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9874_specific; + ops->set_swprof = tfa9874_set_swprofile; + ops->get_swprof = tfa9874_get_swprofile; + ops->set_swvstep = tfa9874_set_swvstep; + ops->get_swvstep = tfa9874_get_swvstep; + ops->dsp_system_stable = tfa9874_dsp_system_stable; + ops->faim_protect = tfa9874_faim_protect; + ops->get_mtpb = tfa9874_get_mtpb; + ops->set_mute = tfa_set_mute_nodsp; +} +/***********************************************************************************/ +/* TFA9878 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9878_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Ok; + /* 0b = FAIM protection enabled 1b = FAIM protection disabled*/ + ret = tfa_set_bf_volatile(tfa, TFA9878_BF_OPENMTP, (uint16_t)(status)); + return ret; +} + + +static enum Tfa98xx_Error tfa9878_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock key 1 and 2 */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + tfa98xx_key2(tfa, 0); + + switch (tfa->rev) { + case 0x0a78: /* Initial revision ID */ +/* ----- generated code start ----- */ +/* ----- version 28 ----- */ + reg_write(tfa, 0x01, 0x2e18); //POR=0x2e88 + reg_write(tfa, 0x02, 0x0628); //POR=0x0008 + reg_write(tfa, 0x04, 0x0240); //POR=0x0340 + reg_write(tfa, 0x52, 0x587c); //POR=0x57dc + reg_write(tfa, 0x61, 0x0183); //POR=0x0a82 + reg_write(tfa, 0x63, 0x055a); //POR=0x0a9a + reg_write(tfa, 0x65, 0x0542); //POR=0x0a82 + reg_write(tfa, 0x71, 0x303e); //POR=0x307e + reg_write(tfa, 0x83, 0x009a); //POR=0x0799 + /* ----- generated code end ----- */ + + + break; + case 0x1a78: /* Initial revision ID */ + /* ----- generated code start ----- */ + /* ----- version 12 ----- */ + reg_write(tfa, 0x01, 0x2e18); //POR=0x2e88 + reg_write(tfa, 0x02, 0x0628); //POR=0x0008 + reg_write(tfa, 0x04, 0x0241); //POR=0x0340 + reg_write(tfa, 0x52, 0x587c); //POR=0x57dc + reg_write(tfa, 0x61, 0x0183); //POR=0x0a82 + reg_write(tfa, 0x63, 0x055a); //POR=0x0a9a + reg_write(tfa, 0x65, 0x0542); //POR=0x0a82 + reg_write(tfa, 0x70, 0xb7ff); //POR=0x37ff + reg_write(tfa, 0x71, 0x303e); //POR=0x307e + reg_write(tfa, 0x83, 0x009a); //POR=0x0799 + reg_write(tfa, 0x84, 0x0211); //POR=0x0011 + reg_write(tfa, 0x8c, 0x0210); //POR=0x0010 + reg_write(tfa, 0xce, 0x2202); //POR=0xa202 + reg_write(tfa, 0xd5, 0x0000); //POR=0x0100 + /* ----- generated code end ----- */ + + break; + default: + pr_info("\nWarning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + break; + } + + return error; +} + +static int tfa9878_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9878_BF_SWPROFIL, new_value); + + return active_value; +} + +static int tfa9878_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9878_BF_SWPROFIL) - 1; +} + +static int tfa9878_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + + /* Set the new value in the struct */ + tfa->vstep = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9878_BF_SWVSTEP, new_value); + + return new_value; +} + +static int tfa9878_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9878_BF_SWVSTEP) - 1; +} + +/* tfa98xx_dsp_system_stable +* return: *ready = 1 when clocks are stable to allow DSP subsystem access +*/ +static enum Tfa98xx_Error tfa9878_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + /* check CLKS: ready if set */ + *ready = tfa_get_bf(tfa, TFA9878_BF_CLKS) == 1; + + return error; +} + +static int tfa9878_get_mtpb(struct tfa_device *tfa) +{ + + int value; + value = tfa_get_bf(tfa, TFA9878_BF_MTPB); + return value; +} + +void tfa9878_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9878_specific; + ops->set_swprof = tfa9878_set_swprofile; + ops->get_swprof = tfa9878_get_swprofile; + ops->set_swvstep = tfa9878_set_swvstep; + ops->get_swvstep = tfa9878_get_swvstep; + ops->dsp_system_stable = tfa9878_dsp_system_stable; + ops->faim_protect = tfa9878_faim_protect; + ops->get_mtpb = tfa9878_get_mtpb; + ops->set_mute = tfa_set_mute_nodsp; +} +/***********************************************************************************/ +/* TFA9888 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9888_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + int patch_version; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock keys to write settings */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + + /* Only N1C2 is supported */ + /* ----- generated code start ----- */ + /* --------- Version v1 ---------- */ + if (tfa->rev == 0x2c88) { + reg_write(tfa, 0x00, 0x164d); //POR=0x064d + reg_write(tfa, 0x01, 0x828b); //POR=0x92cb + reg_write(tfa, 0x02, 0x1dc8); //POR=0x1828 + reg_write(tfa, 0x0e, 0x0080); //POR=0x0000 + reg_write(tfa, 0x20, 0x089e); //POR=0x0890 + reg_write(tfa, 0x22, 0x543c); //POR=0x545c + reg_write(tfa, 0x23, 0x0006); //POR=0x0000 + reg_write(tfa, 0x24, 0x0014); //POR=0x0000 + reg_write(tfa, 0x25, 0x000a); //POR=0x0000 + reg_write(tfa, 0x26, 0x0100); //POR=0x0000 + reg_write(tfa, 0x28, 0x1000); //POR=0x0000 + reg_write(tfa, 0x51, 0x0000); //POR=0x00c0 + reg_write(tfa, 0x52, 0xfafe); //POR=0xbaf6 + reg_write(tfa, 0x70, 0x3ee4); //POR=0x3ee6 + reg_write(tfa, 0x71, 0x1074); //POR=0x3074 + reg_write(tfa, 0x83, 0x0014); //POR=0x0013 + /* ----- generated code end ----- */ + } else { + pr_info("Warning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + } + + patch_version = tfa_cnt_get_patch_version(tfa); + if (patch_version >= 0x060401) + tfa->partial_enable = 1; + + return error; +} + +static enum Tfa98xx_Error tfa9888_tfa_dsp_write_tables(struct tfa_device *tfa, int sample_rate) +{ + unsigned char buffer[15] = { 0 }; + int size = 15 * sizeof(char); + + /* Write the fractional delay in the hardware register 'cs_frac_delay' */ + switch (sample_rate) { + case 0: /* 8kHz */ + TFA_SET_BF(tfa, FRACTDEL, 40); + break; + case 1: /* 11.025KHz */ + TFA_SET_BF(tfa, FRACTDEL, 38); + break; + case 2: /* 12kHz */ + TFA_SET_BF(tfa, FRACTDEL, 37); + break; + case 3: /* 16kHz */ + TFA_SET_BF(tfa, FRACTDEL, 59); + break; + case 4: /* 22.05KHz */ + TFA_SET_BF(tfa, FRACTDEL, 56); + break; + case 5: /* 24kHz */ + TFA_SET_BF(tfa, FRACTDEL, 56); + break; + case 6: /* 32kHz */ + TFA_SET_BF(tfa, FRACTDEL, 52); + break; + case 7: /* 44.1kHz */ + TFA_SET_BF(tfa, FRACTDEL, 48); + break; + case 8: + default:/* 48kHz */ + TFA_SET_BF(tfa, FRACTDEL, 46); + break; + } + + /* First copy the msg_id to the buffer */ + buffer[0] = (uint8_t)0; + buffer[1] = (uint8_t)MODULE_FRAMEWORK + 128; + buffer[2] = (uint8_t)FW_PAR_ID_SET_SENSES_DELAY; + + /* Required for all FS exept 8kHz (8kHz is all zero) */ + if (sample_rate != 0) { + buffer[5] = 1; /* Vdelay_P */ + buffer[8] = 0; /* Idelay_P */ + buffer[11] = 1; /* Vdelay_S */ + buffer[14] = 0; /* Idelay_S */ + } + + /* send SetSensesDelay msg */ + return dsp_msg(tfa, size, (char *)buffer); +} + +static enum Tfa98xx_Error tfa9888_auto_copy_mtp_to_iic(struct tfa_device *tfa) +{ + /* Set auto_copy_mtp_to_iic (bit 5 of A3) to 1. Workaround for 72 and 88 (see PLMA5290) */ + return reg_write(tfa, 0xA3, 0x20); +} + +static enum Tfa98xx_Error tfa9888_factory_trimmer(struct tfa_device *tfa) +{ + unsigned short currentValue, delta; + int result; + + /* Factory trimming for the Boost converter */ + /* check if there is a correction needed */ + result = TFA_GET_BF(tfa, DCMCCAPI); + if (result) { + /* Get currentvalue of DCMCC and the Delta value */ + currentValue = (unsigned short)TFA_GET_BF(tfa, DCMCC); + delta = (unsigned short)TFA_GET_BF(tfa, USERDEF); + + /* check the sign bit (+/-) */ + result = TFA_GET_BF(tfa, DCMCCSB); + if (result == 0) { + /* Do not exceed the maximum value of 15 */ + if (currentValue + delta < 15) { + TFA_SET_BF_VOLATILE(tfa, DCMCC, currentValue + delta); + if (tfa->verbose) + pr_debug("Max coil current is set to: %d \n", currentValue + delta); + } else { + TFA_SET_BF_VOLATILE(tfa, DCMCC, 15); + if (tfa->verbose) + pr_debug("Max coil current is set to: 15 \n"); + } + } else if (result == 1) { + /* Do not exceed the minimum value of 0 */ + if (currentValue - delta > 0) { + TFA_SET_BF_VOLATILE(tfa, DCMCC, currentValue - delta); + if (tfa->verbose) + pr_debug("Max coil current is set to: %d \n", currentValue - delta); + } else { + TFA_SET_BF_VOLATILE(tfa, DCMCC, 0); + if (tfa->verbose) + pr_debug("Max coil current is set to: 0 \n"); + } + } + } + + return Tfa98xx_Error_Ok; +} + +static enum Tfa98xx_Error +tfa9888_set_mute(struct tfa_device *tfa, int mute) +{ + TFA_SET_BF(tfa, CFSMR, (const uint16_t)mute); + TFA_SET_BF(tfa, CFSML, (const uint16_t)mute); + + return Tfa98xx_Error_Ok; +} + +void tfa9888_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9888_specific; + ops->dsp_write_tables = tfa9888_tfa_dsp_write_tables; + ops->auto_copy_mtp_to_iic = tfa9888_auto_copy_mtp_to_iic; + ops->factory_trimmer = tfa9888_factory_trimmer; + ops->set_mute = tfa9888_set_mute; +} + +/***********************************************************************************/ +/* TFA9896 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9896_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Ok; + + if ((tfa->rev == 0x2b96) || (tfa->rev == 0x3b96)) { + ret = tfa_set_bf_volatile(tfa, TFA9896_BF_OPENMTP, (uint16_t)status); + } + + return ret; +} + +/***********************************************************************************/ +/* TFA9896 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9896_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short check_value; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* all i2C registers must already set to default POR value */ + + /* $48:[3] - 1 ==> 0; iddqtestbst - default value changed. + * When Iddqtestbst is set to "0", the slewrate is reduced. + * This will lower the overshoot on IN-B to avoid NMOS damage of booster. + */ + if (tfa->rev == 0x1b96) { + /* ----- generated code start v17 ----- */ + reg_write(tfa, 0x06, 0x000b); //POR=0x0001 + reg_write(tfa, 0x07, 0x3e7f); //POR=0x1e7f + reg_write(tfa, 0x0a, 0x0d8a); //POR=0x0592 + reg_write(tfa, 0x48, 0x0300); //POR=0x0308 + reg_write(tfa, 0x88, 0x0100); //POR=0x0000 + /* ----- generated code end ----- */ + } else if (tfa->rev == 0x2b96) { + /* ----- generated code start ----- v1*/ + reg_write(tfa, 0x06, 0x000b); //POR=0x0001 + reg_write(tfa, 0x07, 0x3e7f); //POR=0x1e7f + reg_write(tfa, 0x0a, 0x0d8a); //POR=0x0592 + reg_write(tfa, 0x48, 0x0300); //POR=0x0308 + reg_write(tfa, 0x88, 0x0100); //POR=0x0000 + /* ----- generated code end ----- */ + } else if (tfa->rev == 0x3b96) { + /* ----- generated code start ----- v1*/ + reg_write(tfa, 0x06, 0x000b); //POR=0x0001 + reg_write(tfa, 0x07, 0x3e7f); //POR=0x1e7f + reg_write(tfa, 0x0a, 0x0d8a); //POR=0x0592 + reg_write(tfa, 0x48, 0x0300); //POR=0x0308 + reg_write(tfa, 0x88, 0x0100); //POR=0x0000 + /* ----- generated code end ----- */ + } + /* $49:[0] - 1 ==> 0; CLIP - default value changed. 0 means CLIPPER on */ + error = reg_read(tfa, 0x49, &check_value); + check_value &= ~0x1; + error = reg_write(tfa, 0x49, check_value); + return error; +} + +/* +* the int24 values for the vsfw delay table +*/ +static unsigned char tfa9896_vsfwdelay_table[] = { + 0, 0, 2, /* Index 0 - Current/Volt Fractional Delay for 8KHz */ + 0, 0, 0, /* Index 1 - Current/Volt Fractional Delay for 11KHz */ + 0, 0, 0, /* Index 2 - Current/Volt Fractional Delay for 12KHz */ + 0, 0, 2, /* Index 3 - Current/Volt Fractional Delay for 16KHz */ + 0, 0, 2, /* Index 4 - Current/Volt Fractional Delay for 22KHz */ + 0, 0, 2, /* Index 5 - Current/Volt Fractional Delay for 24KHz */ + 0, 0, 2, /* Index 6 - Current/Volt Fractional Delay for 32KHz */ + 0, 0, 2, /* Index 7 - Current/Volt Fractional Delay for 44KHz */ + 0, 0, 3 /* Index 8 - Current/Volt Fractional Delay for 48KHz */ +}; + +/* +* TODO make this tfa98xx +* Note that the former products write this table via the patch +* so moving this to the tfa98xx API requires also updating all patches +*/ +static enum Tfa98xx_Error tfa9896_dsp_write_vsfwdelay_table(struct tfa_device *tfa) +{ + return tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURRENT_DELAY, sizeof(tfa9896_vsfwdelay_table), tfa9896_vsfwdelay_table); +} + +/* +* The int24 values for the fracdelay table +* For now applicable only for 8 and 48 kHz +*/ +static unsigned char tfa9896_cvfracdelay_table[] = { + 0, 0, 51, /* Index 0 - Current/Volt Fractional Delay for 8KHz */ + 0, 0, 0, /* Index 1 - Current/Volt Fractional Delay for 11KHz */ + 0, 0, 0, /* Index 2 - Current/Volt Fractional Delay for 12KHz */ + 0, 0, 38, /* Index 3 - Current/Volt Fractional Delay for 16KHz */ + 0, 0, 34, /* Index 4 - Current/Volt Fractional Delay for 22KHz */ + 0, 0, 33, /* Index 5 - Current/Volt Fractional Delay for 24KHz */ + 0, 0, 11, /* Index 6 - Current/Volt Fractional Delay for 32KHz */ + 0, 0, 2, /* Index 7 - Current/Volt Fractional Delay for 44KHz */ + 0, 0, 62 /* Index 8 - Current/Volt Fractional Delay for 48KHz */ +}; + +static enum Tfa98xx_Error tfa9896_dsp_write_cvfracdelay_table(struct tfa_device *tfa) +{ + return tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURFRAC_DELAY, sizeof(tfa9896_cvfracdelay_table), tfa9896_cvfracdelay_table);; +} + +static enum Tfa98xx_Error tfa9896_tfa_dsp_write_tables(struct tfa_device *tfa, int sample_rate) +{ + enum Tfa98xx_Error error; + + /* Not used for max1! */ + (void)sample_rate; + + error = tfa9896_dsp_write_vsfwdelay_table(tfa); + if (error == Tfa98xx_Error_Ok) { + error = tfa9896_dsp_write_cvfracdelay_table(tfa); + } + + return error; +} + +void tfa9896_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9896_specific; + ops->dsp_write_tables = tfa9896_tfa_dsp_write_tables; + ops->faim_protect = tfa9896_faim_protect; +} + +/***********************************************************************************/ +/* TFA9897 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9897_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short check_value; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* all i2C registers must already set to default POR value */ + + /* $48:[3] - 1 ==> 0; iddqtestbst - default value changed. + * When Iddqtestbst is set to "0", the slewrate is reduced. + * This will lower the overshoot on IN-B to avoid NMOS damage of booster */ + error = reg_write(tfa, 0x48, 0x0300); /* POR value = 0x308 */ + + /* $49:[0] - 1 ==> 0; CLIP - default value changed. 0 means CLIPPER on */ + error = reg_read(tfa, 0x49, &check_value); + check_value &= ~0x1; + error = reg_write(tfa, 0x49, check_value); + + return error; +} + +/* +* the int24 values for the vsfw delay table +*/ +static unsigned char tfa9897_vsfwdelay_table[] = { + 0, 0, 2, /* Index 0 - Current/Volt Fractional Delay for 8KHz */ + 0, 0, 0, /* Index 1 - Current/Volt Fractional Delay for 11KHz */ + 0, 0, 0, /* Index 2 - Current/Volt Fractional Delay for 12KHz */ + 0, 0, 2, /* Index 3 - Current/Volt Fractional Delay for 16KHz */ + 0, 0, 2, /* Index 4 - Current/Volt Fractional Delay for 22KHz */ + 0, 0, 2, /* Index 5 - Current/Volt Fractional Delay for 24KHz */ + 0, 0, 2, /* Index 6 - Current/Volt Fractional Delay for 32KHz */ + 0, 0, 2, /* Index 7 - Current/Volt Fractional Delay for 44KHz */ + 0, 0, 3 /* Index 8 - Current/Volt Fractional Delay for 48KHz */ +}; + +/* +* TODO make this tfa98xx +* Note that the former products write this table via the patch +* so moving this to the tfa98xx API requires also updating all patches +*/ +static enum Tfa98xx_Error tfa9897_dsp_write_vsfwdelay_table(struct tfa_device *tfa) +{ + return tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURRENT_DELAY, sizeof(tfa9897_vsfwdelay_table), tfa9897_vsfwdelay_table);; +} + +/* +* The int24 values for the fracdelay table +* For now applicable only for 8 and 48 kHz +*/ +static unsigned char tfa9897_cvfracdelay_table[] = { + 0, 0, 51, /* Index 0 - Current/Volt Fractional Delay for 8KHz */ + 0, 0, 0, /* Index 1 - Current/Volt Fractional Delay for 11KHz */ + 0, 0, 0, /* Index 2 - Current/Volt Fractional Delay for 12KHz */ + 0, 0, 38, /* Index 3 - Current/Volt Fractional Delay for 16KHz */ + 0, 0, 34, /* Index 4 - Current/Volt Fractional Delay for 22KHz */ + 0, 0, 33, /* Index 5 - Current/Volt Fractional Delay for 24KHz */ + 0, 0, 11, /* Index 6 - Current/Volt Fractional Delay for 32KHz */ + 0, 0, 2, /* Index 7 - Current/Volt Fractional Delay for 44KHz */ + 0, 0, 62 /* Index 8 - Current/Volt Fractional Delay for 48KHz */ +}; + +static enum Tfa98xx_Error tfa9897_dsp_write_cvfracdelay_table(struct tfa_device *tfa) +{ + return tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURFRAC_DELAY, sizeof(tfa9897_cvfracdelay_table), tfa9897_cvfracdelay_table);; +} + +static enum Tfa98xx_Error tfa9897_tfa_dsp_write_tables(struct tfa_device *tfa, int sample_rate) +{ + enum Tfa98xx_Error error; + + /* Not used for max1! */ + (void)sample_rate; + + error = tfa9897_dsp_write_vsfwdelay_table(tfa); + if (error == Tfa98xx_Error_Ok) { + error = tfa9897_dsp_write_cvfracdelay_table(tfa); + } + + return error; +} + +void tfa9897_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9897_specific; + ops->dsp_write_tables = tfa9897_tfa_dsp_write_tables; +} + +/***********************************************************************************/ +/* TFA9895 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9895_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int result; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* all i2C registers are already set to default */ + + result = TFA_SET_BF(tfa, AMPE, 1); + if (result < 0) + return -result; + + /* some other registers must be set for optimal amplifier behaviour */ + reg_write(tfa, 0x05, 0x13AB); + reg_write(tfa, 0x06, 0x001F); + /* peak voltage protection is always on, but may be written */ + reg_write(tfa, 0x08, 0x3C4E); + /*TFA98XX_SYSCTRL_DCA=0*/ + reg_write(tfa, 0x09, 0x024D); + reg_write(tfa, 0x41, 0x0308); + error = reg_write(tfa, 0x49, 0x0E82); + + return error; +} + +void tfa9895_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9895_specific; +} + +/***********************************************************************************/ +/* TFA9891 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9891_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* ----- generated code start ----- */ + /* ----- version 18.0 ----- */ + reg_write(tfa, 0x09, 0x025d); //POR=0x024d + reg_write(tfa, 0x10, 0x0018); //POR=0x0024 + reg_write(tfa, 0x22, 0x0003); //POR=0x0023 + reg_write(tfa, 0x25, 0x0001); //POR=0x0000 + reg_write(tfa, 0x46, 0x0000); //POR=0x4000 + reg_write(tfa, 0x55, 0x3ffb); //POR=0x7fff + /* ----- generated code end ----- */ + + return error; +} + +void tfa9891_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9891_specific; +} + +/***********************************************************************************/ +/* TFA9890 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9890_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short regRead = 0; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* all i2C registers are already set to default for N1C2 */ + + /* some PLL registers must be set optimal for amplifier behaviour */ + error = reg_write(tfa, 0x40, 0x5a6b); + if (error) + return error; + reg_read(tfa, 0x59, ®Read); + regRead |= 0x3; + reg_write(tfa, 0x59, regRead); + error = reg_write(tfa, 0x40, 0x0000); + error = reg_write(tfa, 0x47, 0x7BE1); + + return error; +} + +/* +* Disable clock gating +*/ +static enum Tfa98xx_Error tfa9890_clockgating(struct tfa_device *tfa, int on) +{ + enum Tfa98xx_Error error; + unsigned short value; + + /* for TFA9890 temporarily disable clock gating when dsp reset is used */ + error = reg_read(tfa, TFA98XX_CURRENTSENSE4, &value); + if (error) + return error; + + if (Tfa98xx_Error_Ok == error) { + if (on) /* clock gating on - clear the bit */ + value &= ~TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF; + else /* clock gating off - set the bit */ + value |= TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF; + + error = reg_write(tfa, TFA98XX_CURRENTSENSE4, value); + } + + return error; +} + +/* +* Tfa9890_DspReset will deal with clock gating control in order +* to reset the DSP for warm state restart +*/ +static enum Tfa98xx_Error tfa9890_dsp_reset(struct tfa_device *tfa, int state) +{ + enum Tfa98xx_Error error; + + /* for TFA9890 temporarily disable clock gating + when dsp reset is used */ + tfa9890_clockgating(tfa, 0); + + TFA_SET_BF(tfa, RST, (uint16_t)state); + + /* clock gating restore */ + error = tfa9890_clockgating(tfa, 1); + + return error; +} + +/* + * Tfa9890_DspSystemStable will compensate for the wrong behavior of CLKS + * to determine if the DSP subsystem is ready for patch and config loading. + * + * A MTP calibration register is checked for non-zero. + * + * Note: This only works after i2c reset as this will clear the MTP contents. + * When we are configured then the DSP communication will synchronize access. + * + */ +static enum Tfa98xx_Error tfa9890_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short status, mtp0; + int result, tries; + + /* check the contents of the STATUS register */ + result = TFA_READ_REG(tfa, AREFS); + if (result < 0) { + error = -result; + goto errorExit; + } + status = (unsigned short)result; + + /* if AMPS is set then we were already configured and running + * no need to check further + */ + *ready = (TFA_GET_BF_VALUE(tfa, AMPS, status) == 1); + if (*ready) /* if ready go back */ + return error; /* will be Tfa98xx_Error_Ok */ + + /* check AREFS and CLKS: not ready if either is clear */ + *ready = !((TFA_GET_BF_VALUE(tfa, AREFS, status) == 0) + || (TFA_GET_BF_VALUE(tfa, CLKS, status) == 0)); + if (!*ready) /* if not ready go back */ + return error; /* will be Tfa98xx_Error_Ok */ + + /* check MTPB + * mtpbusy will be active when the subsys copies MTP to I2C + * 2 times retry avoids catching this short mtpbusy active period + */ + for (tries = 2; tries > 0; tries--) { + result = TFA_GET_BF(tfa, MTPB);/*TODO_MTPB*/ + if (result < 0) { + error = -result; + goto errorExit; + } + status = (unsigned short)result; + + /* check the contents of the STATUS register */ + *ready = (result == 0); + if (*ready) /* if ready go on */ + break; + } + if (tries == 0) /* ready will be 0 if retries exausted */ + return Tfa98xx_Error_Ok; + + /* check the contents of MTP register for non-zero, + * this indicates that the subsys is ready */ + + error = reg_read(tfa, 0x84, &mtp0); + if (error) + goto errorExit; + + *ready = (mtp0 != 0); /* The MTP register written? */ + + return error; + +errorExit: + *ready = 0; + return error; +} + +void tfa9890_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9890_specific; + ops->dsp_reset = tfa9890_dsp_reset; + ops->dsp_system_stable = tfa9890_dsp_system_stable; +} + +/***********************************************************************************/ +/* TFA9894 */ +/***********************************************************************************/ +static int tfa9894_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + tfa_set_bf_volatile(tfa, TFA9894_BF_SWPROFIL, new_value); + return active_value; +} + +static int tfa9894_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9894_BF_SWPROFIL) - 1; +} + +static int tfa9894_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + /* Set the new value in the struct */ + tfa->vstep = new_value - 1; + tfa_set_bf_volatile(tfa, TFA9894_BF_SWVSTEP, new_value); + return new_value; +} + +static int tfa9894_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9894_BF_SWVSTEP) - 1; +} + +static int tfa9894_get_mtpb(struct tfa_device *tfa) +{ + int value = 0; + value = tfa_get_bf(tfa, TFA9894_BF_MTPB); + return value; +} + +/** Set internal oscillator into power down mode for TFA9894. +* +* This function is a worker for tfa98xx_set_osc_powerdown(). +* +* @param[in] tfa device description structure +* @param[in] state new state 0 - oscillator is on, 1 oscillator is off. +* +* @return Tfa98xx_Error_Ok when successfull, error otherwise. +*/ +static enum Tfa98xx_Error tfa9894_set_osc_powerdown(struct tfa_device *tfa, int state) +{ + if (state == 1 || state == 0) { + return -tfa_set_bf(tfa, TFA9894_BF_MANAOOSC, (uint16_t)state); + } + + return Tfa98xx_Error_Bad_Parameter; +} + +static enum Tfa98xx_Error tfa9894_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Ok; + /* 0b = FAIM protection enabled 1b = FAIM protection disabled*/ + ret = tfa_set_bf_volatile(tfa, TFA9894_BF_OPENMTP, (uint16_t)(status)); + return ret; +} + +static enum Tfa98xx_Error tfa9894_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + if (tfa->verbose) + if (is_94_N2_device(tfa)) + pr_debug("check_correct\n"); + /* Unlock keys to write settings */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + pr_debug("Device REFID:%x\n", tfa->rev); + /* The optimal settings */ + if (tfa->rev == 0x0a94) { + /* V36 */ + /* ----- generated code start ----- */ + reg_write(tfa, 0x00, 0xa245); //POR=0x8245 + reg_write(tfa, 0x02, 0x51e8); //POR=0x55c8 + reg_write(tfa, 0x52, 0xbe17); //POR=0xb617 + reg_write(tfa, 0x57, 0x0344); //POR=0x0366 + reg_write(tfa, 0x61, 0x0033); //POR=0x0073 + reg_write(tfa, 0x71, 0x00cf); //POR=0x018d + reg_write(tfa, 0x72, 0x34a9); //POR=0x44e8 + reg_write(tfa, 0x73, 0x3808); //POR=0x3806 + reg_write(tfa, 0x76, 0x0067); //POR=0x0065 + reg_write(tfa, 0x80, 0x0000); //POR=0x0003 + reg_write(tfa, 0x81, 0x5715); //POR=0x561a + reg_write(tfa, 0x82, 0x0104); //POR=0x0044 + /* ----- generated code end ----- */ + } else if (tfa->rev == 0x1a94) { + /* V17 */ + /* ----- generated code start ----- */ + reg_write(tfa, 0x00, 0xa245); //POR=0x8245 + reg_write(tfa, 0x01, 0x15da); //POR=0x11ca + reg_write(tfa, 0x02, 0x5288); //POR=0x55c8 + reg_write(tfa, 0x52, 0xbe17); //POR=0xb617 + reg_write(tfa, 0x53, 0x0dbe); //POR=0x0d9e + reg_write(tfa, 0x56, 0x05c3); //POR=0x07c3 + reg_write(tfa, 0x57, 0x0344); //POR=0x0366 + reg_write(tfa, 0x61, 0x0032); //POR=0x0073 + reg_write(tfa, 0x71, 0x00cf); //POR=0x018d + reg_write(tfa, 0x72, 0x34a9); //POR=0x44e8 + reg_write(tfa, 0x73, 0x38c8); //POR=0x3806 + reg_write(tfa, 0x76, 0x0067); //POR=0x0065 + reg_write(tfa, 0x80, 0x0000); //POR=0x0003 + reg_write(tfa, 0x81, 0x5799); //POR=0x561a + reg_write(tfa, 0x82, 0x0104); //POR=0x0044 + /* ----- generated code end ----- */ + + } else if (tfa->rev == 0x2a94 || tfa->rev == 0x3a94) { + /* ----- generated code start ----- */ + /* ----- version 25.00 ----- */ + reg_write(tfa, 0x01, 0x15da); //POR=0x11ca + reg_write(tfa, 0x02, 0x51e8); //POR=0x55c8 + reg_write(tfa, 0x04, 0x0200); //POR=0x0000 + reg_write(tfa, 0x52, 0xbe17); //POR=0xb617 + reg_write(tfa, 0x53, 0x0dbe); //POR=0x0d9e + reg_write(tfa, 0x57, 0x0344); //POR=0x0366 + reg_write(tfa, 0x61, 0x0032); //POR=0x0073 + reg_write(tfa, 0x71, 0x6ecf); //POR=0x6f8d + reg_write(tfa, 0x72, 0xb4a9); //POR=0x44e8 + reg_write(tfa, 0x73, 0x38c8); //POR=0x3806 + reg_write(tfa, 0x76, 0x0067); //POR=0x0065 + reg_write(tfa, 0x80, 0x0000); //POR=0x0003 + reg_write(tfa, 0x81, 0x5799); //POR=0x561a + reg_write(tfa, 0x82, 0x0104); //POR=0x0044 + /* ----- generated code end ----- */ + } + return error; +} + +static enum Tfa98xx_Error +tfa9894_set_mute(struct tfa_device *tfa, int mute) +{ + tfa_set_bf(tfa, TFA9894_BF_CFSM, (const uint16_t)mute); + return Tfa98xx_Error_Ok; +} + +static enum Tfa98xx_Error tfa9894_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + /* check CLKS: ready if set */ + *ready = tfa_get_bf(tfa, TFA9894_BF_CLKS) == 1; + + return error; +} + +void tfa9894_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9894_specific; + ops->dsp_system_stable = tfa9894_dsp_system_stable; + ops->set_mute = tfa9894_set_mute; + ops->faim_protect = tfa9894_faim_protect; + ops->get_mtpb = tfa9894_get_mtpb; + ops->set_swprof = tfa9894_set_swprofile; + ops->get_swprof = tfa9894_get_swprofile; + ops->set_swvstep = tfa9894_set_swvstep; + ops->get_swvstep = tfa9894_get_swvstep; + //ops->auto_copy_mtp_to_iic = tfa9894_auto_copy_mtp_to_iic; + ops->set_osc_powerdown = tfa9894_set_osc_powerdown; +} diff --git a/sound/soc/codecs/tfa_internal.h b/sound/soc/codecs/tfa_internal.h new file mode 100644 index 000000000000..fe6407e043ad --- /dev/null +++ b/sound/soc/codecs/tfa_internal.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +/* + * internal functions for TFA layer (not shared with SRV and HAL layer!) + */ + +#ifndef __TFA_INTERNAL_H__ +#define __TFA_INTERNAL_H__ + +#include "tfa_dsp_fw.h" +#include "tfa_ext.h" + +#if __GNUC__ >= 4 + #define TFA_INTERNAL __attribute__((visibility ("hidden"))) +#else + #define TFA_INTERNAL +#endif + +#define TFA98XX_GENERIC_SLAVE_ADDRESS 0x1C + +TFA_INTERNAL enum Tfa98xx_Error tfa98xx_check_rpc_status(struct tfa_device *tfa, + int *pRpcStatus); +TFA_INTERNAL enum Tfa98xx_Error tfa98xx_wait_result(struct tfa_device *tfa, + int waitRetryCount); + +#endif /* __TFA_INTERNAL_H__ */ + diff --git a/sound/soc/codecs/tfa_service.h b/sound/soc/codecs/tfa_service.h new file mode 100644 index 000000000000..240deb911866 --- /dev/null +++ b/sound/soc/codecs/tfa_service.h @@ -0,0 +1,1024 @@ +/* + * Copyright (C) 2014 NXP Semiconductors, 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 as + * published by the Free Software Foundation. + * + */ + +#ifndef TFA_SERVICE_H +#define TFA_SERVICE_H + +#ifdef __KERNEL__ +#include +#else +#include +#endif +#ifdef __cplusplus +extern "C" { +#include "NXP_I2C.h" +#endif + +/* + * Linux kernel module defines TFA98XX_GIT_VERSIONS in the + * linux_driver/Makefile + */ +#ifdef TFA98XX_GIT_VERSIONS + #define TFA98XX_API_REV_STR "v6.6.3"/*TFA98XX_GIT_VERSIONS*/ +#else + #define TFA98XX_API_REV_STR "v6.6.3" +#endif + +#include "tfa_device.h" + +/* + * data previously defined in Tfa9888_dsp.h + */ +#define MEMTRACK_MAX_WORDS 150 +#define LSMODEL_MAX_WORDS 150 +#define TFA98XX_MAXTAG (150) +#define FW_VAR_API_VERSION (521) + +/* Indexes and scaling factors of GetLSmodel */ +#define tfa9888_fs_IDX 128 +#define tfa9888_leakageFactor_IDX 130 +#define tfa9888_ReCorrection_IDX 131 +#define tfa9888_Bl_IDX 132 +#define ReZ_IDX 147 + +#define tfa9872_leakageFactor_IDX 128 +#define tfa9872_ReCorrection_IDX 129 +#define tfa9872_Bl_IDX 130 + +#define fs_SCALE (double)1 +#define leakageFactor_SCALE (double)8388608 +#define ReCorrection_SCALE (double)8388608 +#define Bl_SCALE (double)2097152 +#define tCoef_SCALE (double)8388608 + +/* ---------------------------- Max1 ---------------------------- */ +/* Headroom applied to the main input signal */ +#define SPKRBST_HEADROOM 7 +/* Exponent used for AGC Gain related variables */ +#define SPKRBST_AGCGAIN_EXP SPKRBST_HEADROOM +#define SPKRBST_TEMPERATURE_EXP 9 +/* Exponent used for Gain Corection related variables */ +#define SPKRBST_LIMGAIN_EXP 4 +#define SPKRBST_TIMECTE_EXP 1 +#define DSP_MAX_GAIN_EXP 7 +/* -------------------------------------------------------------- */ + +/* speaker related parameters */ +#define TFA2_SPEAKERPARAMETER_LENGTH (3*151) /* MAX2=450 */ +#define TFA1_SPEAKERPARAMETER_LENGTH (3*141) /* MAX1=423 */ + +/* vstep related parameters */ +#define TFA2_ALGOPARAMETER_LENGTH (3*304) /* N1B = (304) 305 is including the cmd-id */ +#define TFA72_ALGOPARAMETER_LENGTH_MONO (3*183) +#define TFA72_ALGOPARAMETER_LENGTH_STEREO (3*356) +#define TFA2_MBDRCPARAMETER_LENGTH (3*152) /* 154 is including the cmd-id */ +#define TFA72_MBDRCPARAMETER_LENGTH (3*98) +#define TFA1_PRESET_LENGTH 87 +#define TFA1_DRC_LENGTH 381 /* 127 words */ +#define TFA2_FILTERCOEFSPARAMETER_LENGTH (3*168) /* 170 is including the cmd-id */ +#define TFA72_FILTERCOEFSPARAMETER_LENGTH (3*156) + +/* Maximum number of retries for DSP result + * Keep this value low! + * If certain calls require longer wait conditions, the + * application should poll, not the API + * The total wait time depends on device settings. Those + * are application specific. + */ +#define TFA98XX_WAITRESULT_NTRIES 40 +#define TFA98XX_WAITRESULT_NTRIES_LONG 2000 + +/* following lengths are in bytes */ +#define TFA98XX_PRESET_LENGTH 87 +#define TFA98XX_CONFIG_LENGTH 201 +#define TFA98XX_DRC_LENGTH 381 /* 127 words */ + +typedef unsigned char Tfa98xx_Config_t[TFA98XX_CONFIG_LENGTH]; +typedef unsigned char Tfa98xx_Preset_t[TFA98XX_PRESET_LENGTH]; +typedef unsigned char Tfa98xx_DrcParameters_t[TFA98XX_DRC_LENGTH]; + +/* Type containing all the possible errors that can occur */ +enum Tfa98xx_Error { + Tfa98xx_Error_Ok = 0, + Tfa98xx_Error_Device, /* 1. Currently only used to keep in sync with tfa_error */ + Tfa98xx_Error_Bad_Parameter, /* 2. */ + Tfa98xx_Error_Fail, /* 3. generic failure, avoid mislead message */ + Tfa98xx_Error_NoClock, /* 4. no clock detected */ + Tfa98xx_Error_StateTimedOut, /* 5. */ + Tfa98xx_Error_DSP_not_running, /* 6. communication with the DSP failed */ + Tfa98xx_Error_AmpOn, /* 7. amp is still running */ + Tfa98xx_Error_NotOpen, /* 8. the given handle is not open */ + Tfa98xx_Error_InUse, /* 9. too many handles */ + Tfa98xx_Error_Buffer_too_small, /* 10. if a buffer is too small */ + /* the expected response did not occur within the expected time */ + Tfa98xx_Error_RpcBase = 100, + Tfa98xx_Error_RpcBusy = 101, + Tfa98xx_Error_RpcModId = 102, + Tfa98xx_Error_RpcParamId = 103, + Tfa98xx_Error_RpcInvalidCC = 104, + Tfa98xx_Error_RpcInvalidSeq = 105, + Tfa98xx_Error_RpcInvalidParam = 106, + Tfa98xx_Error_RpcBufferOverflow = 107, + Tfa98xx_Error_RpcCalibBusy = 108, + Tfa98xx_Error_RpcCalibFailed = 109, + Tfa98xx_Error_Not_Implemented, + Tfa98xx_Error_Not_Supported, + Tfa98xx_Error_I2C_Fatal, /* Fatal I2C error occurred */ + /* Nonfatal I2C error, and retry count reached */ + Tfa98xx_Error_I2C_NonFatal, + Tfa98xx_Error_Other = 1000 +}; + +/* + * Type containing all the possible msg returns DSP can give + * //TODO move to tfa_dsp_fw.h + */ +enum Tfa98xx_Status_ID { + Tfa98xx_DSP_Not_Running = -1, /* No response from DSP */ + Tfa98xx_I2C_Req_Done = 0, /* Request executed correctly and result, if any, is available for download */ + Tfa98xx_I2C_Req_Busy = 1, /* Request is being processed, just wait for result */ + Tfa98xx_I2C_Req_Invalid_M_ID = 2, /* Provided M-ID does not fit in valid rang [0..2] */ + Tfa98xx_I2C_Req_Invalid_P_ID = 3, /* Provided P-ID isn�t valid in the given M-ID context */ + Tfa98xx_I2C_Req_Invalid_CC = 4, /* Invalid channel configuration bits (SC|DS|DP|DC) combination */ + Tfa98xx_I2C_Req_Invalid_Seq = 5, /* Invalid sequence of commands, in case the DSP expects some commands in a specific order */ + Tfa98xx_I2C_Req_Invalid_Param = 6, /* Generic error */ + Tfa98xx_I2C_Req_Buffer_Overflow = 7, /* I2C buffer has overflowed: host has sent too many parameters, memory integrity is not guaranteed */ + Tfa98xx_I2C_Req_Calib_Busy = 8, /* Calibration not finished */ + Tfa98xx_I2C_Req_Calib_Failed = 9 /* Calibration failed */ +}; + +/* + * speaker as microphone + */ +enum Tfa98xx_saam { + Tfa98xx_saam_none, /*< SAAM feature not available */ + Tfa98xx_saam /*< SAAM feature available */ +}; + +/* + * config file subtypes + */ +enum Tfa98xx_config_type { + Tfa98xx_config_generic, + Tfa98xx_config_sub1, + Tfa98xx_config_sub2, + Tfa98xx_config_sub3, +}; + +enum Tfa98xx_AmpInputSel { + Tfa98xx_AmpInputSel_I2SLeft, + Tfa98xx_AmpInputSel_I2SRight, + Tfa98xx_AmpInputSel_DSP +}; + +enum Tfa98xx_OutputSel { + Tfa98xx_I2SOutputSel_CurrentSense, + Tfa98xx_I2SOutputSel_DSP_Gain, + Tfa98xx_I2SOutputSel_DSP_AEC, + Tfa98xx_I2SOutputSel_Amp, + Tfa98xx_I2SOutputSel_DataI3R, + Tfa98xx_I2SOutputSel_DataI3L, + Tfa98xx_I2SOutputSel_DcdcFFwdCur, +}; + +enum Tfa98xx_StereoGainSel { + Tfa98xx_StereoGainSel_Left, + Tfa98xx_StereoGainSel_Right +}; + +#define TFA98XX_MAXPATCH_LENGTH (3*1024) + +/* the number of biquads supported */ +#define TFA98XX_BIQUAD_NUM 10 + +enum Tfa98xx_Channel { + Tfa98xx_Channel_L, + Tfa98xx_Channel_R, + Tfa98xx_Channel_L_R, + Tfa98xx_Channel_Stereo +}; + +enum Tfa98xx_Mode { + Tfa98xx_Mode_Normal = 0, + Tfa98xx_Mode_RCV +}; + +enum Tfa98xx_Mute { + Tfa98xx_Mute_Off, + Tfa98xx_Mute_Digital, + Tfa98xx_Mute_Amplifier +}; + +enum Tfa98xx_SpeakerBoostStatusFlags { + Tfa98xx_SpeakerBoost_Activity = 0, /* Input signal activity. */ + Tfa98xx_SpeakerBoost_S_Ctrl, /* S Control triggers the limiter */ + Tfa98xx_SpeakerBoost_Muted, /* 1 when signal is muted */ + Tfa98xx_SpeakerBoost_X_Ctrl, /* X Control triggers the limiter */ + Tfa98xx_SpeakerBoost_T_Ctrl, /* T Control triggers the limiter */ + Tfa98xx_SpeakerBoost_NewModel, /* New model is available */ + Tfa98xx_SpeakerBoost_VolumeRdy, /* 0:stable vol, 1:still smoothing */ + Tfa98xx_SpeakerBoost_Damaged, /* Speaker Damage detected */ + Tfa98xx_SpeakerBoost_SignalClipping /* input clipping detected */ +}; + +struct Tfa98xx_DrcStateInfo { + float GRhighDrc1[2]; + float GRhighDrc2[2]; + float GRmidDrc1[2]; + float GRmidDrc2[2]; + float GRlowDrc1[2]; + float GRlowDrc2[2]; + float GRpostDrc1[2]; + float GRpostDrc2[2]; + float GRblDrc[2]; +}; +struct Tfa98xx_StateInfo { + /* SpeakerBoost State */ + float agcGain; /* Current AGC Gain value */ + float limGain; /* Current Limiter Gain value */ + float sMax; /* Current Clip/Lim threshold */ + int T; /* Current Speaker Temperature value */ + int statusFlag; /* Masked bit word */ + float X1; /* estimated excursion caused by Spkrboost gain ctrl */ + float X2; /* estimated excursion caused by manual gain setting */ + float Re; /* Loudspeaker blocked resistance */ + /* Framework state */ + /* increments each time a MIPS problem is detected on the DSP */ + int shortOnMips; + struct Tfa98xx_DrcStateInfo drcState; /* DRC state, when enabled */ +}; + +typedef struct nxpTfaMsg { + uint8_t msg_size; + unsigned char cmdId[3]; + int data[9]; +} nxpTfaMsg_t; + +typedef struct nxp_vstep_msg { + int fw_version; + uint8_t no_of_vsteps; + uint16_t reg_no; + uint8_t *msg_reg; + uint8_t msg_no; + uint32_t algo_param_length; + uint8_t *msg_algo_param; + uint32_t filter_coef_length; + uint8_t *msg_filter_coef; + uint32_t mbdrc_length; + uint8_t *msg_mbdrc; +} nxp_vstep_msg_t; + +typedef struct nxpTfaGroup { + uint8_t msg_size; + uint8_t profileId[64]; +} nxpTfaGroup_t; + + +struct nxpTfa98xx_Memtrack_data { + int length; + float mValues[MEMTRACK_MAX_WORDS]; + int mAdresses[MEMTRACK_MAX_WORDS]; + int trackers[MEMTRACK_MAX_WORDS]; + int scalingFactor[MEMTRACK_MAX_WORDS]; +}; + +/* possible memory values for DMEM in CF_CONTROLs */ +enum Tfa98xx_DMEM { + Tfa98xx_DMEM_ERR = -1, + Tfa98xx_DMEM_PMEM = 0, + Tfa98xx_DMEM_XMEM = 1, + Tfa98xx_DMEM_YMEM = 2, + Tfa98xx_DMEM_IOMEM = 3, +}; + +/** + * lookup the device type and return the family type + */ +int tfa98xx_dev2family(int dev_type); + +/** + * register definition structure + */ +struct regdef { + unsigned char offset; /**< subaddress offset */ + unsigned short pwronDefault; /**< register contents after poweron */ + unsigned short pwronTestmask; /**< mask of bits not test */ + char *name; /**< short register name */ +}; + +enum Tfa98xx_DMEM tfa98xx_filter_mem(struct tfa_device *tfa, int filter_index, unsigned short *address, int channel); + +/** + * Load the default HW settings in the device + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfa98xx_init(struct tfa_device *tfa); + +/** + * If needed, this function can be used to get a text version of the status ID code + * @param status the given status ID code + * @return the I2C status ID string + */ +const char *tfa98xx_get_i2c_status_id_string(int status); + +/* control the powerdown bit + * @param tfa the device struct pointer + * @param powerdown must be 1 or 0 + */ +enum Tfa98xx_Error tfa98xx_powerdown(struct tfa_device *tfa, int powerdown); + +/* indicates on which channel of DATAI2 the gain from the IC is set + * @param tfa the device struct pointer + * @param gain_sel, see Tfa98xx_StereoGainSel_t + */ +enum Tfa98xx_Error tfa98xx_select_stereo_gain_channel(struct tfa_device *tfa, + enum Tfa98xx_StereoGainSel gain_sel); + +/** + * set the mtp with user controllable values + * @param tfa the device struct pointer + * @param value to be written + * @param mask to be applied toi the bits affected + */ +enum Tfa98xx_Error tfa98xx_set_mtp(struct tfa_device *tfa, uint16_t value, uint16_t mask); +enum Tfa98xx_Error tfa98xx_get_mtp(struct tfa_device *tfa, uint16_t *value); + +/** + * lock or unlock KEY2 + * lock = 1 will lock + * lock = 0 will unlock + * note that on return all the hidden key will be off + */ +void tfa98xx_key2(struct tfa_device *tfa, int lock); + +int tfa_calibrate(struct tfa_device *tfa) ; +void tfa98xx_set_exttemp(struct tfa_device *tfa, short ext_temp); +short tfa98xx_get_exttemp(struct tfa_device *tfa); + +/* control the volume of the DSP + * @param vol volume in bit field. It must be between 0 and 255 + */ +enum Tfa98xx_Error tfa98xx_set_volume_level(struct tfa_device *tfa, + unsigned short vol); + +/* set the input channel to use + * @param channel see Tfa98xx_Channel_t enumeration + */ +enum Tfa98xx_Error tfa98xx_select_channel(struct tfa_device *tfa, + enum Tfa98xx_Channel channel); + +/* set the mode for normal or receiver mode + * @param mode see Tfa98xx_Mode enumeration + */ +enum Tfa98xx_Error tfa98xx_select_mode(struct tfa_device *tfa, enum Tfa98xx_Mode mode); + +/* mute/unmute the audio + * @param mute see Tfa98xx_Mute_t enumeration + */ +enum Tfa98xx_Error tfa98xx_set_mute(struct tfa_device *tfa, + enum Tfa98xx_Mute mute); + +/* + * tfa_supported_speakers - required for SmartStudio initialization + * returns the number of the supported speaker count + */ +enum Tfa98xx_Error tfa_supported_speakers(struct tfa_device *tfa, int *spkr_count); + +/** +* Return the tfa revision +*/ +void tfa98xx_rev(int *major, int *minor, int *revision); + +/* + * Return the feature bits from MTP and cnt file for comparison + */ +enum Tfa98xx_Error +tfa98xx_compare_features(struct tfa_device *tfa, int features_from_MTP[3], int features_from_cnt[3]); + +/* + * return feature bits + */ +enum Tfa98xx_Error +tfa98xx_dsp_get_sw_feature_bits(struct tfa_device *tfa, int features[2]); +enum Tfa98xx_Error +tfa98xx_dsp_get_hw_feature_bits(struct tfa_device *tfa, int *features); + +/* + * tfa98xx_supported_saam + * returns the speaker as microphone feature + * @param saam enum pointer + * @return error code + */ +enum Tfa98xx_Error tfa98xx_supported_saam(struct tfa_device *tfa, enum Tfa98xx_saam *saam); + +/* load the tables to the DSP + * called after patch load is done + * @return error code + */ +enum Tfa98xx_Error tfa98xx_dsp_write_tables(struct tfa_device *tfa, int sample_rate); + + +/* set or clear DSP reset signal + * @param new state + * @return error code + */ +enum Tfa98xx_Error tfa98xx_dsp_reset(struct tfa_device *tfa, int state); + +/* check the state of the DSP subsystem + * return ready = 1 when clocks are stable to allow safe DSP subsystem access + * @param tfa the device struct pointer + * @param ready pointer to state flag, non-zero if clocks are not stable + * @return error code + */ +enum Tfa98xx_Error tfa98xx_dsp_system_stable(struct tfa_device *tfa, int *ready); + +enum Tfa98xx_Error tfa98xx_auto_copy_mtp_to_iic(struct tfa_device *tfa); + +/** + * check the state of the DSP coolflux + * @param tfa the device struct pointer + * @return the value of CFE + */ +int tfa_cf_enabled(struct tfa_device *tfa); + +/* The following functions can only be called when the DSP is running + * - I2S clock must be active, + * - IC must be in operating mode + */ + +/** + * patch the ROM code of the DSP + * @param tfa the device struct pointer + * @param patchLength the number of bytes of patchBytes + * @param patchBytes pointer to the bytes to patch + */ +enum Tfa98xx_Error tfa_dsp_patch(struct tfa_device *tfa, + int patchLength, + const unsigned char *patchBytes); + +/** + * load explicitly the speaker parameters in case of free speaker, + * or when using a saved speaker model + */ +enum Tfa98xx_Error tfa98xx_dsp_write_speaker_parameters( + struct tfa_device *tfa, + int length, + const unsigned char *pSpeakerBytes); + +/** + * read the speaker parameters as used by the SpeakerBoost processing + */ +enum Tfa98xx_Error tfa98xx_dsp_read_speaker_parameters( + struct tfa_device *tfa, + int length, + unsigned char *pSpeakerBytes); + +/** + * read the current status of the DSP, typically used for development, + * not essential to be used in a product + */ +enum Tfa98xx_Error tfa98xx_dsp_get_state_info( + struct tfa_device *tfa, + unsigned char bytes[], + unsigned int *statesize); + +/** + * Check whether the DSP supports DRC + * pbSupportDrc=1 when DSP supports DRC, + * pbSupportDrc=0 when DSP doesn't support it + */ +enum Tfa98xx_Error tfa98xx_dsp_support_drc(struct tfa_device *tfa, + int *pbSupportDrc); + +enum Tfa98xx_Error +tfa98xx_dsp_support_framework(struct tfa_device *tfa, int *pbSupportFramework); + +/** + * read the speaker excursion model as used by SpeakerBoost processing + */ +enum Tfa98xx_Error tfa98xx_dsp_read_excursion_model( + struct tfa_device *tfa, + int length, + unsigned char *pSpeakerBytes); + +/** + * load all the parameters for a preset from a file + */ +enum Tfa98xx_Error tfa98xx_dsp_write_preset(struct tfa_device *tfa, + int length, const unsigned char + *pPresetBytes); + +/** + * wrapper for dsp_msg that adds opcode and only writes + */ +enum Tfa98xx_Error tfa_dsp_cmd_id_write(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + const unsigned char data[]); + +/** + * wrapper for dsp_msg that writes opcode and reads back the data + */ +enum Tfa98xx_Error tfa_dsp_cmd_id_write_read(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + unsigned char data[]); + +/** + * wrapper for dsp_msg that adds opcode and 3 bytes required for coefs + */ +enum Tfa98xx_Error tfa_dsp_cmd_id_coefs(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + unsigned char data[]); + +/** + * wrapper for dsp_msg that adds opcode and 3 bytes required for MBDrcDynamics + */ +enum Tfa98xx_Error tfa_dsp_cmd_id_MBDrc_dynamics(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int index_subband, + int num_bytes, unsigned char data[]); + +/** + * Disable a certain biquad. + * @param tfa the device struct pointer + * @param biquad_index: 1-10 of the biquad that needs to be adressed +*/ +enum Tfa98xx_Error Tfa98xx_DspBiquad_Disable(struct tfa_device *tfa, + int biquad_index); + +/** + * fill the calibration value as milli ohms in the struct + * assume that the device has been calibrated + */ +enum Tfa98xx_Error +tfa_dsp_get_calibration_impedance(struct tfa_device *tfa); + +/* + * return the mohm value + */ +int tfa_get_calibration_info(struct tfa_device *tfa, int channel); + +/* + * return sign extended tap pattern + */ +int tfa_get_tap_pattern(struct tfa_device *tfa); + +/** + * Reads a number of words from dsp memory + * @param tfa the device struct pointer + * @param subaddress write address to set in address register + * @param pValue pointer to read data +*/ +enum Tfa98xx_Error tfa98xx_read_register16(struct tfa_device *tfa, + unsigned char subaddress, + unsigned short *pValue); + +/** + * Reads a number of words from dsp memory + * @param tfa the device struct pointer + * @param subaddress write address to set in address register + * @param value value to write int the memory +*/ +enum Tfa98xx_Error tfa98xx_write_register16(struct tfa_device *tfa, + unsigned char subaddress, + unsigned short value); + +/** + * Intialise the dsp + * @param tfa the device struct pointer + * @return tfa error enum +*/ +enum Tfa98xx_Error +tfa98xx_init_dsp(struct tfa_device *tfa); + +/** + * Get the status of the external DSP + * @param tfa the device struct pointer + * @return status +*/ +int tfa98xx_get_dsp_status(struct tfa_device *tfa); + +/** + * Write a command message (RPC) to the dsp + * @param tfa the device struct pointer + * @param num_bytes command buffer size in bytes + * @param command_buffer + * @return tfa error enum +*/ +enum Tfa98xx_Error +tfa98xx_write_dsp(struct tfa_device *tfa, int num_bytes, const char *command_buffer); + +/** + * Read the result from the last message from the dsp + * @param tfa the device struct pointer + * @param num_bytes result buffer size in bytes + * @param result_buffer + * @return tfa error enum +*/ +enum Tfa98xx_Error +tfa98xx_read_dsp(struct tfa_device *tfa, int num_bytes, unsigned char *result_buffer); + +/** + * Write a command message (RPC) to the dsp and return the result + * @param tfa the device struct pointer + * @param command_length command buffer size in bytes + * @param command_buffer command buffer + * @param result_length result buffer size in bytes + * @param result_buffer result buffer + * @return tfa error enum +*/ +enum Tfa98xx_Error +tfa98xx_writeread_dsp(struct tfa_device *tfa, int command_length, void *command_buffer, + int result_length, void *result_buffer); + +/** + * Reads a number of words from dsp memory + * @param tfa the device struct pointer + * @param start_offset offset from where to start reading + * @param num_words number of words to read + * @param pValues pointer to read data +*/ +enum Tfa98xx_Error tfa98xx_dsp_read_mem(struct tfa_device *tfa, + unsigned int start_offset, + int num_words, int *pValues); +/** + * Write a value to dsp memory + * @param tfa the device struct pointer + * @param address write address to set in address register + * @param value value to write int the memory + * @param memtype type of memory to write to +*/ +enum Tfa98xx_Error tfa98xx_dsp_write_mem_word(struct tfa_device *tfa, + unsigned short address, int value, int memtype); + +/** + * Read data from dsp memory + * @param tfa the device struct pointer + * @param subaddress write address to set in address register + * @param num_bytes number of bytes to read from dsp + * @param data the unsigned char buffer to read data into +*/ +enum Tfa98xx_Error tfa98xx_read_data(struct tfa_device *tfa, + unsigned char subaddress, + int num_bytes, unsigned char data[]); + +/** + * Write all the bytes specified by num_bytes and data to dsp memory + * @param tfa the device struct pointer + * @param subaddress the subaddress to write to + * @param num_bytes number of bytes to write + * @param data actual data to write +*/ +enum Tfa98xx_Error tfa98xx_write_data(struct tfa_device *tfa, + unsigned char subaddress, + int num_bytes, + const unsigned char data[]); + +enum Tfa98xx_Error tfa98xx_write_raw(struct tfa_device *tfa, + int num_bytes, + const unsigned char data[]); + +/* support for converting error codes into text */ +const char *tfa98xx_get_error_string(enum Tfa98xx_Error error); + +/** + * convert signed 24 bit integers to 32bit aligned bytes + * input: data contains "num_bytes/3" int24 elements + * output: bytes contains "num_bytes" byte elements + * @param num_data length of the input data array + * @param data input data as integer array + * @param bytes output data as unsigned char array +*/ +void tfa98xx_convert_data2bytes(int num_data, const int data[], + unsigned char bytes[]); + +/** + * convert memory bytes to signed 24 bit integers + * input: bytes contains "num_bytes" byte elements + * output: data contains "num_bytes/3" int24 elements + * @param num_bytes length of the input data array + * @param bytes input data as unsigned char array + * @param data output data as integer array +*/ +void tfa98xx_convert_bytes2data(int num_bytes, const unsigned char bytes[], + int data[]); + +/** + * Read a part of the dsp memory + * @param tfa the device struct pointer + * @param memoryType indicator to the memory type + * @param offset from where to start reading + * @param length the number of bytes to read + * @param bytes output data as unsigned char array +*/ +enum Tfa98xx_Error tfa98xx_dsp_get_memory(struct tfa_device *tfa, + int memoryType, int offset, int length, + unsigned char bytes[]); + +/** + * Write a value to the dsp memory + * @param tfa the device struct pointer + * @param memoryType indicator to the memory type + * @param offset from where to start writing + * @param length the number of bytes to write + * @param value the value to write to the dsp +*/ +enum Tfa98xx_Error tfa98xx_dsp_set_memory(struct tfa_device *tfa, + int memoryType, int offset, + int length, int value); + +enum Tfa98xx_Error tfa98xx_dsp_write_config(struct tfa_device *tfa, int length, + const unsigned char *p_config_bytes); +enum Tfa98xx_Error tfa98xx_dsp_write_drc(struct tfa_device *tfa, int length, + const unsigned char *p_drc_bytes); + +/** + * write/read raw msg functions : + * the buffer is provided in little endian format, each word occupying 3 bytes, length is in bytes + * The functions will return immediately and do not not wait for DSP response + * @param tfa the device struct pointer + * @param length length of the character buffer to write + * @param buf character buffer to write +*/ +enum Tfa98xx_Error tfa_dsp_msg(struct tfa_device *tfa, int length, const char *buf); + + +/** + * The wrapper functions to call the dsp msg, register and memory function for tfa or probus + */ +enum Tfa98xx_Error dsp_msg(struct tfa_device *tfa, int length, const char *buf); +enum Tfa98xx_Error dsp_msg_read(struct tfa_device *tfa, int length, unsigned char *bytes); +enum Tfa98xx_Error reg_write(struct tfa_device *tfa, unsigned char subaddress, unsigned short value); +enum Tfa98xx_Error reg_read(struct tfa_device *tfa, unsigned char subaddress, unsigned short *value); +enum Tfa98xx_Error mem_write(struct tfa_device *tfa, unsigned short address, int value, int memtype); +enum Tfa98xx_Error mem_read(struct tfa_device *tfa, unsigned int start_offset, int num_words, int *pValues); + +enum Tfa98xx_Error dsp_partial_coefficients(struct tfa_device *tfa, uint8_t *prev, uint8_t *next); +int is_94_N2_device(struct tfa_device *tfa); +/** + * write/read raw msg functions: + * the buffer is provided in little endian format, each word occupying 3 bytes, + * length is in bytes The functions will return immediately and do not not wait + * for DSP response. An ID is added to modify the command-ID + * @param tfa the device struct pointer + * @param length length of the character buffer to write + * @param buf character buffer to write + * @param cmdid command identifier +*/ +enum Tfa98xx_Error tfa_dsp_msg_id(struct tfa_device *tfa, int length, + const char *buf, uint8_t cmdid[3]); + +/** + * write raw dsp msg functions + * @param tfa the device struct pointer + * @param length length of the character buffer to write + * @param buffer character buffer to write +*/ +enum Tfa98xx_Error tfa_dsp_msg_write(struct tfa_device *tfa, int length, + const char *buffer); + +/** + * write raw dsp msg functions + * @param tfa the device struct pointer + * @param length length of the character buffer to write + * @param buffer character buffer to write + * @param cmdid command identifier +*/ +enum Tfa98xx_Error tfa_dsp_msg_write_id(struct tfa_device *tfa, int length, + const char *buffer, uint8_t cmdid[3]); + +/** + * status function used by tfa_dsp_msg() to retrieve command/msg status: + * return a <0 status of the DSP did not ACK. + * @param tfa the device struct pointer + * @param pRpcStatus status for remote processor communication +*/ +enum Tfa98xx_Error tfa_dsp_msg_status(struct tfa_device *tfa, int *pRpcStatus); + +/** + * Read a message from dsp + * @param tfa the device struct pointer + * @param length number of bytes of the message + * @param bytes pointer to unsigned char buffer +*/ +enum Tfa98xx_Error tfa_dsp_msg_read(struct tfa_device *tfa, int length, + unsigned char *bytes); + +int tfa_set_bf(struct tfa_device *tfa, const uint16_t bf, const uint16_t value); +int tfa_set_bf_volatile(struct tfa_device *tfa, const uint16_t bf, + const uint16_t value); + +/** + * Get the value of a given bitfield + * @param tfa the device struct pointer + * @param bf the value indicating which bitfield + */ +int tfa_get_bf(struct tfa_device *tfa, const uint16_t bf); + +/** + * Set the value of a given bitfield + * @param bf the value indicating which bitfield + * @param bf_value the value of the bitfield + * @param p_reg_value a pointer to the register where to write the bitfield + * value + */ +int tfa_set_bf_value(const uint16_t bf, const uint16_t bf_value, + uint16_t *p_reg_value); + +uint16_t tfa_get_bf_value(const uint16_t bf, const uint16_t reg_value); +int tfa_write_reg(struct tfa_device *tfa, const uint16_t bf, + const uint16_t reg_value); +int tfa_read_reg(struct tfa_device *tfa, const uint16_t bf); + +/* bitfield */ +/** + * get the datasheet or bitfield name corresponding to the bitfield number + * @param num is the number for which to get the bitfield name + * @param rev is the device type + */ +char *tfaContBfName(uint16_t num, unsigned short rev); + +/** + * get the datasheet name corresponding to the bitfield number + * @param num is the number for which to get the bitfield name + * @param rev is the device type + */ +char *tfaContDsName(uint16_t num, unsigned short rev); + +/** + * get the bitfield name corresponding to the bitfield number + * @param num is the number for which to get the bitfield name + * @param rev is the device type + */ +char *tfaContBitName(uint16_t num, unsigned short rev); + +/** + * get the bitfield number corresponding to the bitfield name + * @param name is the bitfield name for which to get the bitfield number + * @param rev is the device type + */ +uint16_t tfaContBfEnum(const char *name, unsigned short rev); + +/** +* get the bitfield number corresponding to the bitfield name, checks for all devices +* @param name is the bitfield name for which to get the bitfield number + */ +uint16_t tfaContBfEnumAny(const char *name); + +#define TFA_FAM(tfa, fieldname) ((tfa->tfa_family == 1) ? TFA1_BF_##fieldname : TFA2_BF_##fieldname) +#define TFA_FAM_FW(tfa, fwname) ((tfa->tfa_family == 1) ? TFA1_FW_##fwname : TFA2_FW_##fwname) + +/* set/get bit fields to HW register*/ +#define TFA_SET_BF(tfa, fieldname, value) tfa_set_bf(tfa, TFA_FAM(tfa, fieldname), value) +#define TFA_SET_BF_VOLATILE(tfa, fieldname, value) tfa_set_bf_volatile(tfa, TFA_FAM(tfa, fieldname), value) +#define TFA_GET_BF(tfa, fieldname) tfa_get_bf(tfa, TFA_FAM(tfa, fieldname)) + +/* set/get bit field in variable */ +#define TFA_SET_BF_VALUE(tfa, fieldname, bf_value, p_reg_value) tfa_set_bf_value(TFA_FAM(tfa, fieldname), bf_value, p_reg_value) +#define TFA_GET_BF_VALUE(tfa, fieldname, reg_value) tfa_get_bf_value(TFA_FAM(tfa, fieldname), reg_value) + +/* write/read registers using a bit field name to determine the register address */ +#define TFA_WRITE_REG(tfa, fieldname, value) tfa_write_reg(tfa, TFA_FAM(tfa, fieldname), value) +#define TFA_READ_REG(tfa, fieldname) tfa_read_reg(tfa, TFA_FAM(tfa, fieldname)) + +/* FOR CALIBRATION RETRIES */ +#define TFA98XX_API_WAITRESULT_NTRIES 3000 // defined in API + +/** + * run the startup/init sequence and set ACS bit + * @param tfa the device struct pointer + * @param state the cold start state that is requested + */ +enum Tfa98xx_Error tfaRunColdboot(struct tfa_device *tfa, int state); +enum Tfa98xx_Error tfaRunMute(struct tfa_device *tfa); +enum Tfa98xx_Error tfaRunUnmute(struct tfa_device *tfa); + +/** + * wait for calibrateDone + * @param tfa the device struct pointer + * @param calibrateDone pointer to status of calibration + */ +enum Tfa98xx_Error tfaRunWaitCalibration(struct tfa_device *tfa, int *calibrateDone); + +/** + * run the startup/init sequence and set ACS bit + * @param tfa the device struct pointer + * @param profile the profile that should be loaded + */ +enum Tfa98xx_Error tfaRunColdStartup(struct tfa_device *tfa, int profile); + +/** + * this will load the patch witch will implicitly start the DSP + * if no patch is available the DPS is started immediately + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfaRunStartDSP(struct tfa_device *tfa); + +/** + * start the clocks and wait until the AMP is switching + * on return the DSP sub system will be ready for loading + * @param tfa the device struct pointer + * @param profile the profile that should be loaded on startup + */ +enum Tfa98xx_Error tfaRunStartup(struct tfa_device *tfa, int profile); + +/** + * start the maximus speakerboost algorithm + * this implies a full system startup when the system was not already started + * @param tfa the device struct pointer + * @param force indicates whether a full system startup should be allowed + * @param profile the profile that should be loaded + */ +enum Tfa98xx_Error tfaRunSpeakerBoost(struct tfa_device *tfa, + int force, int profile); + +/** + * Startup the device and write all files from device and profile section + * @param tfa the device struct pointer + * @param force indicates whether a full system startup should be allowed + * @param profile the profile that should be loaded on speaker startup + */ +enum Tfa98xx_Error tfaRunSpeakerStartup(struct tfa_device *tfa, int force, + int profile); + +/** + * Run calibration + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfaRunSpeakerCalibration(struct tfa_device *tfa); + +/** + * startup all devices. all step until patch loading is handled + * @param tfa the device struct pointer + */ +int tfaRunStartupAll(struct tfa_device *tfa); + +/** + * powerup the coolflux subsystem and wait for it + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfa_cf_powerup(struct tfa_device *tfa); + +/* + * print the current device manager state + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error show_current_state(struct tfa_device *tfa); + +/** + * Init registers and coldboot dsp + * @param tfa the device struct pointer + */ +int tfa_reset(struct tfa_device *tfa); + +/** + * Get profile from a register + * @param tfa the device struct pointer + */ +int tfa_dev_get_swprof(struct tfa_device *tfa); + +/** + * Save profile in a register + */ +int tfa_dev_set_swprof(struct tfa_device *tfa, unsigned short new_value); + +int tfa_dev_get_swvstep(struct tfa_device *tfa); + +int tfa_dev_set_swvstep(struct tfa_device *tfa, unsigned short new_value); + +int tfa_needs_reset(struct tfa_device *tfa); + +int tfa_is_cold(struct tfa_device *tfa); + +void tfa_set_query_info(struct tfa_device *tfa); + +int tfa_get_pga_gain(struct tfa_device *tfa); +int tfa_set_pga_gain(struct tfa_device *tfa, uint16_t value); +int tfa_get_noclk(struct tfa_device *tfa); + +/** + * Status of used for monitoring + * @param tfa the device struct pointer + * @return tfa error enum + */ + +enum Tfa98xx_Error tfa_status(struct tfa_device *tfa); + +/* + * function overload for flag_mtp_busy + */ +int tfa_dev_get_mtpb(struct tfa_device *tfa); + +enum Tfa98xx_Error tfaGetFwApiVersion(struct tfa_device *tfa, unsigned char *pFirmwareVersion); +#ifdef __cplusplus +} +#endif +#endif /* TFA_SERVICE_H */ -- GitLab From 4d227fb6865f38e6e2eacbca8438608e5f8b4808 Mon Sep 17 00:00:00 2001 From: Dhanalakshmi Siddani Date: Tue, 10 Mar 2020 20:07:36 +0530 Subject: [PATCH 0965/1055] ASoC: tfa98xx: Fix type casting error Fix errors related to type casting Change-Id: Icbef88a91c6b6a80df8e1bb57745ad7e90f27c07 Signed-off-by: Dhanalakshmi Siddani --- sound/soc/codecs/tfa98xx.c | 2 +- sound/soc/codecs/tfa_dsp.c | 27 ++++++++++++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/tfa98xx.c b/sound/soc/codecs/tfa98xx.c index 03af4cc018b9..15e9a0c6cf5e 100644 --- a/sound/soc/codecs/tfa98xx.c +++ b/sound/soc/codecs/tfa98xx.c @@ -478,7 +478,7 @@ static ssize_t tfa98xx_dbgfs_start_set(struct file *file, return -EINVAL; mutex_lock(&tfa98xx->dsp_lock); - ret = tfa_calibrate(tfa98xx->tfa); + ret = (enum tfa_error)tfa_calibrate(tfa98xx->tfa); if (ret == tfa_error_ok) { cal_profile = tfaContGetCalProfile(tfa98xx->tfa); if (cal_profile < 0) { diff --git a/sound/soc/codecs/tfa_dsp.c b/sound/soc/codecs/tfa_dsp.c index 3d02b4264192..9530d35695be 100644 --- a/sound/soc/codecs/tfa_dsp.c +++ b/sound/soc/codecs/tfa_dsp.c @@ -3215,7 +3215,7 @@ enum tfa_error tfa_dev_start(struct tfa_device *tfa, int next_profile, int vstep error_exit: show_current_state(tfa); - return err; + return (enum tfa_error)err; } enum tfa_error tfa_dev_stop(struct tfa_device *tfa) @@ -3231,12 +3231,12 @@ enum tfa_error tfa_dev_stop(struct tfa_device *tfa) /* powerdown CF */ err = tfa98xx_powerdown(tfa, 1); if (err != Tfa98xx_Error_Ok) - return err; + return (enum tfa_error)err; /* disable I2S output on TFA1 devices without TDM */ err = tfa98xx_aec_output(tfa, 0); - return err; + return (enum tfa_error)err; } /* @@ -3785,7 +3785,8 @@ enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state, i /* Make sure the DSP is running! */ do { - err = tfa98xx_dsp_system_stable(tfa, &ready); + err = (enum tfa_error)tfa98xx_dsp_system_stable(tfa, + &ready); if (err != tfa_error_ok) return err; if (ready) @@ -3793,7 +3794,7 @@ enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state, i } while (loop--); if (((!tfa->is_probus_device) && (is_calibration)) || ((tfa->rev & 0xff) == 0x13)) { /* Enable FAIM when clock is stable, to avoid MTP corruption */ - err = tfa98xx_faim_protect(tfa, 1); + err = (enum tfa_error)tfa98xx_faim_protect(tfa, 1); if (tfa->verbose) { pr_debug("FAIM enabled (err:%d).\n", err); } @@ -3822,7 +3823,7 @@ enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state, i } } if (((!tfa->is_probus_device) && (is_calibration)) || ((tfa->rev & 0xff) == 0x13)) { - err = tfa98xx_faim_protect(tfa, 0); + err = (enum tfa_error)tfa98xx_faim_protect(tfa, 0); if (tfa->verbose) { pr_debug("FAIM disabled (err:%d).\n", err); } @@ -3941,16 +3942,19 @@ int tfa_dev_mtp_get(struct tfa_device *tfa, enum tfa_mtp item) return value; } -enum tfa_error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, int value) +enum tfa_error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, + int value) { enum tfa_error err = tfa_error_ok; switch (item) { case TFA_MTP_OTC: - err = tfa98xx_set_mtp(tfa, (uint16_t)value, TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MSK); + err = (enum tfa_error)tfa98xx_set_mtp(tfa, (uint16_t)value, + TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MSK); break; case TFA_MTP_EX: - err = tfa98xx_set_mtp(tfa, (uint16_t)value, TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK); + err = (enum tfa_error)tfa98xx_set_mtp(tfa, (uint16_t)value, + TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK); break; case TFA_MTP_RE25: case TFA_MTP_RE25_PRIM: @@ -3978,7 +3982,7 @@ enum tfa_error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, int va break; } - return err; + return (enum tfa_error)err; } int tfa_get_pga_gain(struct tfa_device *tfa) @@ -4068,7 +4072,8 @@ int tfa_plop_noise_interrupt(struct tfa_device *tfa, int profile, int vstep) if (no_clk == 1) { /* Clock is lost. Set I2CR to remove POP noise */ pr_info("No clock detected. Resetting the I2CR to avoid pop on 72! \n"); - err = tfa_dev_start(tfa, profile, vstep); + err = (enum Tfa98xx_Error)tfa_dev_start(tfa, profile, + vstep); if (err != Tfa98xx_Error_Ok) { pr_err("Error loading i2c registers (tfa_dev_start), err=%d\n", err); } else { -- GitLab From 2588b455475c0181f829b8f893d34d46c7f66c43 Mon Sep 17 00:00:00 2001 From: Dhanalakshmi Siddani Date: Thu, 5 Mar 2020 21:39:10 +0530 Subject: [PATCH 0966/1055] ASoC: tfa98xx: Update profile info properly Smart PA profile info is not updated properly. Fix it by returning proper profile value. Change-Id: I75af9d7c1d379fb29067dea5c848fe06cd53108f Signed-off-by: Dhanalakshmi Siddani --- sound/soc/codecs/tfa_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tfa_init.c b/sound/soc/codecs/tfa_init.c index 1ced553714ab..e004b6522341 100644 --- a/sound/soc/codecs/tfa_init.c +++ b/sound/soc/codecs/tfa_init.c @@ -123,7 +123,7 @@ int tfa_set_swprofile(struct tfa_device *tfa, unsigned short new_value) static int tfa_get_swprofile(struct tfa_device *tfa) { - return TFA_GET_BF(tfa, SWPROFIL) - 1; + return tfa->profile; } static int tfa_set_swvstep(struct tfa_device *tfa, unsigned short new_value) -- GitLab From 628c50f202b45864a5ca6c09ed53ebd66fb3d1a8 Mon Sep 17 00:00:00 2001 From: Vipin Deep Kaur Date: Wed, 11 Dec 2019 18:13:51 +0530 Subject: [PATCH 0967/1055] i2c: i2c-qcom-geni: Enhance IPC logging debug infra in I2C Add additional logs with extra parameters which can help track previous transfer parameters and status in I2C geni driver. Change-Id: Id8cf640163a554e1cddbb233fd8ea59b5cfc59f1 Signed-off-by: Vipin Deep Kaur Signed-off-by: Ashish Kori --- drivers/i2c/busses/i2c-qcom-geni.c | 147 +++++++++++++++++++++-------- 1 file changed, 110 insertions(+), 37 deletions(-) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 255074d7ef76..8eeea7f72261 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -29,6 +29,7 @@ #include #include #include +#include #define SE_I2C_TX_TRANS_LEN (0x26C) #define SE_I2C_RX_TRANS_LEN (0x270) @@ -82,6 +83,8 @@ #define I2C_TIMEOUT_MIN_USEC 500000 +#define MAX_SE 20 + enum i2c_se_mode { UNINITIALIZED, FIFO_SE_DMA, @@ -101,6 +104,11 @@ struct geni_i2c_ssr { bool is_ssr_down; }; +struct dbg_buf_ctxt { + void *virt_buf; + void *map_buf; +}; + struct geni_i2c_dev { struct device *dev; void __iomem *base; @@ -137,11 +145,16 @@ struct geni_i2c_dev { bool cmd_done; struct geni_i2c_clk_fld geni_i2c_clk_param; struct geni_i2c_ssr i2c_ssr; + u32 dbg_num; + struct dbg_buf_ctxt *dbg_buf_ptr; }; static void ssr_i2c_force_suspend(struct device *dev); static void ssr_i2c_force_resume(struct device *dev); +static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE]; +static int arr_idx; + struct geni_i2c_err_log { int err; const char *msg; @@ -219,12 +232,6 @@ static inline void qcom_geni_i2c_calc_timeout(struct geni_i2c_dev *gi2c) static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) { - if (gi2c->cur) - GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, - "len:%d, slv-addr:0x%x, RD/WR:%d timeout:%u\n", - gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags, - gi2c->xfer_timeout); - if (err == I2C_NACK || err == GENI_ABORT_DONE) { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", gi2c_log[err].msg); @@ -233,8 +240,6 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s\n", gi2c_log[err].msg); } - GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s: se-mode:%d\n", __func__, - gi2c->se_mode); geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); err_ret: gi2c->err = gi2c_log[err].err; @@ -261,7 +266,13 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) dm_rx_st = readl_relaxed(gi2c->base + SE_DMA_RX_IRQ_STAT); dma = readl_relaxed(gi2c->base + SE_GENI_DMA_MODE_EN); - if (!cur || (m_stat & M_CMD_FAILURE_EN) || + if (!cur) { + geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); + GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, "Spurious irq\n"); + goto irqret; + } + + if ((m_stat & M_CMD_FAILURE_EN) || (dm_rx_st & (DM_I2C_CB_ERR)) || (m_stat & M_CMD_CANCEL_EN) || (m_stat & M_CMD_ABORT_EN)) { @@ -288,12 +299,6 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) goto irqret; } - if (dma) { - dev_dbg(gi2c->dev, "i2c dma tx:0x%x, dma rx:0x%x\n", dm_tx_st, - dm_rx_st); - goto irqret; - } - if (((m_stat & M_RX_FIFO_WATERMARK_EN) || (m_stat & M_RX_FIFO_LAST_EN)) && (cur->flags & I2C_M_RD)) { u32 rxcnt = rx_st & RX_FIFO_WC_MSK; @@ -486,6 +491,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], goto geni_i2c_gsi_xfer_out; } } + if (!gi2c->rx_c) { gi2c->rx_c = dma_request_slave_channel(gi2c->dev, "rx"); if (!gi2c->rx_c) { @@ -564,6 +570,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], sizeof(gi2c->go_t)); if (msgs[i].flags & I2C_M_RD) { + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "msg[%d].len:%d R\n", i, gi2c->cur->len); sg_init_table(&gi2c->rx_sg, 1); ret = geni_se_iommu_map_buf(rx_dev, &gi2c->rx_ph, msgs[i].buf, msgs[i].len, @@ -574,6 +582,11 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], ret); goto geni_i2c_gsi_xfer_out; + } else if (gi2c->dbg_buf_ptr) { + gi2c->dbg_buf_ptr[i].virt_buf = + (void *)msgs[i].buf; + gi2c->dbg_buf_ptr[i].map_buf = + (void *)&gi2c->rx_ph; } gi2c->rx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph); @@ -604,6 +617,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], rx_cookie = dmaengine_submit(gi2c->rx_desc); dma_async_issue_pending(gi2c->rx_c); } else { + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "msg[%d].len:%d W\n", i, gi2c->cur->len); ret = geni_se_iommu_map_buf(tx_dev, &gi2c->tx_ph, msgs[i].buf, msgs[i].len, DMA_TO_DEVICE); @@ -613,7 +628,13 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], ret); goto geni_i2c_gsi_xfer_out; + } else if (gi2c->dbg_buf_ptr) { + gi2c->dbg_buf_ptr[i].virt_buf = + (void *)msgs[i].buf; + gi2c->dbg_buf_ptr[i].map_buf = + (void *)&gi2c->tx_ph; } + gi2c->tx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph); gi2c->tx_t.dword[1] = @@ -649,8 +670,11 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (!timeout) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, - "GSI Txn timed out: %u len: %d\n", - gi2c->xfer_timeout, gi2c->cur->len); + "I2C gsi xfer timeout:%u flags:%d addr:0x%x\n", + gi2c->xfer_timeout, gi2c->cur->flags, + gi2c->cur->addr); + geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, + gi2c->ipcl); gi2c->err = -ETIMEDOUT; } geni_i2c_err_prep_sg: @@ -684,7 +708,6 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, int i, ret = 0, timeout = 0; gi2c->err = 0; - gi2c->cur = &msgs[0]; reinit_completion(&gi2c->xfer); mutex_lock(&gi2c->i2c_ssr.ssr_lock); if (gi2c->i2c_ssr.is_ssr_down) { @@ -693,6 +716,12 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mutex_unlock(&gi2c->i2c_ssr.ssr_lock); return -EINVAL; } + /* Client to respect system suspend */ + if (!pm_runtime_enabled(gi2c->dev)) { + GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, + "%s: System suspended\n", __func__); + return -EACCES; + } ret = pm_runtime_get_sync(gi2c->dev); if (ret < 0) { @@ -704,14 +733,23 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mutex_unlock(&gi2c->i2c_ssr.ssr_lock); return ret; } + + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "n:%d addr:0x%x\n", num, msgs[0].addr); + + gi2c->dbg_num = num; + kfree(gi2c->dbg_buf_ptr); + gi2c->dbg_buf_ptr = + kcalloc(num, sizeof(struct dbg_buf_ctxt), GFP_KERNEL); + if (!gi2c->dbg_buf_ptr) + GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, + "Buf logging pointer not available\n"); + if (gi2c->se_mode == GSI_ONLY) { ret = geni_i2c_gsi_xfer(adap, msgs, num); goto geni_i2c_txn_ret; } - qcom_geni_i2c_conf(gi2c, 0); - dev_dbg(gi2c->dev, "i2c xfer:num:%d, msgs:len:%d,flg:%d\n", - num, msgs[0].len, msgs[0].flags); for (i = 0; i < num; i++) { int stretch = (i < (num - 1)); u32 m_param = 0; @@ -734,9 +772,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, break; } if (msgs[i].flags & I2C_M_RD) { - dev_dbg(gi2c->dev, - "READ,n:%d,i:%d len:%d, stretch:%d\n", - num, i, msgs[i].len, stretch); + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "msgs[%d].len:%d R\n", i, msgs[i].len); geni_write_reg(msgs[i].len, gi2c->base, SE_I2C_RX_TRANS_LEN); m_cmd = I2C_READ; @@ -749,12 +786,16 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mode = FIFO_MODE; ret = geni_se_select_mode(gi2c->base, mode); + } else if (gi2c->dbg_buf_ptr) { + gi2c->dbg_buf_ptr[i].virt_buf = + (void *)msgs[i].buf; + gi2c->dbg_buf_ptr[i].map_buf = + (void *)&rx_dma; } } } else { - dev_dbg(gi2c->dev, - "WRITE:n:%d,i:%d len:%d, stretch:%d, m_param:0x%x\n", - num, i, msgs[i].len, stretch, m_param); + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "msgs[%d].len:%d W\n", i, msgs[i].len); geni_write_reg(msgs[i].len, gi2c->base, SE_I2C_TX_TRANS_LEN); m_cmd = I2C_WRITE; @@ -767,6 +808,11 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mode = FIFO_MODE; ret = geni_se_select_mode(gi2c->base, mode); + } else if (gi2c->dbg_buf_ptr) { + gi2c->dbg_buf_ptr[i].virt_buf = + (void *)msgs[i].buf; + gi2c->dbg_buf_ptr[i].map_buf = + (void *)&tx_dma; } } if (mode == FIFO_MODE) /* Get FIFO IRQ */ @@ -785,12 +831,14 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, "%s: SSR Down\n", __func__); goto geni_i2c_txn_ret; } - if (!timeout) + if (!timeout) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "I2C xfer timeout: %d\n", gi2c->xfer_timeout); geni_i2c_err(gi2c, GENI_TIMEOUT); + } if (gi2c->err) { reinit_completion(&gi2c->xfer); - gi2c->cur = NULL; geni_cancel_m_cmd(gi2c->base); mutex_unlock(&gi2c->i2c_ssr.ssr_lock); timeout = wait_for_completion_timeout(&gi2c->xfer, HZ); @@ -802,8 +850,11 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, goto geni_i2c_txn_ret; } - if (!timeout) + if (!timeout) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "Abort\n"); geni_abort_m_cmd(gi2c->base); + } } gi2c->cur_wr = 0; @@ -824,9 +875,11 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, geni_se_tx_dma_unprep(gi2c->wrapper_dev, tx_dma, msgs[i].len); } + ret = gi2c->err; if (gi2c->err) { - dev_err(gi2c->dev, "i2c error :%d\n", gi2c->err); + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "i2c error :%d\n", gi2c->err); break; } } @@ -836,9 +889,12 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, pm_runtime_mark_last_busy(gi2c->dev); pm_runtime_put_autosuspend(gi2c->dev); + gi2c->cur_wr = 0; + gi2c->cur_rd = 0; gi2c->cur = NULL; gi2c->err = 0; - dev_dbg(gi2c->dev, "i2c txn ret:%d\n", ret); + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "i2c txn ret:%d\n", ret); mutex_unlock(&gi2c->i2c_ssr.ssr_lock); return ret; } @@ -867,6 +923,10 @@ static int geni_i2c_probe(struct platform_device *pdev) if (!gi2c) return -ENOMEM; + if (arr_idx++ < MAX_SE) + /* Debug purpose */ + gi2c_dev_dbg[arr_idx] = gi2c; + gi2c->dev = &pdev->dev; snprintf(boot_marker, sizeof(boot_marker), "M - DRIVER GENI_I2C Init"); @@ -906,14 +966,12 @@ static int geni_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret); return ret; } - gi2c->i2c_rsc.m_ahb_clk = devm_clk_get(&pdev->dev, "m-ahb"); if (IS_ERR(gi2c->i2c_rsc.m_ahb_clk)) { ret = PTR_ERR(gi2c->i2c_rsc.m_ahb_clk); dev_err(&pdev->dev, "Err getting M AHB clk %d\n", ret); return ret; } - gi2c->i2c_rsc.s_ahb_clk = devm_clk_get(&pdev->dev, "s-ahb"); if (IS_ERR(gi2c->i2c_rsc.s_ahb_clk)) { ret = PTR_ERR(gi2c->i2c_rsc.s_ahb_clk); @@ -998,6 +1056,7 @@ static int geni_i2c_probe(struct platform_device *pdev) gi2c->irq, ret); return ret; } + disable_irq(gi2c->irq); i2c_set_adapdata(&gi2c->adap, gi2c); gi2c->adap.dev.parent = gi2c->dev; @@ -1012,7 +1071,11 @@ static int geni_i2c_probe(struct platform_device *pdev) gi2c->i2c_rsc.rsc_ssr.force_suspend = ssr_i2c_force_suspend; gi2c->i2c_rsc.rsc_ssr.force_resume = ssr_i2c_force_resume; mutex_init(&gi2c->i2c_ssr.ssr_lock); - i2c_add_adapter(&gi2c->adap); + ret = i2c_add_adapter(&gi2c->adap); + if (ret) { + dev_err(gi2c->dev, "Add adapter failed\n"); + return ret; + } snprintf(boot_marker, sizeof(boot_marker), "M - DRIVER GENI_I2C_%d Ready", gi2c->adap.nr); @@ -1034,6 +1097,9 @@ static int geni_i2c_remove(struct platform_device *pdev) static int geni_i2c_resume_noirq(struct device *device) { + struct geni_i2c_dev *gi2c = dev_get_drvdata(device); + + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return 0; } @@ -1064,6 +1130,7 @@ static int geni_i2c_runtime_suspend(struct device *dev) GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s failed ret:%d\n", __func__, ret); + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return ret; } @@ -1103,23 +1170,27 @@ static int geni_i2c_runtime_resume(struct device *dev) gi2c->se_mode = GSI_ONLY; geni_se_select_mode(gi2c->base, GSI_DMA); GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, - "i2c in GSI ONLY mode\n"); + "i2c GSI mode\n"); } else { int gi2c_tx_depth = get_tx_fifo_depth(gi2c->base); gi2c->se_mode = FIFO_SE_DMA; - gi2c->tx_wm = gi2c_tx_depth - 1; geni_se_init(gi2c->base, gi2c->tx_wm, gi2c_tx_depth); se_config_packing(gi2c->base, 8, 4, true); + qcom_geni_i2c_conf(gi2c, 0); GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "i2c fifo/se-dma mode. fifo depth:%d\n", gi2c_tx_depth); } + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "i2c-%d: %s\n", + gi2c->adap.nr, dev_name(gi2c->dev)); } + if (gi2c->se_mode == FIFO_SE_DMA) enable_irq(gi2c->irq); + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return 0; } @@ -1136,6 +1207,8 @@ static int geni_i2c_suspend_noirq(struct device *device) return -EBUSY; } if (!pm_runtime_status_suspended(device)) { + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "%s\n", __func__); geni_i2c_runtime_suspend(device); pm_runtime_disable(device); pm_runtime_set_suspended(device); -- GitLab From ca04ce1477f2abd6c4aac1653782d699e48d186a Mon Sep 17 00:00:00 2001 From: Arun KS Date: Fri, 26 Jun 2020 15:18:58 +0530 Subject: [PATCH 0968/1055] drivers: soc: sdx_ext_ipc: Make gpio DT entries optional To reuse the driver for multiple configurations where all the gpios are not mandatory. Make gpios optional to get probe successful. Change-Id: Iacfe4a09d55caa1622fdbc2470c693a8610ec1de Signed-off-by: Arun KS --- .../bindings/arm/msm/sdx-ext-ipc.txt | 5 +- drivers/soc/qcom/sdx_ext_ipc.c | 106 +++++++++++------- 2 files changed, 68 insertions(+), 43 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt b/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt index e98f793b66d7..0b800acb8616 100644 --- a/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt +++ b/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt @@ -8,14 +8,11 @@ state of one subsytem to another. Modem can indicate different events Required Properties: - compatible: "qcom,sdx-ext-ipc". -Required named gpio properties: +Optional named gpio properties: - qcom,mdm2ap-status-gpio: gpio for modem to indicate the boot status to APQ. - qcom,ap2mdm-status-gpio: gpio for APQ to indicate the boot status to modem. - - -Optional named gpio properties: - qcom,mdm2ap-status2-gpio: gpio for modem to indicate to APQ that it is in E911 call or doing firmware upgrade. diff --git a/drivers/soc/qcom/sdx_ext_ipc.c b/drivers/soc/qcom/sdx_ext_ipc.c index 0118f4a33fa6..883ebfeb3576 100644 --- a/drivers/soc/qcom/sdx_ext_ipc.c +++ b/drivers/soc/qcom/sdx_ext_ipc.c @@ -94,6 +94,9 @@ static ssize_t e911_show(struct device *dev, struct device_attribute *attr, int ret, state; struct gpio_cntrl *mdm = dev_get_drvdata(dev); + if (mdm->gpios[MDM2AP_STATUS2] < 0) + return -ENXIO; + mutex_lock(&mdm->e911_lock); state = gpio_get_value(mdm->gpios[MDM2AP_STATUS2]); ret = scnprintf(buf, 2, "%d\n", state); @@ -111,6 +114,9 @@ static ssize_t e911_store(struct device *dev, struct device_attribute *attr, if (kstrtoint(buf, 0, &e911)) return -EINVAL; + if (mdm->gpios[MDM2AP_STATUS2] < 0) + return -ENXIO; + mutex_lock(&mdm->e911_lock); if (e911) gpio_set_value(mdm->gpios[MDM2AP_STATUS2], 1); @@ -162,37 +168,47 @@ static int setup_ipc(struct gpio_cntrl *mdm) node = mdm->dev->of_node; for (i = 0; i < ARRAY_SIZE(gpio_map); i++) { val = of_get_named_gpio(node, gpio_map[i], 0); - if (val >= 0) - mdm->gpios[i] = val; - } - - ret = gpio_request(mdm->gpios[AP2MDM_STATUS], "AP2MDM_STATUS"); - if (ret) { - dev_err(mdm->dev, "Failed to configure AP2MDM_STATUS gpio\n"); - return ret; + mdm->gpios[i] = (val >= 0) ? val : -1; } - gpio_direction_input(mdm->gpios[AP2MDM_STATUS]); - ret = gpio_request(mdm->gpios[MDM2AP_STATUS], "MDM2AP_STATUS"); - if (ret) { - dev_err(mdm->dev, "Failed to configure MDM2AP_STATUS gpio\n"); - return ret; - } - gpio_direction_output(mdm->gpios[MDM2AP_STATUS], 1); + if (mdm->gpios[AP2MDM_STATUS] >= 0) { + ret = gpio_request(mdm->gpios[AP2MDM_STATUS], "AP2MDM_STATUS"); + if (ret) { + dev_err(mdm->dev, + "Failed to configure AP2MDM_STATUS gpio\n"); + return ret; + } + gpio_direction_input(mdm->gpios[AP2MDM_STATUS]); - ret = gpio_request(mdm->gpios[MDM2AP_STATUS2], "MDM2AP_STATUS2"); - if (ret) { - dev_err(mdm->dev, "Failed to configure MDM2AP_STATUS2 gpio\n"); - return ret; - } - gpio_direction_output(mdm->gpios[MDM2AP_STATUS2], 0); + irq = gpio_to_irq(mdm->gpios[AP2MDM_STATUS]); + if (irq < 0) { + dev_err(mdm->dev, "bad AP2MDM_STATUS IRQ resource\n"); + return irq; + } + mdm->status_irq = irq; + } else + dev_info(mdm->dev, "AP2MDM_STATUS not used\n"); - irq = gpio_to_irq(mdm->gpios[AP2MDM_STATUS]); - if (irq < 0) { - dev_err(mdm->dev, "bad AP2MDM_STATUS IRQ resource\n"); - return irq; - } - mdm->status_irq = irq; + if (mdm->gpios[MDM2AP_STATUS] >= 0) { + ret = gpio_request(mdm->gpios[MDM2AP_STATUS], "MDM2AP_STATUS"); + if (ret) { + dev_err(mdm->dev, "Failed to configure MDM2AP_STATUS gpio\n"); + return ret; + } + gpio_direction_output(mdm->gpios[MDM2AP_STATUS], 1); + } else + dev_info(mdm->dev, "MDM2AP_STATUS not used\n"); + + if (mdm->gpios[MDM2AP_STATUS2] >= 0) { + ret = gpio_request(mdm->gpios[MDM2AP_STATUS2], + "MDM2AP_STATUS2"); + if (ret) { + dev_err(mdm->dev, "Failed to configure MDM2AP_STATUS2 gpio\n"); + return ret; + } + gpio_direction_output(mdm->gpios[MDM2AP_STATUS2], 0); + } else + dev_info(mdm->dev, "MDM2AP_STATUS2 not used\n"); return 0; } @@ -227,8 +243,11 @@ static int sdx_ext_ipc_probe(struct platform_device *pdev) return ret; } - mdm->panic_blk.notifier_call = sdx_ext_ipc_panic; - atomic_notifier_chain_register(&panic_notifier_list, &mdm->panic_blk); + if (mdm->gpios[MDM2AP_STATUS] >= 0) { + mdm->panic_blk.notifier_call = sdx_ext_ipc_panic; + atomic_notifier_chain_register(&panic_notifier_list, + &mdm->panic_blk); + } mutex_init(&mdm->policy_lock); mutex_init(&mdm->e911_lock); @@ -251,15 +270,19 @@ static int sdx_ext_ipc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mdm); - ret = devm_request_irq(mdm->dev, mdm->status_irq, ap_status_change, + if (mdm->gpios[AP2MDM_STATUS] >= 0) { + ret = devm_request_irq(mdm->dev, mdm->status_irq, + ap_status_change, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "ap status", mdm); - if (ret < 0) { - dev_err(mdm->dev, "%s: AP2MDM_STATUS IRQ#%d request failed,\n", - __func__, mdm->status_irq); - goto irq_fail; + "ap status", mdm); + if (ret < 0) { + dev_err(mdm->dev, + "%s: AP2MDM_STATUS IRQ#%d request failed,\n", + __func__, mdm->status_irq); + goto irq_fail; + } + irq_set_irq_wake(mdm->status_irq, 1); } - irq_set_irq_wake(mdm->status_irq, 1); return 0; irq_fail: @@ -267,7 +290,9 @@ static int sdx_ext_ipc_probe(struct platform_device *pdev) sys_fail1: device_remove_file(mdm->dev, &dev_attr_e911); sys_fail: - atomic_notifier_chain_unregister(&panic_notifier_list, &mdm->panic_blk); + if (mdm->gpios[MDM2AP_STATUS] >= 0) + atomic_notifier_chain_unregister(&panic_notifier_list, + &mdm->panic_blk); remove_ipc(mdm); devm_kfree(&pdev->dev, mdm); return ret; @@ -278,8 +303,11 @@ static int sdx_ext_ipc_remove(struct platform_device *pdev) struct gpio_cntrl *mdm; mdm = dev_get_drvdata(&pdev->dev); - disable_irq_wake(mdm->status_irq); - atomic_notifier_chain_unregister(&panic_notifier_list, &mdm->panic_blk); + if (mdm->gpios[AP2MDM_STATUS] >= 0) + disable_irq_wake(mdm->status_irq); + if (mdm->gpios[MDM2AP_STATUS] >= 0) + atomic_notifier_chain_unregister(&panic_notifier_list, + &mdm->panic_blk); remove_ipc(mdm); device_remove_file(mdm->dev, &dev_attr_policy); return 0; -- GitLab From da326c7450289700b5cf27ab1e3f91adb1073088 Mon Sep 17 00:00:00 2001 From: Arun KS Date: Tue, 30 Jun 2020 09:53:37 +0530 Subject: [PATCH 0969/1055] drivers: soc: sdx_ext_ipc: Give generic name for gpios Disassociate the driver from mdm perspective. This driver can be reused from AP side as well. Change the gpio names applicable in both cases. Change-Id: Icea71d5eb3be33cfd3d461dc9bae9eda07448e74 Signed-off-by: Arun KS --- .../bindings/arm/msm/sdx-ext-ipc.txt | 15 ++-- drivers/soc/qcom/sdx_ext_ipc.c | 76 +++++++++---------- 2 files changed, 44 insertions(+), 47 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt b/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt index 0b800acb8616..d8c6478c469a 100644 --- a/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt +++ b/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt @@ -9,22 +9,19 @@ Required Properties: - compatible: "qcom,sdx-ext-ipc". Optional named gpio properties: -- qcom,mdm2ap-status-gpio: gpio for modem to indicate the boot status to APQ. +- qcom,status-out-gpio: gpio to indicate the boot status to remote processor. -- qcom,ap2mdm-status-gpio: gpio for APQ to indicate the boot status to modem. +- qcom,status-in-gpio: gpio for remote processor to indicate the boot status. -- qcom,mdm2ap-status2-gpio: gpio for modem to indicate to APQ that it is in +- qcom,status-out2-gpio: gpio to indicate to remote processor that it is in E911 call or doing firmware upgrade. -- qcom,ap2mdm-status2-gpio: gpio for APQ to indicate graceful shutdown to modem. - - qcom,default-policy-nop: Set default policy from PANIC to NOP. Example: sdx_ext_ipc: qcom,sdx_ext_ipc { compatible = "qcom,sdx-ext-ipc"; - qcom,ap2mdm-status-gpio = <&tlmm 64 0x00>; - qcom,ap2mdm-status2-gpio = <&tlmm 65 0x00>; - qcom,mdm2ap-status-gpio = <&tlmm 63 0x00>; - qcom,mdm2ap-status2-gpio = <&tlmm 66 0x00>; + qcom,status-in-gpio = <&tlmm 64 0x00>; + qcom,status-out-gpio = <&tlmm 63 0x00>; + qcom,status-out2-gpio = <&tlmm 66 0x00>; }; diff --git a/drivers/soc/qcom/sdx_ext_ipc.c b/drivers/soc/qcom/sdx_ext_ipc.c index 883ebfeb3576..2c4e9f764e08 100644 --- a/drivers/soc/qcom/sdx_ext_ipc.c +++ b/drivers/soc/qcom/sdx_ext_ipc.c @@ -30,16 +30,16 @@ static const char * const policies[] = { }; enum gpios { - AP2MDM_STATUS = 0, - MDM2AP_STATUS, - MDM2AP_STATUS2, + STATUS_IN = 0, + STATUS_OUT, + STATUS_OUT2, NUM_GPIOS, }; static const char * const gpio_map[] = { - [AP2MDM_STATUS] = "qcom,ap2mdm-status-gpio", - [MDM2AP_STATUS] = "qcom,mdm2ap-status-gpio", - [MDM2AP_STATUS2] = "qcom,mdm2ap-status2-gpio", + [STATUS_IN] = "qcom,status-in-gpio", + [STATUS_OUT] = "qcom,status-out-gpio", + [STATUS_OUT2] = "qcom,status-out2-gpio", }; struct gpio_cntrl { @@ -94,11 +94,11 @@ static ssize_t e911_show(struct device *dev, struct device_attribute *attr, int ret, state; struct gpio_cntrl *mdm = dev_get_drvdata(dev); - if (mdm->gpios[MDM2AP_STATUS2] < 0) + if (mdm->gpios[STATUS_OUT2] < 0) return -ENXIO; mutex_lock(&mdm->e911_lock); - state = gpio_get_value(mdm->gpios[MDM2AP_STATUS2]); + state = gpio_get_value(mdm->gpios[STATUS_OUT2]); ret = scnprintf(buf, 2, "%d\n", state); mutex_unlock(&mdm->e911_lock); @@ -114,14 +114,14 @@ static ssize_t e911_store(struct device *dev, struct device_attribute *attr, if (kstrtoint(buf, 0, &e911)) return -EINVAL; - if (mdm->gpios[MDM2AP_STATUS2] < 0) + if (mdm->gpios[STATUS_OUT2] < 0) return -ENXIO; mutex_lock(&mdm->e911_lock); if (e911) - gpio_set_value(mdm->gpios[MDM2AP_STATUS2], 1); + gpio_set_value(mdm->gpios[STATUS_OUT2], 1); else - gpio_set_value(mdm->gpios[MDM2AP_STATUS2], 0); + gpio_set_value(mdm->gpios[STATUS_OUT2], 0); mutex_unlock(&mdm->e911_lock); return count; @@ -132,13 +132,13 @@ static irqreturn_t ap_status_change(int irq, void *dev_id) { struct gpio_cntrl *mdm = dev_id; int state; - struct gpio_desc *gp_status = gpio_to_desc(mdm->gpios[AP2MDM_STATUS]); + struct gpio_desc *gp_status = gpio_to_desc(mdm->gpios[STATUS_IN]); int active_low = 0; if (gp_status) active_low = gpiod_is_active_low(gp_status); - state = gpio_get_value(mdm->gpios[AP2MDM_STATUS]); + state = gpio_get_value(mdm->gpios[STATUS_IN]); if ((!active_low && !state) || (active_low && state)) { if (mdm->policy) dev_info(mdm->dev, "Host undergoing SSR, leaving SDX as it is\n"); @@ -171,44 +171,44 @@ static int setup_ipc(struct gpio_cntrl *mdm) mdm->gpios[i] = (val >= 0) ? val : -1; } - if (mdm->gpios[AP2MDM_STATUS] >= 0) { - ret = gpio_request(mdm->gpios[AP2MDM_STATUS], "AP2MDM_STATUS"); + if (mdm->gpios[STATUS_IN] >= 0) { + ret = gpio_request(mdm->gpios[STATUS_IN], "STATUS_IN"); if (ret) { dev_err(mdm->dev, - "Failed to configure AP2MDM_STATUS gpio\n"); + "Failed to configure STATUS_IN gpio\n"); return ret; } - gpio_direction_input(mdm->gpios[AP2MDM_STATUS]); + gpio_direction_input(mdm->gpios[STATUS_IN]); - irq = gpio_to_irq(mdm->gpios[AP2MDM_STATUS]); + irq = gpio_to_irq(mdm->gpios[STATUS_IN]); if (irq < 0) { - dev_err(mdm->dev, "bad AP2MDM_STATUS IRQ resource\n"); + dev_err(mdm->dev, "bad STATUS_IN IRQ resource\n"); return irq; } mdm->status_irq = irq; } else - dev_info(mdm->dev, "AP2MDM_STATUS not used\n"); + dev_info(mdm->dev, "STATUS_IN not used\n"); - if (mdm->gpios[MDM2AP_STATUS] >= 0) { - ret = gpio_request(mdm->gpios[MDM2AP_STATUS], "MDM2AP_STATUS"); + if (mdm->gpios[STATUS_OUT] >= 0) { + ret = gpio_request(mdm->gpios[STATUS_OUT], "STATUS_OUT"); if (ret) { - dev_err(mdm->dev, "Failed to configure MDM2AP_STATUS gpio\n"); + dev_err(mdm->dev, "Failed to configure STATUS_OUT gpio\n"); return ret; } - gpio_direction_output(mdm->gpios[MDM2AP_STATUS], 1); + gpio_direction_output(mdm->gpios[STATUS_OUT], 1); } else - dev_info(mdm->dev, "MDM2AP_STATUS not used\n"); + dev_info(mdm->dev, "STATUS_OUT not used\n"); - if (mdm->gpios[MDM2AP_STATUS2] >= 0) { - ret = gpio_request(mdm->gpios[MDM2AP_STATUS2], - "MDM2AP_STATUS2"); + if (mdm->gpios[STATUS_OUT2] >= 0) { + ret = gpio_request(mdm->gpios[STATUS_OUT2], + "STATUS_OUT2"); if (ret) { - dev_err(mdm->dev, "Failed to configure MDM2AP_STATUS2 gpio\n"); + dev_err(mdm->dev, "Failed to configure STATUS_OUT2 gpio\n"); return ret; } - gpio_direction_output(mdm->gpios[MDM2AP_STATUS2], 0); + gpio_direction_output(mdm->gpios[STATUS_OUT2], 0); } else - dev_info(mdm->dev, "MDM2AP_STATUS2 not used\n"); + dev_info(mdm->dev, "STATUS_OUT2 not used\n"); return 0; } @@ -219,7 +219,7 @@ static int sdx_ext_ipc_panic(struct notifier_block *this, struct gpio_cntrl *mdm = container_of(this, struct gpio_cntrl, panic_blk); - gpio_set_value(mdm->gpios[MDM2AP_STATUS], 0); + gpio_set_value(mdm->gpios[STATUS_OUT], 0); return NOTIFY_DONE; } @@ -243,7 +243,7 @@ static int sdx_ext_ipc_probe(struct platform_device *pdev) return ret; } - if (mdm->gpios[MDM2AP_STATUS] >= 0) { + if (mdm->gpios[STATUS_OUT] >= 0) { mdm->panic_blk.notifier_call = sdx_ext_ipc_panic; atomic_notifier_chain_register(&panic_notifier_list, &mdm->panic_blk); @@ -270,14 +270,14 @@ static int sdx_ext_ipc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mdm); - if (mdm->gpios[AP2MDM_STATUS] >= 0) { + if (mdm->gpios[STATUS_IN] >= 0) { ret = devm_request_irq(mdm->dev, mdm->status_irq, ap_status_change, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "ap status", mdm); if (ret < 0) { dev_err(mdm->dev, - "%s: AP2MDM_STATUS IRQ#%d request failed,\n", + "%s: STATUS_IN IRQ#%d request failed,\n", __func__, mdm->status_irq); goto irq_fail; } @@ -290,7 +290,7 @@ static int sdx_ext_ipc_probe(struct platform_device *pdev) sys_fail1: device_remove_file(mdm->dev, &dev_attr_e911); sys_fail: - if (mdm->gpios[MDM2AP_STATUS] >= 0) + if (mdm->gpios[STATUS_OUT] >= 0) atomic_notifier_chain_unregister(&panic_notifier_list, &mdm->panic_blk); remove_ipc(mdm); @@ -303,9 +303,9 @@ static int sdx_ext_ipc_remove(struct platform_device *pdev) struct gpio_cntrl *mdm; mdm = dev_get_drvdata(&pdev->dev); - if (mdm->gpios[AP2MDM_STATUS] >= 0) + if (mdm->gpios[STATUS_IN] >= 0) disable_irq_wake(mdm->status_irq); - if (mdm->gpios[MDM2AP_STATUS] >= 0) + if (mdm->gpios[STATUS_OUT] >= 0) atomic_notifier_chain_unregister(&panic_notifier_list, &mdm->panic_blk); remove_ipc(mdm); -- GitLab From 2d684bc43c096caa0862925e06fe2b8d29650bb5 Mon Sep 17 00:00:00 2001 From: Arun KS Date: Fri, 26 Jun 2020 23:14:44 +0530 Subject: [PATCH 0970/1055] ARM: dts: msm: Align with the gpio name change in driver Align gpio dt property with the sdx_ipc_ext.c driver changes. Change-Id: I0c33dc0fc7c6a9a5d6a7cad300a0a0d6585aa8e7 Signed-off-by: Arun KS --- arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts | 6 +++--- arch/arm64/boot/dts/qcom/sdxprairie.dtsi | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts index bb1f2ae1b5f2..ebeac7624478 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts +++ b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-pcie-ep.dts @@ -75,8 +75,8 @@ &sdx_ext_ipc { compatible = "qcom,sa515m-ccard"; - qcom,ap2mdm-status-gpio = <&tlmm 76 0x00>; - qcom,mdm2ap-status-gpio = <&tlmm 33 0x00>; - qcom,mdm2ap-status2-gpio = <&tlmm 31 0x00>; + qcom,status-in-gpio = <&tlmm 76 0x00>; + qcom,status-out-gpio = <&tlmm 33 0x00>; + qcom,status-out2-gpio = <&tlmm 31 0x00>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index b2e0fb5853bf..6307a3983b33 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -1593,9 +1593,9 @@ sdx_ext_ipc: qcom,sdx_ext_ipc { compatible = "qcom,sdx-ext-ipc"; - qcom,ap2mdm-status-gpio = <&tlmm 64 0x00>; - qcom,mdm2ap-status-gpio = <&tlmm 63 0x00>; - qcom,mdm2ap-status2-gpio = <&tlmm 66 0x00>; + qcom,status-in-gpio = <&tlmm 64 0x00>; + qcom,status-out-gpio = <&tlmm 63 0x00>; + qcom,status-out2-gpio = <&tlmm 66 0x00>; status = "disabled"; }; }; -- GitLab From 0d8f9483258319f234ed1894cc35397f165f7920 Mon Sep 17 00:00:00 2001 From: Yunyun Cao Date: Tue, 30 Jun 2020 10:45:05 +0800 Subject: [PATCH 0971/1055] msm: ais: remove cci reset for specified master during cci initialization Doing cci reset in function cci init function leads to concurrency issue between different clients of same cci master. Remove cci reset if reference count is not zero to avoid such issue. Change-Id: Id74c46523a566444ac25abf6590e4b803bb7da57 Signed-off-by: Yunyun Cao --- .../cam_sensor_module/cam_cci/cam_cci_soc.c | 43 +++---------------- 1 file changed, 5 insertions(+), 38 deletions(-) diff --git a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_soc.c index f3aec6291595..3a81905a234f 100644 --- a/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/media/platform/msm/ais/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -27,8 +27,7 @@ int cam_cci_init(struct v4l2_subdev *sd, cci_dev = v4l2_get_subdevdata(sd); if (!cci_dev || !c_ctrl) { - CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", - cci_dev, c_ctrl); + CAM_ERR(CAM_CCI, "failed: invalid params"); rc = -EINVAL; return rc; } @@ -37,47 +36,15 @@ int cam_cci_init(struct v4l2_subdev *sd, base = soc_info->reg_map[0].mem_base; if (!soc_info || !base) { - CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", - soc_info, base); + CAM_ERR(CAM_CCI, "failed: invalid params"); rc = -EINVAL; return rc; } - CAM_DBG(CAM_CCI, "Base address %pK", base); - - if (cci_dev->ref_count++) { - CAM_DBG(CAM_CCI, "ref_count %d", cci_dev->ref_count); - CAM_DBG(CAM_CCI, "master %d", master); - if (master < MASTER_MAX && master >= 0) { - mutex_lock(&cci_dev->cci_master_info[master].mutex); - flush_workqueue(cci_dev->write_wq[master]); - /* Re-initialize the completion */ - reinit_completion( - &cci_dev->cci_master_info[master].reset_complete); - reinit_completion( - &cci_dev->cci_master_info[master].rd_done); - for (i = 0; i < NUM_QUEUES; i++) - reinit_completion( - &cci_dev->cci_master_info[master].report_q[i]); - /* Set reset pending flag to TRUE */ - cci_dev->cci_master_info[master].reset_pending = TRUE; - /* Set proper mask to RESET CMD address */ - if (master == MASTER_0) - cam_io_w_mb(CCI_M0_RESET_RMSK, - base + CCI_RESET_CMD_ADDR); - else - cam_io_w_mb(CCI_M1_RESET_RMSK, - base + CCI_RESET_CMD_ADDR); - /* wait for reset done irq */ - rc = wait_for_completion_timeout( - &cci_dev->cci_master_info[master].reset_complete, - CCI_TIMEOUT); - if (rc <= 0) - CAM_ERR(CAM_CCI, "wait failed %d", rc); - mutex_unlock(&cci_dev->cci_master_info[master].mutex); - } + CAM_DBG(CAM_CCI, "ref_count %d master %d", cci_dev->ref_count, master); + + if (cci_dev->ref_count++) return 0; - } /* Enable Regulators and IRQ*/ rc = cam_soc_util_enable_platform_resource(soc_info, true, -- GitLab From 683f99243fae347073d09df877641eec74c80923 Mon Sep 17 00:00:00 2001 From: Jiten Patel Date: Tue, 23 Jun 2020 16:29:38 +0530 Subject: [PATCH 0972/1055] qseecom: register qseecom client with msm bus driver This allows qseecom to update bus bandwidth while making scm calls. Change-Id: If39fb7b496491ada84f9472819b2eb6e77b9ec32 Signed-off-by: Jiten Patel --- drivers/misc/qseecom.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index f402e161e55f..041c7fbb2f8b 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -9005,6 +9005,7 @@ static int qseecom_probe(struct platform_device *pdev) struct device *class_dev; struct qseecom_command_scm_resp resp; struct qseecom_ce_info_use *pce_info_use = NULL; + struct msm_bus_scale_pdata *qseecom_platform_support = NULL; qseecom.qsee_bw_count = 0; qseecom.qsee_perf_client = 0; @@ -9185,6 +9186,9 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.ce_drv.ce_bus_clk = qclk->ce_bus_clk; } + qseecom_platform_support = (struct msm_bus_scale_pdata *) + msm_bus_cl_get_pdata(pdev); + if (qseecom.qsee_version >= (QSEE_VERSION_02) && (!qseecom.is_apps_region_protected && !qseecom.appsbl_qseecom_support)) { @@ -9252,6 +9256,9 @@ static int qseecom_probe(struct platform_device *pdev) if (qseecom.is_apps_region_protected || qseecom.appsbl_qseecom_support) qseecom.commonlib_loaded = true; + } else { + qseecom_platform_support = (struct msm_bus_scale_pdata *) + pdev->dev.platform_data; } if (qseecom.support_bus_scaling) { @@ -9260,8 +9267,10 @@ static int qseecom_probe(struct platform_device *pdev) qseecom_bw_inactive_req_work); qseecom.bw_scale_down_timer.function = qseecom_scale_bus_bandwidth_timer_callback; + qseecom.timer_running = false; + qseecom.qsee_perf_client = msm_bus_scale_register_client( + qseecom_platform_support); } - qseecom.timer_running = false; qseecom.whitelist_support = qseecom_check_whitelist_feature(); pr_warn("qseecom.whitelist_support = %d\n", @@ -9291,6 +9300,9 @@ static int qseecom_probe(struct platform_device *pdev) atomic_set(&qseecom.unload_app_kthread_state, UNLOAD_APP_KT_SLEEP); + if (!qseecom.qsee_perf_client) + pr_err("Unable to register bus client\n"); + atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY); return 0; -- GitLab From fb34a13a6d5ced15666e5a1f98a674bff53cb76a Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Tue, 17 Mar 2020 13:44:43 +0530 Subject: [PATCH 0973/1055] usb: dwc3: Add support for 4 PHYs for dual port controller Add 2 new PHY instances (HS and SS) in dwc3 and dwc3-msm structures. Probe and initialize them when the controller is dual port capable. This capability is advertised by cores supporting only host mode using the DT flag 'qcom,dual-port'. Update PHY1 flags wherever applicable while maintaining single port controller support. Avoid workaround of SSPHY powerdown as a part of HS device connect because of the known HW bug of the other SSPHY going in and out of P3 when data transfers are being done. Change-Id: If52fd6383cc2da8b763c774d2ad688448f90aea0 Signed-off-by: Ajay Agarwal --- .../devicetree/bindings/usb/msm-ssusb.txt | 2 + drivers/usb/dwc3/core.c | 59 +++++- drivers/usb/dwc3/core.h | 12 +- drivers/usb/dwc3/dwc3-msm.c | 187 +++++++++++++++--- 4 files changed, 227 insertions(+), 33 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt index deab2aea6104..59f9afff2e6b 100644 --- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt @@ -93,6 +93,8 @@ Optional properties : capable DWC3 which does not have extcon handle. - qcom,default-mode-host: If present, start host mode on probe for an OTG capable DWC3 which does not have extcon handle. +- qcom,dual-port: If present, 2 different physical ports are supported by this + core. Please note that this flag is valid for cores supporting only host mode. Sub nodes: - Sub node for "DWC3- USB3 controller". diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 5637024fcade..e813d30e9572 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -198,6 +198,14 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) return ret; } + usb_phy_reset(dwc->usb2_phy1); + ret = usb_phy_init(dwc->usb2_phy1); + if (ret) { + pr_err("%s: usb_phy_init(dwc->usb2_phy1) returned %d\n", + __func__, ret); + return ret; + } + if (dwc->maximum_speed <= USB_SPEED_HIGH) goto generic_phy_init; @@ -215,6 +223,14 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc) return ret; } + usb_phy_reset(dwc->usb3_phy1); + ret = usb_phy_init(dwc->usb3_phy1); + if (ret) { + pr_err("%s: usb_phy_init(dwc->usb3_phy1) returned %d\n", + __func__, ret); + return ret; + } + generic_phy_init: ret = phy_init(dwc->usb2_generic_phy); if (ret < 0) @@ -670,12 +686,16 @@ static void dwc3_core_exit(struct dwc3 *dwc) { dwc3_event_buffers_cleanup(dwc); + usb_phy_shutdown(dwc->usb2_phy1); usb_phy_shutdown(dwc->usb2_phy); + usb_phy_shutdown(dwc->usb3_phy1); usb_phy_shutdown(dwc->usb3_phy); phy_exit(dwc->usb2_generic_phy); phy_exit(dwc->usb3_generic_phy); + usb_phy_set_suspend(dwc->usb2_phy1, 1); usb_phy_set_suspend(dwc->usb2_phy, 1); + usb_phy_set_suspend(dwc->usb3_phy1, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); phy_power_off(dwc->usb2_generic_phy); phy_power_off(dwc->usb3_generic_phy); @@ -854,8 +874,11 @@ int dwc3_core_init(struct dwc3 *dwc) dwc3_frame_length_adjustment(dwc); usb_phy_set_suspend(dwc->usb2_phy, 0); - if (dwc->maximum_speed >= USB_SPEED_SUPER) + usb_phy_set_suspend(dwc->usb2_phy1, 0); + if (dwc->maximum_speed >= USB_SPEED_SUPER) { usb_phy_set_suspend(dwc->usb3_phy, 0); + usb_phy_set_suspend(dwc->usb3_phy1, 0); + } ret = phy_power_on(dwc->usb2_generic_phy); if (ret < 0) @@ -958,11 +981,15 @@ int dwc3_core_init(struct dwc3 *dwc) phy_power_off(dwc->usb2_generic_phy); err2: + usb_phy_set_suspend(dwc->usb2_phy1, 1); + usb_phy_set_suspend(dwc->usb3_phy1, 1); usb_phy_set_suspend(dwc->usb2_phy, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); dwc3_free_scratch_buffers(dwc); err1: + usb_phy_shutdown(dwc->usb2_phy1); + usb_phy_shutdown(dwc->usb3_phy1); usb_phy_shutdown(dwc->usb2_phy); usb_phy_shutdown(dwc->usb3_phy); phy_exit(dwc->usb2_generic_phy); @@ -984,6 +1011,12 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) if (node) { dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); + if (dwc->dual_port) { + dwc->usb2_phy1 = devm_usb_get_phy_by_phandle(dev, + "usb-phy", 2); + dwc->usb3_phy1 = devm_usb_get_phy_by_phandle(dev, + "usb-phy", 3); + } } else { dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); @@ -1013,6 +1046,30 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) } } + if (dwc->dual_port) { + if (IS_ERR(dwc->usb2_phy1)) { + ret = PTR_ERR(dwc->usb2_phy1); + if (ret == -ENXIO || ret == -ENODEV) { + dwc->usb2_phy1 = NULL; + } else { + if (ret != -EPROBE_DEFER) + dev_err(dev, "no usb2 phy1 configured\n"); + return ret; + } + } + + if (IS_ERR(dwc->usb3_phy1)) { + ret = PTR_ERR(dwc->usb3_phy1); + if (ret == -ENXIO || ret == -ENODEV) { + dwc->usb3_phy1 = NULL; + } else { + if (ret != -EPROBE_DEFER) + dev_err(dev, "no usb3 phy1 configured\n"); + return ret; + } + } + } + dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); if (IS_ERR(dwc->usb2_generic_phy)) { ret = PTR_ERR(dwc->usb2_generic_phy); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 2f0c4d4cc548..96c0413c82a9 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -904,8 +904,10 @@ struct dwc3_scratchpad_array { * @hsphy_mode: UTMI phy mode, one of following: * - USBPHY_INTERFACE_MODE_UTMI * - USBPHY_INTERFACE_MODE_UTMIW - * @usb2_phy: pointer to USB2 PHY - * @usb3_phy: pointer to USB3 PHY + * @usb2_phy: pointer to USB2 PHY 0 + * @usb2_phy1: pointer to USB2 PHY 1 + * @usb3_phy: pointer to USB3 PHY 0 + * @usb3_phy1: pointer to USB3 PHY 1 * @usb2_generic_phy: pointer to USB2 PHY * @usb3_generic_phy: pointer to USB3 PHY * @phys_ready: flag to indicate that PHYs are ready @@ -998,6 +1000,7 @@ struct dwc3_scratchpad_array { * @bh_dbg_index: index for capturing bh_completion_time and bh_handled_evt_cnt * @last_run_stop: timestamp denoting the last run_stop update * @num_gsi_eps: number of GSI based hardware accelerated endpoints + * @dual_port: If true, this core supports two ports */ struct dwc3 { struct work_struct drd_work; @@ -1026,8 +1029,8 @@ struct dwc3 { struct usb_gadget gadget; struct usb_gadget_driver *gadget_driver; - struct usb_phy *usb2_phy; - struct usb_phy *usb3_phy; + struct usb_phy *usb2_phy, *usb2_phy1; + struct usb_phy *usb3_phy, *usb3_phy1; struct phy *usb2_generic_phy; struct phy *usb3_generic_phy; @@ -1219,6 +1222,7 @@ struct dwc3 { int retries_on_error; ktime_t last_run_stop; u32 num_gsi_eps; + bool dual_port; }; #define work_to_dwc(w) (container_of((w), struct dwc3, drd_work)) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 66895aa7e9f4..32562716d24c 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -262,6 +262,7 @@ struct dwc3_msm { struct regulator *dwc3_gdsc; struct usb_phy *hs_phy, *ss_phy; + struct usb_phy *hs_phy1, *ss_phy1; struct dbm *dbm; @@ -333,6 +334,7 @@ struct dwc3_msm { struct device_node *dwc3_node; struct property *num_gsi_eps; + bool dual_port; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ @@ -448,17 +450,37 @@ static bool dwc3_msm_is_host_superspeed(struct dwc3_msm *mdwc) { int i, num_ports; u32 reg; + bool is_host_ss = false; reg = dwc3_msm_read_reg(mdwc->base, USB3_HCSPARAMS1); num_ports = HCS_MAX_PORTS(reg); + /* + * For single port controller, PORTSC register 1 is for SS bus, hence it + * maps to the only SSPHY. But for dual port controllers, PORTSC + * registers 2 and 3 are for SS busses 0 and 1 respectively. Hence, + * PORTSC register 2 maps to SSPHY0 and 3 maps to SSPHY1. Handle the + * flag setting using the below logic which will also maintain single + * port core. + * num_ports = 2 (or) 4 (depending on no. of ports) + * ->num_ports/2 = 1 (or) 2 + * So, for single port core, i % (num_ports/2) = 0, hence we will always + * be updating SSPHY0 flags. + * For dual port, i % (num_ports/2) = 0 for port 0 (or) 1 for port 1. + * Hence we update SSPHY0 for reg 0 and 2; and SSPHY1 for reg 1 and 3. + */ for (i = 0; i < num_ports; i++) { reg = dwc3_msm_read_reg(mdwc->base, USB3_PORTSC + i*0x10); - if ((reg & PORT_PE) && DEV_SUPERSPEED_ANY(reg)) - return true; + if ((reg & PORT_PE) && DEV_SUPERSPEED_ANY(reg)) { + is_host_ss = true; + if (i % (num_ports / 2)) + mdwc->ss_phy1->flags |= DEVICE_IN_SS_MODE; + else + mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE; + } } - return false; + return is_host_ss; } static inline bool dwc3_msm_is_dev_superspeed(struct dwc3_msm *mdwc) @@ -2305,13 +2327,58 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc, bool ignore_p3_state) return 0; } +/* Generic functions to set/clear PHY flags */ +static void dwc3_msm_set_hsphy_flags(struct dwc3_msm *mdwc, int set) +{ + mdwc->hs_phy->flags |= set; + if (mdwc->hs_phy1) + mdwc->hs_phy1->flags |= set; +} + +static void dwc3_msm_clear_hsphy_flags(struct dwc3_msm *mdwc, int clear) +{ + mdwc->hs_phy->flags &= ~clear; + if (mdwc->hs_phy1) + mdwc->hs_phy1->flags &= ~clear; +} + +static void dwc3_msm_set_ssphy_flags(struct dwc3_msm *mdwc, int set) +{ + mdwc->ss_phy->flags |= set; + if (mdwc->ss_phy1) + mdwc->ss_phy1->flags |= set; +} + +static void dwc3_msm_clear_ssphy_flags(struct dwc3_msm *mdwc, int clear) +{ + mdwc->ss_phy->flags &= ~clear; + if (mdwc->ss_phy1) + mdwc->ss_phy1->flags &= ~clear; +} + static void dwc3_set_phy_speed_flags(struct dwc3_msm *mdwc) { struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); int i, num_ports; u32 reg; - mdwc->hs_phy->flags &= ~(PHY_HSFS_MODE | PHY_LS_MODE); + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HSFS_MODE | PHY_LS_MODE); + + /* + * For single port controller, there are 2 PORTSC registers, one for + * HS bus and other for SS bus, hence both mapping to the only HSPHY. + * But for dual port controllers, there are 4 PORTSC registers: 0 and 1 + * for HS busses 0 and 1 respectively; and registers 2 and 3 for SS + * busses 0 and 1 respectively. Hence, PORTSC registers 0 and 2 map to + * HSPHY 0 and registers 1 and 3 map to HSPHY1. Handle the flag setting + * using the below logic which will also maintain single port core. + * num_ports = 2 (or) 4 (depending on no. of ports) + * ->num_ports/2 = 1 (or) 2 + * So, for single port core, i % (num_ports/2) = 0, hence we will always + * be updating HSPHY0 flags. + * For dual port, i % (num_ports/2) = 0 for port 0 (or) 1 for port 1. + * Hence we update HSPHY0 for reg 0 and 2; and HSPHY1 for reg 1 and 3. + */ if (mdwc->in_host_mode) { reg = dwc3_msm_read_reg(mdwc->base, USB3_HCSPARAMS1); num_ports = HCS_MAX_PORTS(reg); @@ -2319,10 +2386,21 @@ static void dwc3_set_phy_speed_flags(struct dwc3_msm *mdwc) reg = dwc3_msm_read_reg(mdwc->base, USB3_PORTSC + i*0x10); if (reg & PORT_PE) { - if (DEV_HIGHSPEED(reg) || DEV_FULLSPEED(reg)) - mdwc->hs_phy->flags |= PHY_HSFS_MODE; - else if (DEV_LOWSPEED(reg)) - mdwc->hs_phy->flags |= PHY_LS_MODE; + if (DEV_HIGHSPEED(reg) || DEV_FULLSPEED(reg)) { + if (i % (num_ports / 2)) + mdwc->hs_phy1->flags |= + PHY_HSFS_MODE; + else + mdwc->hs_phy->flags |= + PHY_HSFS_MODE; + } else if (DEV_LOWSPEED(reg)) { + if (i % (num_ports / 2)) + mdwc->hs_phy1->flags |= + PHY_LS_MODE; + else + mdwc->hs_phy->flags |= + PHY_LS_MODE; + } } } } else { @@ -2556,6 +2634,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse, dwc3_set_phy_speed_flags(mdwc); /* Suspend HS PHY */ usb_phy_set_suspend(mdwc->hs_phy, 1); + usb_phy_set_suspend(mdwc->hs_phy1, 1); /* * Synopsys Superspeed PHY does not support ss_phy_irq, so to detect @@ -2579,9 +2658,10 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse, dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); } /* indicate phy about SS mode */ - if (dwc3_msm_is_superspeed(mdwc)) - mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE; + dwc3_msm_is_superspeed(mdwc); + usb_phy_set_suspend(mdwc->ss_phy, 1); + usb_phy_set_suspend(mdwc->ss_phy1, 1); mdwc->lpm_flags |= MDWC3_SS_PHY_SUSPEND; } else if (mdwc->use_pwr_event_for_wakeup) { dwc3_msm_set_ss_pwr_events(mdwc, true); @@ -2770,13 +2850,14 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) /* Resume SS PHY */ if (dwc->maximum_speed >= USB_SPEED_SUPER && mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND) { - mdwc->ss_phy->flags &= ~(PHY_LANE_A | PHY_LANE_B); + dwc3_msm_clear_ssphy_flags(mdwc, PHY_LANE_A | PHY_LANE_B); if (mdwc->typec_orientation == ORIENTATION_CC1) mdwc->ss_phy->flags |= PHY_LANE_A; if (mdwc->typec_orientation == ORIENTATION_CC2) mdwc->ss_phy->flags |= PHY_LANE_B; + usb_phy_set_suspend(mdwc->ss_phy1, 0); usb_phy_set_suspend(mdwc->ss_phy, 0); - mdwc->ss_phy->flags &= ~DEVICE_IN_SS_MODE; + dwc3_msm_clear_ssphy_flags(mdwc, DEVICE_IN_SS_MODE); mdwc->lpm_flags &= ~MDWC3_SS_PHY_SUSPEND; if (mdwc->in_host_mode) { @@ -2787,8 +2868,9 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) } } - mdwc->hs_phy->flags &= ~(PHY_HSFS_MODE | PHY_LS_MODE); + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HSFS_MODE | PHY_LS_MODE); /* Resume HS PHY */ + usb_phy_set_suspend(mdwc->hs_phy1, 0); usb_phy_set_suspend(mdwc->hs_phy, 0); /* Recover from controller power collapse */ @@ -3720,6 +3802,7 @@ static int dwc3_msm_probe(struct platform_device *pdev) mdwc->charging_disabled = of_property_read_bool(node, "qcom,charging-disabled"); + mdwc->dual_port = of_property_read_bool(node, "qcom,dual-port"); ret = of_property_read_u32(node, "qcom,lpm-to-suspend-delay-ms", &mdwc->lpm_to_suspend_delay); @@ -3909,6 +3992,24 @@ static int dwc3_msm_probe(struct platform_device *pdev) goto put_dwc3; } + if (mdwc->dual_port) { + mdwc->hs_phy1 = devm_usb_get_phy_by_phandle(&mdwc->dwc3->dev, + "usb-phy", 2); + if (IS_ERR(mdwc->hs_phy1)) { + dev_err(&pdev->dev, "unable to get hsphy1 device\n"); + ret = PTR_ERR(mdwc->hs_phy1); + goto put_dwc3; + } + + mdwc->ss_phy1 = devm_usb_get_phy_by_phandle(&mdwc->dwc3->dev, + "usb-phy", 3); + if (IS_ERR(mdwc->ss_phy1)) { + dev_err(&pdev->dev, "unable to get ssphy1 device\n"); + ret = PTR_ERR(mdwc->ss_phy1); + goto put_dwc3; + } + } + /* use default as nominal bus voting */ mdwc->default_bus_vote = BUS_VOTE_NOMINAL; ret = of_property_read_u32(node, "qcom,default-bus-vote", @@ -3969,6 +4070,13 @@ static int dwc3_msm_probe(struct platform_device *pdev) __func__); } + if (mdwc->dual_port && dwc->dr_mode != USB_DR_MODE_HOST) { + dev_err(&pdev->dev, "Dual port not allowed for DRD core\n"); + goto err_get_extcon; + } + + dwc->dual_port = mdwc->dual_port; + mutex_init(&mdwc->suspend_resume_mutex); if (of_property_read_bool(node, "extcon")) { @@ -4102,8 +4210,7 @@ static int dwc3_msm_remove(struct platform_device *pdev) cancel_delayed_work_sync(&mdwc->perf_vote_work); cancel_delayed_work_sync(&mdwc->sm_work); - if (mdwc->hs_phy) - mdwc->hs_phy->flags &= ~PHY_HOST_MODE; + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HOST_MODE); dbg_event(0xFF, "Remov put", 0); platform_device_put(mdwc->dwc3); of_platform_depopulate(&pdev->dev); @@ -4168,6 +4275,18 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb, if (event != USB_DEVICE_ADD && event != USB_DEVICE_REMOVE) return NOTIFY_DONE; + /* + * STAR: 9001378493: SSPHY1 going in and out of P3 when HS transfers + * being done on port 0. We do not need the below workaround of + * corresponding SSPHY powerdown for multiport controller. Instead, we + * will keep the SSPHY autosuspend disabled when USB is in resumed + * state. Since dual port controller is present only on automotive + * platforms, power leakage is not a concern. Also, as a part of USB + * suspend sequence, we will enable autosuspend for SSPHYs to go to P3. + */ + if (mdwc->dual_port) + return NOTIFY_DONE; + /* * For direct-attach devices, new udev is direct child of root hub * i.e. dwc -> xhci -> root_hub -> udev @@ -4287,23 +4406,26 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) if (on) { dev_dbg(mdwc->dev, "%s: turn on host\n", __func__); - mdwc->hs_phy->flags |= PHY_HOST_MODE; + dwc3_msm_set_hsphy_flags(mdwc, PHY_HOST_MODE); pm_runtime_get_sync(mdwc->dev); dbg_event(0xFF, "StrtHost gync", atomic_read(&mdwc->dev->power.usage_count)); if (dwc->maximum_speed >= USB_SPEED_SUPER) { - mdwc->ss_phy->flags |= PHY_HOST_MODE; + dwc3_msm_set_ssphy_flags(mdwc, PHY_HOST_MODE); usb_phy_notify_connect(mdwc->ss_phy, USB_SPEED_SUPER); + usb_phy_notify_connect(mdwc->ss_phy1, + USB_SPEED_SUPER); } usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH); + usb_phy_notify_connect(mdwc->hs_phy1, USB_SPEED_HIGH); if (!IS_ERR_OR_NULL(mdwc->vbus_reg)) ret = regulator_enable(mdwc->vbus_reg); if (ret) { dev_err(mdwc->dev, "unable to enable vbus_reg\n"); - mdwc->hs_phy->flags &= ~PHY_HOST_MODE; - mdwc->ss_phy->flags &= ~PHY_HOST_MODE; + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HOST_MODE); + dwc3_msm_clear_ssphy_flags(mdwc, PHY_HOST_MODE); pm_runtime_put_sync(mdwc->dev); dbg_event(0xFF, "vregerr psync", atomic_read(&mdwc->dev->power.usage_count)); @@ -4326,8 +4448,8 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) if (!IS_ERR_OR_NULL(mdwc->vbus_reg)) regulator_disable(mdwc->vbus_reg); - mdwc->hs_phy->flags &= ~PHY_HOST_MODE; - mdwc->ss_phy->flags &= ~PHY_HOST_MODE; + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HOST_MODE); + dwc3_msm_clear_ssphy_flags(mdwc, PHY_HOST_MODE); pm_runtime_put_sync(mdwc->dev); dbg_event(0xFF, "pdeverr psync", atomic_read(&mdwc->dev->power.usage_count)); @@ -4386,14 +4508,17 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) pm_runtime_get_sync(mdwc->dev); dbg_event(0xFF, "StopHost gsync", atomic_read(&mdwc->dev->power.usage_count)); + usb_phy_notify_disconnect(mdwc->hs_phy1, USB_SPEED_HIGH); usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH); - if (mdwc->ss_phy->flags & PHY_HOST_MODE) { + if (dwc->maximum_speed >= USB_SPEED_SUPER) { + usb_phy_notify_disconnect(mdwc->ss_phy1, + USB_SPEED_SUPER); usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER); - mdwc->ss_phy->flags &= ~PHY_HOST_MODE; } - mdwc->hs_phy->flags &= ~PHY_HOST_MODE; + dwc3_msm_clear_ssphy_flags(mdwc, PHY_HOST_MODE); + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HOST_MODE); dwc3_host_exit(dwc); usb_unregister_notify(&mdwc->host_nb); @@ -4918,10 +5043,12 @@ static int dwc3_msm_pm_freeze(struct device *dev) * PHYs also need to be power collapsed, so call notify_disconnect * before suspend to ensure it. */ + usb_phy_notify_disconnect(mdwc->hs_phy1, USB_SPEED_HIGH); usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH); - mdwc->hs_phy->flags &= ~PHY_HOST_MODE; + dwc3_msm_clear_hsphy_flags(mdwc, PHY_HOST_MODE); + usb_phy_notify_disconnect(mdwc->ss_phy1, USB_SPEED_SUPER); usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER); - mdwc->ss_phy->flags &= ~PHY_HOST_MODE; + dwc3_msm_clear_ssphy_flags(mdwc, PHY_HOST_MODE); /* * Power collapse the core. Hence call dwc3_msm_suspend with @@ -4960,12 +5087,16 @@ static int dwc3_msm_pm_restore(struct device *dev) pm_runtime_enable(dev); /* Restore PHY flags if hibernated in host mode */ - mdwc->hs_phy->flags |= PHY_HOST_MODE; + dwc3_msm_set_hsphy_flags(mdwc, PHY_HOST_MODE); usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH); + usb_phy_notify_connect(mdwc->hs_phy1, USB_SPEED_HIGH); + if (dwc->maximum_speed >= USB_SPEED_SUPER) { - mdwc->ss_phy->flags |= PHY_HOST_MODE; + dwc3_msm_set_ssphy_flags(mdwc, PHY_HOST_MODE); usb_phy_notify_connect(mdwc->ss_phy, USB_SPEED_SUPER); + usb_phy_notify_connect(mdwc->ss_phy1, + USB_SPEED_SUPER); } /* kick in otg state machine */ -- GitLab From 9224f27e7de568bfce241d078651ffe1e043b3bb Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Tue, 17 Mar 2020 14:26:07 +0530 Subject: [PATCH 0974/1055] usb: dwc3-msm: Add support for 2nd set of wakeup IRQs Certain targets may have a dual port capable host controller. Add support for the PHY IRQs for the second port. Since the SSPHY autosuspend will be disabled for such controllers, remove the support of pwr_evnt_irq as a mandatory IRQ and allow SSPHY to go into P3 as a part of suspend sequence. Handle the logic gracefully to maintain single port controllers. Change-Id: I5a53d6e23f64bec7ae940d23923df310309a28da Signed-off-by: Ajay Agarwal --- drivers/usb/dwc3/core.h | 2 +- drivers/usb/dwc3/dwc3-msm.c | 163 +++++++++++++++++++++++++++++++++--- 2 files changed, 152 insertions(+), 13 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 96c0413c82a9..ae63ee62491f 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -167,7 +167,7 @@ #define GEN2_U3_EXIT_RSP_RX_CLK_MASK GEN2_U3_EXIT_RSP_RX_CLK(0xff) #define GEN1_U3_EXIT_RSP_RX_CLK(n) (n) #define GEN1_U3_EXIT_RSP_RX_CLK_MASK GEN1_U3_EXIT_RSP_RX_CLK(0xff) -#define DWC31_LINK_GDBGLTSSM 0xd050 +#define DWC31_LINK_GDBGLTSSM(n) (0xd050 + ((n) * 0x80)) /* Bit fields */ diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 32562716d24c..33b509afd2cc 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -79,6 +79,7 @@ #define CGCTL_REG (QSCRATCH_REG_OFFSET + 0x28) #define PWR_EVNT_IRQ_STAT_REG (QSCRATCH_REG_OFFSET + 0x58) #define PWR_EVNT_IRQ_MASK_REG (QSCRATCH_REG_OFFSET + 0x5C) +#define PWR_EVNT_IRQ_STAT_REG1 (QSCRATCH_REG_OFFSET + 0x1DC) #define PWR_EVNT_POWERDOWN_IN_P3_MASK BIT(2) #define PWR_EVNT_POWERDOWN_OUT_P3_MASK BIT(3) @@ -185,6 +186,9 @@ enum msm_usb_irq { DP_HS_PHY_IRQ, DM_HS_PHY_IRQ, SS_PHY_IRQ, + DP_HS_PHY_IRQ_1, + DM_HS_PHY_IRQ_1, + SS_PHY_IRQ_1, USB_MAX_IRQ }; @@ -208,6 +212,9 @@ static const struct usb_irq usb_irq_info[USB_MAX_IRQ] = { {"dp_hs_phy_irq", 0}, {"dm_hs_phy_irq", 0}, {"ss_phy_irq", 0}, + {"dp_hs_phy_irq1", 0}, + {"dm_hs_phy_irq1", 0}, + {"ss_phy_irq1", 0}, }; static const char * const gsi_op_strings[] = { @@ -2246,7 +2253,7 @@ static void dwc3_msm_block_reset(struct dwc3_msm *mdwc, bool core_reset) static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) { struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); - u32 val; + u32 val, val1; int ret; /* Configure AHB2PHY for one wait state read/write */ @@ -2269,15 +2276,27 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) __func__, ret); /* Get initial P3 status and enable IN_P3 event */ - if (dwc3_is_usb31(dwc)) + if (dwc3_is_usb31(dwc)) { val = dwc3_msm_read_reg_field(mdwc->base, - DWC31_LINK_GDBGLTSSM, + DWC31_LINK_GDBGLTSSM(0), DWC3_GDBGLTSSM_LINKSTATE_MASK); - else + if (mdwc->dual_port) + val1 = dwc3_msm_read_reg_field(mdwc->base, + DWC31_LINK_GDBGLTSSM(1), + DWC3_GDBGLTSSM_LINKSTATE_MASK); + } else { val = dwc3_msm_read_reg_field(mdwc->base, DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK); - atomic_set(&mdwc->in_p3, val == DWC3_LINK_STATE_U3); - dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, + } + + if (!mdwc->dual_port) + val1 = DWC3_LINK_STATE_U3; + + atomic_set(&mdwc->in_p3, (val == DWC3_LINK_STATE_U3) && + (val1 == DWC3_LINK_STATE_U3)); + + if (!mdwc->dual_port) + dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG, PWR_EVNT_POWERDOWN_IN_P3_MASK, 1); /* Set the core in host mode if it was in host mode during pm_suspend */ @@ -2288,6 +2307,44 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) } +static void dwc3_msm_dp_ssphy_autosuspend(struct dwc3_msm *mdwc) +{ + unsigned long timeout; + u32 reg = 0, reg1 = 0; + + /* Clear previous P3 events */ + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, + PWR_EVNT_POWERDOWN_IN_P3_MASK | PWR_EVNT_POWERDOWN_OUT_P3_MASK); + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG1, + PWR_EVNT_POWERDOWN_IN_P3_MASK | PWR_EVNT_POWERDOWN_OUT_P3_MASK); + + /* Prepare SSPHYs for suspend */ + reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB3PIPECTL(0)); + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB3PIPECTL(0), + reg | DWC3_GUSB3PIPECTL_SUSPHY); + reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB3PIPECTL(1)); + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB3PIPECTL(1), + reg | DWC3_GUSB3PIPECTL_SUSPHY); + + /* Wait for PHYs to go into P3 */ + timeout = jiffies + msecs_to_jiffies(5); + while (!time_after(jiffies, timeout)) { + reg = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG); + reg1 = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG1); + if ((reg & PWR_EVNT_POWERDOWN_IN_P3_MASK) && + (reg1 & PWR_EVNT_POWERDOWN_IN_P3_MASK)) { + atomic_set(&mdwc->in_p3, 1); + break; + } + } + + /* Clear P3 event bit */ + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, + PWR_EVNT_POWERDOWN_IN_P3_MASK); + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG1, + PWR_EVNT_POWERDOWN_IN_P3_MASK); +} + static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc, bool ignore_p3_state) { unsigned long timeout; @@ -2295,6 +2352,9 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc, bool ignore_p3_state) if (!ignore_p3_state && ((mdwc->in_host_mode || mdwc->in_device_mode) && dwc3_msm_is_superspeed(mdwc) && !mdwc->in_restart)) { + /* Allow SSPHYs to go to P3 for dual port controllers */ + if (mdwc->dual_port) + dwc3_msm_dp_ssphy_autosuspend(mdwc); if (!atomic_read(&mdwc->in_p3)) { dev_err(mdwc->dev, "Not in P3,aborting LPM sequence\n"); return -EBUSY; @@ -2324,6 +2384,33 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc, bool ignore_p3_state) dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG, PWR_EVNT_LPM_IN_L2_MASK); + /* Handling for dual port core */ + if (!mdwc->dual_port) + return 0; + + /* Clear previous L2 events */ + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG1, + PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK); + + /* Prepare HSPHY for suspend */ + reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(1)); + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(1), + reg | DWC3_GUSB2PHYCFG_ENBLSLPM | DWC3_GUSB2PHYCFG_SUSPHY); + + /* Wait for PHY to go into L2 */ + timeout = jiffies + msecs_to_jiffies(5); + while (!time_after(jiffies, timeout)) { + reg = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG1); + if (reg & PWR_EVNT_LPM_IN_L2_MASK) + break; + } + if (!(reg & PWR_EVNT_LPM_IN_L2_MASK)) + dev_err(mdwc->dev, "could not transition HS PHY1 to L2\n"); + + /* Clear L2 event bit */ + dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG1, + PWR_EVNT_LPM_IN_L2_MASK); + return 0; } @@ -2461,12 +2548,40 @@ static void enable_usb_pdc_interrupt(struct dwc3_msm *mdwc, bool enable) IRQ_TYPE_EDGE_RISING, true); } + if (mdwc->dual_port) { + if (mdwc->hs_phy1->flags & PHY_LS_MODE) { + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[DM_HS_PHY_IRQ_1], + IRQ_TYPE_EDGE_FALLING, enable); + } else if (mdwc->hs_phy1->flags & PHY_HSFS_MODE) { + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[DP_HS_PHY_IRQ_1], + IRQ_TYPE_EDGE_FALLING, enable); + } else { + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[DP_HS_PHY_IRQ_1], + IRQ_TYPE_EDGE_RISING, true); + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[DM_HS_PHY_IRQ_1], + IRQ_TYPE_EDGE_RISING, true); + } + } + configure_usb_wakeup_interrupt(mdwc, &mdwc->wakeup_irq[SS_PHY_IRQ], IRQF_TRIGGER_HIGH | IRQ_TYPE_LEVEL_HIGH, enable); + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[SS_PHY_IRQ_1], + IRQF_TRIGGER_HIGH | IRQ_TYPE_LEVEL_HIGH, enable); return; disable_usb_irq: + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[DP_HS_PHY_IRQ_1], 0, enable); + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[DM_HS_PHY_IRQ_1], 0, enable); + configure_usb_wakeup_interrupt(mdwc, + &mdwc->wakeup_irq[SS_PHY_IRQ_1], 0, enable); configure_usb_wakeup_interrupt(mdwc, &mdwc->wakeup_irq[DP_HS_PHY_IRQ], 0, enable); configure_usb_wakeup_interrupt(mdwc, @@ -2902,6 +3017,21 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0)) & ~DWC3_GUSB2PHYCFG_SUSPHY); + if (mdwc->dual_port) + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(1), + dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(1)) & + ~DWC3_GUSB2PHYCFG_SUSPHY); + + if (dwc->dis_u3_susphy_quirk) { + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB3PIPECTL(0), + dwc3_msm_read_reg(mdwc->base, DWC3_GUSB3PIPECTL(0)) & + ~DWC3_GUSB3PIPECTL_SUSPHY); + if (mdwc->dual_port) + dwc3_msm_write_reg(mdwc->base, DWC3_GUSB3PIPECTL(1), + dwc3_msm_read_reg(mdwc->base, DWC3_GUSB3PIPECTL(1)) & + ~DWC3_GUSB3PIPECTL_SUSPHY); + } + /* Disable wakeup capable for HS_PHY IRQ & SS_PHY_IRQ if enabled */ if (mdwc->lpm_flags & MDWC3_ASYNC_IRQ_WAKE_CAPABILITY) { if (mdwc->use_pdc_interrupts) { @@ -3078,7 +3208,7 @@ static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc) /* Can't tell if entered or exit P3, so check LINKSTATE */ if (dwc3_is_usb31(dwc)) ls = dwc3_msm_read_reg_field(mdwc->base, - DWC31_LINK_GDBGLTSSM, + DWC31_LINK_GDBGLTSSM(0), DWC3_GDBGLTSSM_LINKSTATE_MASK); else ls = dwc3_msm_read_reg_field(mdwc->base, @@ -3103,7 +3233,7 @@ static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc) /* Clear L2 exit */ if (irq_stat & PWR_EVNT_LPM_OUT_L2_MASK) { irq_stat &= ~PWR_EVNT_LPM_OUT_L2_MASK; - irq_stat |= PWR_EVNT_LPM_OUT_L2_MASK; + irq_clear |= PWR_EVNT_LPM_OUT_L2_MASK; } /* Handle exit from L1 events */ @@ -3817,9 +3947,10 @@ static int dwc3_msm_probe(struct platform_device *pdev) IRQF_ONESHOT; mdwc->wakeup_irq[i].irq = platform_get_irq_byname(pdev, mdwc->wakeup_irq[i].name); + /* pwr_evnt_irq is only mandatory irq for single port core */ if (mdwc->wakeup_irq[i].irq < 0) { - /* pwr_evnt_irq is only mandatory irq */ - if (!strcmp(mdwc->wakeup_irq[i].name, + if (!mdwc->dual_port && + !strcmp(mdwc->wakeup_irq[i].name, "pwr_event_irq")) { dev_err(&pdev->dev, "get_irq for %s failed\n\n", mdwc->wakeup_irq[i].name); @@ -3831,7 +3962,8 @@ static int dwc3_msm_probe(struct platform_device *pdev) irq_set_status_flags(mdwc->wakeup_irq[i].irq, IRQ_NOAUTOEN); /* ss_phy_irq is level trigger interrupt */ - if (!strcmp(mdwc->wakeup_irq[i].name, "ss_phy_irq")) + if (!strncmp(mdwc->wakeup_irq[i].name, + "ss_phy_irq", 10)) irq_type = IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQ_TYPE_LEVEL_HIGH | IRQF_EARLY_RESUME; @@ -3903,7 +4035,8 @@ static int dwc3_msm_probe(struct platform_device *pdev) /* Add power event if the dbm indicates coming out of L1 by interrupt */ if (mdwc->dbm && dbm_l1_lpm_interrupt(mdwc->dbm)) { - if (!mdwc->wakeup_irq[PWR_EVNT_IRQ].irq) { + /* Dual port core does not need pwr_evnt_irq */ + if (!mdwc->dual_port && !mdwc->wakeup_irq[PWR_EVNT_IRQ].irq) { dev_err(&pdev->dev, "need pwr_event_irq exiting L1\n"); ret = -EINVAL; @@ -4241,6 +4374,12 @@ static int dwc3_msm_remove(struct platform_device *pdev) disable_irq(mdwc->wakeup_irq[DM_HS_PHY_IRQ].irq); if (mdwc->wakeup_irq[SS_PHY_IRQ].irq) disable_irq(mdwc->wakeup_irq[SS_PHY_IRQ].irq); + if (mdwc->wakeup_irq[DP_HS_PHY_IRQ_1].irq) + disable_irq(mdwc->wakeup_irq[DP_HS_PHY_IRQ_1].irq); + if (mdwc->wakeup_irq[DM_HS_PHY_IRQ_1].irq) + disable_irq(mdwc->wakeup_irq[DM_HS_PHY_IRQ_1].irq); + if (mdwc->wakeup_irq[SS_PHY_IRQ_1].irq) + disable_irq(mdwc->wakeup_irq[SS_PHY_IRQ_1].irq); disable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq); clk_disable_unprepare(mdwc->utmi_clk); -- GitLab From 62f3232d497c81e67761e62942c6905a93ff08b3 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Mon, 29 Jun 2020 21:34:01 +0530 Subject: [PATCH 0975/1055] usb: dwc3: Write necessary registers for dual port enablement In line with the sequence for primary port, update proper fields of DWC3_GUSB2PHYCFG and DWC3_GUSB3PIPECTL registers for the second port of the dual port controller. Update other registers as required. While at it, also avoid enabling SSPHY autosuspend if dis_u3_susphy_quirk is set. Change-Id: Ib79dba4c6d854fa2bf33a1b7cecf06f988250662 Signed-off-by: Ajay Agarwal --- drivers/usb/dwc3/core.c | 32 ++++++++++++++++++++++++++++++++ drivers/usb/dwc3/dwc3-msm.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index e813d30e9572..4dcb96aeb6ac 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -59,6 +59,9 @@ void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend) { u32 reg; + if (dwc->dis_u3_susphy_quirk) + return; + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); if (suspend) @@ -67,6 +70,17 @@ void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend) reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + + if (dwc->dual_port) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(1)); + + if (suspend) + reg |= DWC3_GUSB3PIPECTL_SUSPHY; + else + reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; + + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(1), reg); + } } /** @@ -143,6 +157,12 @@ void dwc3_en_sleep_mode(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg |= DWC3_GUSB2PHYCFG_ENBLSLPM; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + + if (dwc->dual_port) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(1)); + reg |= DWC3_GUSB2PHYCFG_ENBLSLPM; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(1), reg); + } } void dwc3_dis_sleep_mode(struct dwc3 *dwc) @@ -565,6 +585,10 @@ static int dwc3_phy_setup(struct dwc3 *dwc) u32 reg; reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + if (dwc->dual_port) { + if (reg != dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(1))) + dev_warn(dwc->dev, "Reset values of pipectl registers are different!\n"); + } /* * Make sure UX_EXIT_PX is cleared as that causes issues with some @@ -616,8 +640,14 @@ static int dwc3_phy_setup(struct dwc3 *dwc) DWC3_GUSB3PIPECTL_P3EXSIGP2); dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + if (dwc->dual_port) + dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(1), reg); reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + if (dwc->dual_port) { + if (reg != dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(1))) + dev_warn(dwc->dev, "Reset values of usb2phycfg registers are different!\n"); + } /* Select the HS PHY interface */ switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) { @@ -678,6 +708,8 @@ static int dwc3_phy_setup(struct dwc3 *dwc) reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + if (dwc->dual_port) + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(1), reg); return 0; } diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 33b509afd2cc..9bfad4bfbb02 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -2771,6 +2771,14 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse, reg |= DWC3_GUSB3PIPECTL_DISRXDETU3; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + + if (mdwc->dual_port) { + reg = dwc3_readl(dwc->regs, + DWC3_GUSB3PIPECTL(1)); + reg |= DWC3_GUSB3PIPECTL_DISRXDETU3; + dwc3_writel(dwc->regs, + DWC3_GUSB3PIPECTL(1), reg); + } } /* indicate phy about SS mode */ dwc3_msm_is_superspeed(mdwc); @@ -2980,6 +2988,14 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc) reg &= ~DWC3_GUSB3PIPECTL_DISRXDETU3; dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); + + if (mdwc->dual_port) { + reg = dwc3_readl(dwc->regs, + DWC3_GUSB3PIPECTL(1)); + reg &= ~DWC3_GUSB3PIPECTL_DISRXDETU3; + dwc3_writel(dwc->regs, + DWC3_GUSB3PIPECTL(1), reg); + } } } @@ -4609,9 +4625,21 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) dwc3_msm_write_reg_field(mdwc->base, DWC31_LINK_LU3LFPSRXTIM(0), GEN1_U3_EXIT_RSP_RX_CLK_MASK, 5); - dev_dbg(mdwc->dev, "LU3:%08x\n", + dev_dbg(mdwc->dev, "link0 LU3:%08x\n", dwc3_msm_read_reg(mdwc->base, DWC31_LINK_LU3LFPSRXTIM(0))); + + if (mdwc->dual_port) { + dwc3_msm_write_reg_field(mdwc->base, + DWC31_LINK_LU3LFPSRXTIM(1), + GEN2_U3_EXIT_RSP_RX_CLK_MASK, 6); + dwc3_msm_write_reg_field(mdwc->base, + DWC31_LINK_LU3LFPSRXTIM(1), + GEN1_U3_EXIT_RSP_RX_CLK_MASK, 5); + dev_dbg(mdwc->dev, "link1 LU3:%08x\n", + dwc3_msm_read_reg(mdwc->base, + DWC31_LINK_LU3LFPSRXTIM(1))); + } } /* xHCI should have incremented child count as necessary */ -- GitLab From 5644fe4a6deb3cdb78ede09ab382374fe4d89d67 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Thu, 26 Dec 2019 11:04:21 +0530 Subject: [PATCH 0976/1055] ARM: dts: msm: Add multiport USB controller and PHYs on sdmshrike sdmshrike has a third USB controller which is dual port capable. Add support for this controller and the corresponding PHYs. For the driver to handle this as dual port controller, add 'qcom,dual-port' flag to the node. Enable the same for sa8195p. While at this, also fix the SS phy IRQ number for USB1 and PHY init sequence for USB1 HSPHY. Remove other unrequired configs from USB0 and USB1. Change-Id: I1fbd9e1ddbd74ee4b7a0ad03ea7313c96391379f Signed-off-by: Ajay Agarwal --- arch/arm64/boot/dts/qcom/sa8195p.dtsi | 31 ++ arch/arm64/boot/dts/qcom/sdmshrike-usb.dtsi | 429 ++++++++++++++++++-- 2 files changed, 434 insertions(+), 26 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa8195p.dtsi b/arch/arm64/boot/dts/qcom/sa8195p.dtsi index 863c5330d7e5..3e31e5d48b2a 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p.dtsi @@ -294,6 +294,11 @@ status = "ok"; }; +&usb2 { + qcom,ignore-wakeup-src-in-hostmode; + status = "ok"; +}; + &slpi_tlmm { status = "ok"; }; @@ -379,6 +384,32 @@ status = "ok"; }; +&usb2_phy2 { + vdd-supply = <&pm8195_3_l5>; + vdda18-supply = <&pm8195_1_l12>; + vdda33-supply = <&pm8195_3_l16>; + status = "ok"; +}; + +&usb_qmp_phy0 { + vdd-supply = <&pm8195_3_l9>; + core-supply = <&pm8195_1_l9>; + status = "ok"; +}; + +&usb2_phy3 { + vdd-supply = <&pm8195_3_l5>; + vdda18-supply = <&pm8195_1_l12>; + vdda33-supply = <&pm8195_3_l16>; + status = "ok"; +}; + +&usb_qmp_phy1 { + vdd-supply = <&pm8195_3_l9>; + core-supply = <&pm8195_1_l9>; + status = "ok"; +}; + &mdss_dsi_phy0 { vdda-0p9-supply = <&pm8195_3_l5>; }; diff --git a/arch/arm64/boot/dts/qcom/sdmshrike-usb.dtsi b/arch/arm64/boot/dts/qcom/sdmshrike-usb.dtsi index 9362ddd57f99..9807f0bb4c92 100644 --- a/arch/arm64/boot/dts/qcom/sdmshrike-usb.dtsi +++ b/arch/arm64/boot/dts/qcom/sdmshrike-usb.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, 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 @@ -46,26 +46,25 @@ qcom,core-clk-rate = <200000000>; qcom,core-clk-rate-hs = <66666667>; - qcom,num-gsi-evt-buffs = <0x3>; - qcom,gsi-reg-offset = - <0x0fc /* GSI_GENERAL_CFG */ - 0x110 /* GSI_DBL_ADDR_L */ - 0x120 /* GSI_DBL_ADDR_H */ - 0x130 /* GSI_RING_BASE_ADDR_L */ - 0x144 /* GSI_RING_BASE_ADDR_H */ - 0x1a4>; /* GSI_IF_STS */ qcom,dwc-usb3-msm-tx-fifo-size = <27696>; + qcom,charging-disabled; qcom,msm-bus,name = "usb0"; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = + /* suspend vote */ , - , , + + /* nominal vote */ , - , + , + + /* svs vote */ + , ; dwc3@a600000 { @@ -149,7 +148,7 @@ #size-cells = <1>; ranges; - interrupts = <0 491 0>, <0 135 0>, <0 487 0>, <0 490 0>; + interrupts = <0 491 0>, <0 135 0>, <0 520 0>, <0 490 0>; interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", "ss_phy_irq", "dm_hs_phy_irq"; qcom,use-pdc-interrupts; @@ -169,36 +168,25 @@ qcom,core-clk-rate = <200000000>; qcom,core-clk-rate-hs = <66666667>; - qcom,num-gsi-evt-buffs = <0x3>; - qcom,gsi-reg-offset = - <0x0fc /* GSI_GENERAL_CFG */ - 0x110 /* GSI_DBL_ADDR_L */ - 0x120 /* GSI_DBL_ADDR_H */ - 0x130 /* GSI_RING_BASE_ADDR_L */ - 0x144 /* GSI_RING_BASE_ADDR_H */ - 0x1a4>; /* GSI_IF_STS */ qcom,dwc-usb3-msm-tx-fifo-size = <27696>; qcom,charging-disabled; qcom,msm-bus,name = "usb1"; qcom,msm-bus,num-cases = <3>; - qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = /* suspend vote */ , - , , /* nominal vote */ , - , , /* svs vote */ , - , ; status = "disabled"; @@ -236,6 +224,395 @@ resets = <&clock_gcc GCC_QUSB2PHY_SEC_BCR>; reset-names = "phy_reset"; + qcom,param-override-seq = <0x43 0x70>; + + status = "disabled"; + }; + + /* Tertiary USB port related controller */ + usb2: ssusb@a400000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a400000 0x100000>; + reg-names = "core_base"; + + iommus = <&apps_smmu 0x60 0x0>; + qcom,smmu-s1-bypass; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 539 0>, <0 487 0>, <0 526 0>, + <0 551 0>, <0 510 0>, <0 548 0>; + interrupt-names = "dp_hs_phy_irq", "ss_phy_irq", + "dm_hs_phy_irq", "dp_hs_phy_irq1", + "ss_phy_irq1", "dm_hs_phy_irq1"; + qcom,use-pdc-interrupts; + + USB3_GDSC-supply = <&usb30_mp_gdsc>; + clocks = <&clock_gcc GCC_USB30_MP_MASTER_CLK>, + <&clock_gcc GCC_CFG_NOC_USB3_MP_AXI_CLK>, + <&clock_gcc GCC_AGGRE_USB3_MP_AXI_CLK>, + <&clock_gcc GCC_USB30_MP_MOCK_UTMI_CLK>, + <&clock_gcc GCC_USB30_MP_SLEEP_CLK>, + <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "utmi_clk", "sleep_clk", "xo"; + + resets = <&clock_gcc GCC_USB30_MP_BCR>; + reset-names = "core_reset"; + + qcom,core-clk-rate = <200000000>; + qcom,charging-disabled; + qcom,dual-port; + + qcom,msm-bus,name = "usb2"; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + /* suspend vote */ + , + + /* nominal vote */ + , + + /* svs vote */ + ; + + status = "disabled"; + + dwc3@a400000 { + compatible = "snps,dwc3"; + reg = <0x0a400000 0xcd00>; + interrupts = <0 654 0>; + usb-phy = <&usb2_phy2>, <&usb_qmp_phy0>, + <&usb2_phy3>, <&usb_qmp_phy1>; + linux,sysdev_is_parent; + snps,disable-clk-gating; + snps,has-lpm-erratum; + snps,hird-threshold = /bits/ 8 <0x10>; + snps,ssp-u3-u0-quirk; + snps,usb3-u1u2-disable; + snps,dis_u3_susphy_quirk; + usb-core-id = <2>; + maximum-speed = "super-speed-plus"; + dr_mode = "host"; + }; + }; + + /* Tertiary USB port 0 related High Speed PHY */ + usb2_phy2: hsphy@88e4000 { + compatible = "qcom,usb-hsphy-snps-femto"; + reg = <0x88e4000 0x110>; + reg-names = "hsusb_phy_base"; + + vdd-supply = <&pm8150_2_l5>; + vdda18-supply = <&pm8150_1_l12>; + vdda33-supply = <&pm8150_2_l16>; + qcom,vdd-voltage-level = <0 880000 880000>; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "ref_clk_src"; + + resets = <&clock_gcc GCC_QUSB2PHY_MP0_BCR>; + reset-names = "phy_reset"; + qcom,param-override-seq = <0x43 0x70>; + + status = "disabled"; + }; + + /* Tertiary USB port 0 related QMP PHY */ + usb_qmp_phy0: ssphy@88eb000 { + compatible = "qcom,usb-ssphy-qmp-v2"; + reg = <0x88eb000 0x1000>, + <0x088eb88c 0x4>; + reg-names = "qmp_phy_base", + "pcs_clamp_enable_reg"; + + vdd-supply = <&pm8150_1_l9>; + qcom,vdd-voltage-level = <0 880000 880000>; + qcom,vdd-max-load-uA = <47000>; + core-supply = <&pm8150_2_l16>; + qcom,qmp-phy-init-seq = + /* */ + ; + + qcom,qmp-phy-reg-offset = + ; + + clocks = <&clock_gcc GCC_USB3_MP_PHY_AUX_CLK>, + <&clock_gcc GCC_USB3_MP_PHY_PIPE_0_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_SEC_CLKREF_CLK>, + <&clock_gcc GCC_USB3_MP_PHY_COM_AUX_CLK>; + clock-names = "aux_clk", "pipe_clk", "ref_clk_src", + "ref_clk", "com_aux_clk"; + + resets = <&clock_gcc GCC_USB3_UNIPHY_MP0_BCR>, + <&clock_gcc GCC_USB3UNIPHY_PHY_MP0_BCR>; + reset-names = "phy_reset", "phy_phy_reset"; + + status = "disabled"; + }; + + /* Tertiary USB port 1 related High Speed PHY */ + usb2_phy3: hsphy@88e5000 { + compatible = "qcom,usb-hsphy-snps-femto"; + reg = <0x88e5000 0x110>; + reg-names = "hsusb_phy_base"; + + vdd-supply = <&pm8150_2_l5>; + vdda18-supply = <&pm8150_1_l12>; + vdda33-supply = <&pm8150_2_l16>; + qcom,vdd-voltage-level = <0 880000 880000>; + + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "ref_clk_src"; + + resets = <&clock_gcc GCC_QUSB2PHY_MP1_BCR>; + reset-names = "phy_reset"; + qcom,param-override-seq = <0x43 0x70>; + + status = "disabled"; + }; + + /* Tertiary USB port 1 related QMP PHY */ + usb_qmp_phy1: ssphy@88ec000 { + compatible = "qcom,usb-ssphy-qmp-v2"; + reg = <0x88ec000 0x1000>, + <0x088ec88c 0x4>; + reg-names = "qmp_phy_base", + "pcs_clamp_enable_reg"; + + vdd-supply = <&pm8150_1_l9>; + qcom,vdd-voltage-level = <0 880000 880000>; + qcom,vdd-max-load-uA = <47000>; + core-supply = <&pm8150_2_l16>; + qcom,qmp-phy-init-seq = + /* */ + ; + + qcom,qmp-phy-reg-offset = + ; + + clocks = <&clock_gcc GCC_USB3_MP_PHY_AUX_CLK>, + <&clock_gcc GCC_USB3_MP_PHY_PIPE_1_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_PCIE_1_CLKREF_CLK>, + <&clock_gcc GCC_USB3_MP_PHY_COM_AUX_CLK>; + clock-names = "aux_clk", "pipe_clk", "ref_clk_src", + "ref_clk", "com_aux_clk"; + + resets = <&clock_gcc GCC_USB3_UNIPHY_MP1_BCR>, + <&clock_gcc GCC_USB3UNIPHY_PHY_MP1_BCR>; + reset-names = "phy_reset", "phy_phy_reset"; status = "disabled"; }; -- GitLab From 55793058f5e1e6183961546f0f0664e7d8558b02 Mon Sep 17 00:00:00 2001 From: Sneh Shah Date: Wed, 1 Jul 2020 15:11:21 +0530 Subject: [PATCH 0977/1055] arm: dts: msm: Add dt entry to enable geometry mapping in stmmac Add dt entry to to enable geometry mapping for fastmap to save memory. Change-Id: I22fa1b075c322e81ecbc5b7a9fd4bbfe1f6a45b5 Signed-off-by: Sneh Shah --- arch/arm64/boot/dts/qcom/sdxprairie.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index d6d12e56951c..2f5b2c882a13 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -1526,6 +1526,7 @@ compatible = "qcom,emac-smmu-embedded"; iommus = <&apps_smmu 0x1c0 0xf>; qcom,iova-mapping = <0x80000000 0x40000000>; + qcom,smmu-geometry; }; }; -- GitLab From ab044b053591316030826d8ac2481b7a18515029 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 7 Oct 2019 17:44:20 -0700 Subject: [PATCH 0978/1055] power: smb5-lib: Show unknown battery status for debug battery For a debug battery (battery id is 7.5 K), show the battery status as unknown instead of discharging/not charging. Since the charging is disabled for debug battery, this makes sense. Also, it helps the userspace to stay in poweron mode based on the user request. Change-Id: Ia83e2c3903a01c0f61e9cbbb5b05f30668f6d652 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/smb5-lib.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index cd1ae35a17c6..26f844285cee 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -1954,6 +1954,16 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, u8 stat; int rc, suspend = 0; + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_DEBUG_BATTERY, &pval); + if (rc < 0) { + pr_err_ratelimited("Couldn't get debug battery prop rc=%d\n", + rc); + } else if (pval.intval == 1) { + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + return 0; + } + if (chg->dbc_usbov) { rc = smblib_get_prop_usb_present(chg, &pval); if (rc < 0) { -- GitLab From b07a31cf6686407364435bed31615fbb1b3fe4ec Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Wed, 20 Nov 2019 18:28:03 -0800 Subject: [PATCH 0979/1055] power: qpnp-smb5: add property to show fake charging status Add "qcom,fake-chg-status-on-debug-batt" property to show charging status as unknown when debug battery is present. Change-Id: Ieab27bd9c2c2c44925057c4d9f2c634c93b3925d Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/qpnp-smb5.c | 3 +++ drivers/power/supply/qcom/smb5-lib.c | 18 ++++++++++-------- drivers/power/supply/qcom/smb5-lib.h | 1 + 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index bdd75c003cc7..3903c213c0d3 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -549,6 +549,9 @@ static int smb5_parse_dt(struct smb5 *chip) chg->suspend_input_on_debug_batt = of_property_read_bool(node, "qcom,suspend-input-on-debug-batt"); + chg->fake_chg_status_on_debug_batt = of_property_read_bool(node, + "qcom,fake-chg-status-on-debug-batt"); + rc = of_property_read_u32(node, "qcom,otg-deglitch-time-ms", &chg->otg_delay_ms); if (rc < 0) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 26f844285cee..ea3f74aa578b 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -1954,14 +1954,16 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, u8 stat; int rc, suspend = 0; - rc = smblib_get_prop_from_bms(chg, - POWER_SUPPLY_PROP_DEBUG_BATTERY, &pval); - if (rc < 0) { - pr_err_ratelimited("Couldn't get debug battery prop rc=%d\n", - rc); - } else if (pval.intval == 1) { - val->intval = POWER_SUPPLY_STATUS_UNKNOWN; - return 0; + if (chg->fake_chg_status_on_debug_batt) { + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_DEBUG_BATTERY, &pval); + if (rc < 0) { + pr_err_ratelimited("Couldn't get debug battery prop rc=%d\n", + rc); + } else if (pval.intval == 1) { + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + return 0; + } } if (chg->dbc_usbov) { diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index a9dbc9af5e55..de04a7ab4a06 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -514,6 +514,7 @@ struct smb_charger { int connector_type; bool otg_en; bool suspend_input_on_debug_batt; + bool fake_chg_status_on_debug_batt; int default_icl_ua; int otg_cl_ua; bool uusb_apsd_rerun_done; -- GitLab From 624be4529906cab27254559f1214fc8c4cddf069 Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Wed, 1 Jul 2020 14:29:18 +0530 Subject: [PATCH 0980/1055] ARM: dts: msm: add device tree for EAP connection through ethernet This commit adds device tree needed when an external processor and modem processor are connected through ethernet. Change-Id: Iaae917f7bd7a390b640027382bc7ef836bb544f1 Signed-off-by: Rishi Gupta --- arch/arm64/boot/dts/qcom/Makefile | 20 +++++---- .../boot/dts/qcom/sa515m-ccard-eth-ep.dts | 43 +++++++++++++++++++ .../boot/dts/qcom/sa515m-v2-ccard-eth-ep.dts | 43 +++++++++++++++++++ 3 files changed, 97 insertions(+), 9 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/sa515m-ccard-eth-ep.dts create mode 100644 arch/arm64/boot/dts/qcom/sa515m-v2-ccard-eth-ep.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 43f4730fe16a..b2d9cacbd674 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -434,20 +434,22 @@ dtb-$(CONFIG_ARCH_SDXPRAIRIE) += sdxprairie-rumi.dtb \ sdxprairie-v2-mtp-v1.1.dtb \ sdxprairie-v2-mtp-le-cpe.dtb \ sdxprairie-v2-ttp-cpe.dtb \ - sa515m-v2-ttp.dtb \ - sa515m-v2-ttp-usb-ep.dtb \ - sa515m-v2-ttp-pcie-ep.dtb \ - sa515m-v2-ttp-flashless-usb-ep.dtb \ - sa515m-v2-ttp-flashless-pcie-ep.dtb \ - sa515m-v2-ttp-emmc.dtb \ + sa515m-v2-ttp.dtb \ + sa515m-v2-ttp-usb-ep.dtb \ + sa515m-v2-ttp-pcie-ep.dtb \ + sa515m-v2-ttp-flashless-usb-ep.dtb \ + sa515m-v2-ttp-flashless-pcie-ep.dtb \ + sa515m-v2-ttp-emmc.dtb \ sa515m-ccard.dtb \ sa515m-ccard-pcie-ep.dtb \ sa515m-ccard-usb-ep.dtb \ - sa515m-v2-ccard-flashless-pcie-ep.dtb \ - sa515m-v2-ccard-flashless-usb-ep.dtb \ + sa515m-ccard-eth-ep.dtb \ + sa515m-v2-ccard-flashless-pcie-ep.dtb \ + sa515m-v2-ccard-flashless-usb-ep.dtb \ sa515m-v2-ccard.dtb \ sa515m-v2-ccard-pcie-ep.dtb \ - sa515m-v2-ccard-usb-ep.dtb + sa515m-v2-ccard-usb-ep.dtb \ + sa515m-v2-ccard-eth-ep.dtb dtb-$(CONFIG_ARCH_MDM9607) += mdm9607-cdp.dtb \ mdm9607-mtp.dtb \ diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard-eth-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-ccard-eth-ep.dts new file mode 100644 index 000000000000..67e23a084989 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard-eth-ep.dts @@ -0,0 +1,43 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "sdxprairie.dtsi" +#include "sa515m-ccard.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA515M CCARD ETH"; + compatible = "qcom,sa515m-ccard", + "qcom,sdxprairie", "qcom,ccard"; + qcom,board-id = <25 5>, <25 0x105>; + + /delete-node/ qcom_gadget; + qcom_gadget { + compatible = "qcom,usb-gadget"; + qcom,vid = <0x05c6>; + + composition1 { + qcom,pid = <0x9105>; + qcom,composition = "diag.diag,gsi.dpl"; + }; + }; +}; + +&ipa_hw { + qcom,ipa-config-is-auto; + qcom,use-xbl-boot; +}; + +&usb { + qcom,smmu-s1-bypass; +}; diff --git a/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-eth-ep.dts b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-eth-ep.dts new file mode 100644 index 000000000000..9eeb1c42076f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa515m-v2-ccard-eth-ep.dts @@ -0,0 +1,43 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "sdxprairie-v2.dtsi" +#include "sa515m-ccard.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA515M CCARD ETH V2"; + compatible = "qcom,sa515m-ccard", + "qcom,sdxprairie", "qcom,ccard"; + qcom,board-id = <25 5>, <25 0x105>; + + /delete-node/ qcom_gadget; + qcom_gadget { + compatible = "qcom,usb-gadget"; + qcom,vid = <0x05c6>; + + composition1 { + qcom,pid = <0x9105>; + qcom,composition = "diag.diag,gsi.dpl"; + }; + }; +}; + +&ipa_hw { + qcom,ipa-config-is-auto; + qcom,use-xbl-boot; +}; + +&usb { + qcom,smmu-s1-bypass; +}; -- GitLab From b3a9bd3f5a2e75f125586cb13a5fbbd273e815e7 Mon Sep 17 00:00:00 2001 From: Archit Saxena Date: Tue, 2 Jun 2020 22:10:19 +0530 Subject: [PATCH 0981/1055] defconfig: sdm429: Add pil configs to sdm429 Add blackghost and modem pil configs to sdm429. Change-Id: Ife0e5468a4d52cd4446ef437f7773fa09f0259f6 Signed-off-by: Archit Saxena --- arch/arm/configs/vendor/sdm429-bg-perf_defconfig | 2 ++ arch/arm/configs/vendor/sdm429-bg_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig index b5270ed9de47..ab40f32e345b 100644 --- a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig @@ -537,6 +537,7 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 @@ -566,6 +567,7 @@ CONFIG_QCOM_CX_IPEAK=y CONFIG_MSM_BAM_DMUX=y CONFIG_MSM_BGCOM_INTERFACE=y CONFIG_MSM_BGCOM=y +CONFIG_MSM_PIL_SSR_BG=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y diff --git a/arch/arm/configs/vendor/sdm429-bg_defconfig b/arch/arm/configs/vendor/sdm429-bg_defconfig index 8e0eb0c080a2..158a5ab5fdbc 100644 --- a/arch/arm/configs/vendor/sdm429-bg_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg_defconfig @@ -556,6 +556,7 @@ CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y CONFIG_MSM_SYSMON_QMI_COMM=y CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 @@ -591,6 +592,7 @@ CONFIG_QCOM_CX_IPEAK=y CONFIG_MSM_BAM_DMUX=y CONFIG_MSM_BGCOM_INTERFACE=y CONFIG_MSM_BGCOM=y +CONFIG_MSM_PIL_SSR_BG=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y -- GitLab From 7470c5a635264a3524287a341fd2bc93af8a0ff6 Mon Sep 17 00:00:00 2001 From: Trinath Thammishetty Date: Thu, 25 Jun 2020 12:29:06 +0530 Subject: [PATCH 0982/1055] ARM: dts: msm: Define adsp loader node Define adsp loader node for loading adsp on sdm429. Change-Id: I3df74b761ce1c3c1bb16e70405458c398527ac27 Signed-off-by: Trinath Thammishetty --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 8dc5196c4363..18b4827f01a9 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -1131,6 +1131,11 @@ qcom,ea-pc = <0x230>; status = "disabled"; }; + qcom,msm-adsp-loader { + status = "ok"; + compatible = "qcom,adsp-loader"; + qcom,adsp-state = <0>; + }; }; #include "sdm429-gdsc.dtsi" -- GitLab From 6c9df75a4b38e29263b690bf0cab72806745171d Mon Sep 17 00:00:00 2001 From: Archit Saxena Date: Tue, 2 Jun 2020 21:52:17 +0530 Subject: [PATCH 0983/1055] ARM: dts: msm: Add blackghost pil node Add BG pil node for sdm429w target. Change-Id: I07b9019f2f865997685fc86c95e786a08345d703 Signed-off-by: Archit Saxena Signed-off-by: Chandrasekhar Mattaparthy --- .../boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi | 2 +- arch/arm64/boot/dts/qcom/sda429-wdp.dtsi | 2 +- arch/arm64/boot/dts/qcom/sda429-wtp.dtsi | 2 +- .../boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi | 2 +- arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi | 27 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm429-wdp.dtsi | 2 +- arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi | 2 +- 7 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi diff --git a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi index a1160641d216..30c022abd36f 100644 --- a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ - +#include "sdm429-bg-soc.dtsi" &sdhc_1 { /* device core power supply */ vdd-supply = <&L19A>; diff --git a/arch/arm64/boot/dts/qcom/sda429-wdp.dtsi b/arch/arm64/boot/dts/qcom/sda429-wdp.dtsi index a1160641d216..30c022abd36f 100644 --- a/arch/arm64/boot/dts/qcom/sda429-wdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sda429-wdp.dtsi @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ - +#include "sdm429-bg-soc.dtsi" &sdhc_1 { /* device core power supply */ vdd-supply = <&L19A>; diff --git a/arch/arm64/boot/dts/qcom/sda429-wtp.dtsi b/arch/arm64/boot/dts/qcom/sda429-wtp.dtsi index a1160641d216..30c022abd36f 100644 --- a/arch/arm64/boot/dts/qcom/sda429-wtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sda429-wtp.dtsi @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ - +#include "sdm429-bg-soc.dtsi" &sdhc_1 { /* device core power supply */ vdd-supply = <&L19A>; diff --git a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi index a1160641d216..30c022abd36f 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ - +#include "sdm429-bg-soc.dtsi" &sdhc_1 { /* device core power supply */ vdd-supply = <&L19A>; diff --git a/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi b/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi new file mode 100644 index 000000000000..f2e451179235 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi @@ -0,0 +1,27 @@ +/* Copyright (c) 2020, 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. + */ + +&soc { + + qcom,blackghost { + compatible = "qcom,pil-blackghost"; + qcom,pil-force-shutdown; + qcom,firmware-name = "bg-wear"; + /* GPIO inputs from blackghost */ + qcom,bg2ap-status-gpio = <&tlmm 44 0>; + qcom,bg2ap-errfatal-gpio = <&tlmm 72 0>; + /* GPIO output to blackghost */ + qcom,ap2bg-status-gpio = <&tlmm 61 0>; + qcom,ap2bg-errfatal-gpio = <&tlmm 62 0>; + }; + +}; diff --git a/arch/arm64/boot/dts/qcom/sdm429-wdp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-wdp.dtsi index a1160641d216..30c022abd36f 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-wdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-wdp.dtsi @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ - +#include "sdm429-bg-soc.dtsi" &sdhc_1 { /* device core power supply */ vdd-supply = <&L19A>; diff --git a/arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi index a1160641d216..30c022abd36f 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi @@ -11,7 +11,7 @@ * GNU General Public License for more details. */ - +#include "sdm429-bg-soc.dtsi" &sdhc_1 { /* device core power supply */ vdd-supply = <&L19A>; -- GitLab From ca4c257248872410ed8c95455c00529d35ef74fd Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Sat, 13 Jun 2020 10:54:27 +0800 Subject: [PATCH 0984/1055] coresight-tmc-etr: Add QDSS IPA bam connection support Add QDSS IPA bam connection support for pcie hw transfer path. And add support to switch between pcie sw and hw path. Change-Id: Idbd6f9e2a869fabfa0a23a834b1cbd7945cf93f4 Signed-off-by: Mao Jinlong --- .../devicetree/bindings/arm/coresight.txt | 3 + .../hwtracing/coresight/coresight-tmc-etr.c | 229 +++++++++++++++--- drivers/hwtracing/coresight/coresight-tmc.c | 48 ++++ drivers/hwtracing/coresight/coresight-tmc.h | 20 ++ 4 files changed, 273 insertions(+), 27 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index 33f85860c924..1688ba2744b1 100644 --- a/Documentation/devicetree/bindings/arm/coresight.txt +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -139,6 +139,9 @@ its hardware characteristcs. * arm,sg-enable : indicates whether scatter gather feature is enabled by default for TMC ETR configuration. + * qcom,qdss-ipa-support : indicates whether qdss to ipa bam connection + need to support. + * Required property for TPDAs: * qcom,tpda-atid: must be present. Specifies the ATID for TPDA. diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 745fcaad4348..83e5505ce8e7 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1167,13 +1167,13 @@ static int tmc_etr_fill_usb_bam_data(struct tmc_drvdata *drvdata) return 0; } -static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) +static int __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) { struct tmc_etr_bam_data *bamdata = drvdata->bamdata; uint32_t axictl; if (drvdata->enable_to_bam) - return; + return 0; /* Configure and enable required CSR registers */ msm_qdss_csr_enable_bam_to_usb(drvdata->csr); @@ -1182,7 +1182,13 @@ static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) CS_UNLOCK(drvdata->base); - writel_relaxed(bamdata->data_fifo.size / 4, drvdata->base + TMC_RSZ); + if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) + writel_relaxed(bamdata->data_fifo.size / 4, + drvdata->base + TMC_RSZ); + else if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) + writel_relaxed(bamdata->connect.data.size / 4, + drvdata->base + TMC_RSZ); + writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); axictl = readl_relaxed(drvdata->base + TMC_AXICTL); @@ -1193,15 +1199,33 @@ static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) axictl = (axictl & ~0x3) | 0x2; writel_relaxed(axictl, drvdata->base + TMC_AXICTL); - if (bamdata->props.options & SPS_BAM_SMMU_EN) { - writel_relaxed((uint32_t)bamdata->data_fifo.iova, - drvdata->base + TMC_DBALO); - writel_relaxed((((uint64_t)bamdata->data_fifo.iova) >> 32) - & 0xFF, drvdata->base + TMC_DBAHI); - } else { - writel_relaxed((uint32_t)bamdata->data_fifo.phys_base, - drvdata->base + TMC_DBALO); - writel_relaxed((((uint64_t)bamdata->data_fifo.phys_base) >> 32) + if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) { + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + writel_relaxed((uint32_t)bamdata->data_fifo.iova, + drvdata->base + TMC_DBALO); + writel_relaxed( + (((uint64_t)bamdata->data_fifo.iova) >> 32) + & 0xFF, drvdata->base + TMC_DBAHI); + } else { + writel_relaxed((uint32_t)bamdata->data_fifo.phys_base, + drvdata->base + TMC_DBALO); + writel_relaxed( + (((uint64_t)bamdata->data_fifo.phys_base) >> 32) + & 0xFF, drvdata->base + TMC_DBAHI); + } + } + + if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + CS_LOCK(drvdata->base); + dev_err(drvdata->dev, "PCIE mode doesn't support smmu.\n"); + return -EINVAL; + } + + writel_relaxed((uint32_t)bamdata->connect.data.phys_base, + drvdata->base + TMC_DBALO); + writel_relaxed( + (((uint64_t)bamdata->connect.data.phys_base) >> 32) & 0xFF, drvdata->base + TMC_DBAHI); } /* Set FOnFlIn for periodic flush */ @@ -1213,6 +1237,7 @@ static void __tmc_etr_enable_to_bam(struct tmc_drvdata *drvdata) msm_qdss_csr_enable_flush(drvdata->csr); drvdata->enable_to_bam = true; + return 0; } static int get_usb_bam_iova(struct device *dev, unsigned long usb_bam_handle, @@ -1262,19 +1287,57 @@ static int tmc_etr_bam_enable(struct tmc_drvdata *drvdata) bamdata->connect.source = bamdata->handle; bamdata->connect.event_thresh = 0x4; bamdata->connect.src_pipe_index = TMC_ETR_BAM_PIPE_INDEX; - bamdata->connect.options = SPS_O_AUTO_ENABLE; + if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) { + bamdata->connect.options = SPS_O_AUTO_ENABLE; + + bamdata->connect.destination = bamdata->dest; + bamdata->connect.dest_pipe_index = bamdata->dest_pipe_idx; + bamdata->connect.desc = bamdata->desc_fifo; + bamdata->connect.data = bamdata->data_fifo; + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + ret = get_usb_bam_iova(drvdata->dev, + bamdata->dest, &iova); + if (ret) + goto err1; + bamdata->connect.dest_iova = iova; + } + } else if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { + if (bamdata->props.options & SPS_BAM_SMMU_EN) { + dev_err(drvdata->dev, "PCIE mode doesn't support smmu.\n"); + ret = -EINVAL; + goto err1; + } - bamdata->connect.destination = bamdata->dest; - bamdata->connect.dest_pipe_index = bamdata->dest_pipe_idx; - bamdata->connect.desc = bamdata->desc_fifo; - bamdata->connect.data = bamdata->data_fifo; + bamdata->connect.options = SPS_O_AUTO_ENABLE | SPS_O_DUMMY_PEER; + + bamdata->connect.destination = + drvdata->ipa_data->ipa_qdss_out.ipa_rx_db_pa; + bamdata->connect.dest_pipe_index = 0; + bamdata->connect.desc.phys_base = + drvdata->ipa_data->ipa_qdss_in.desc_fifo_base_addr; + bamdata->connect.desc.size = + drvdata->ipa_data->ipa_qdss_in.desc_fifo_size; + bamdata->connect.desc.base = + ioremap(bamdata->connect.desc.phys_base, + bamdata->connect.desc.size); + if (!bamdata->connect.desc.base) { + ret = -ENOMEM; + goto err1; + } - if (bamdata->props.options & SPS_BAM_SMMU_EN) { - ret = get_usb_bam_iova(drvdata->dev, bamdata->dest, &iova); - if (ret) + bamdata->connect.data.phys_base = + drvdata->ipa_data->ipa_qdss_in.data_fifo_base_addr; + bamdata->connect.data.size = + drvdata->ipa_data->ipa_qdss_in.data_fifo_size; + bamdata->connect.data.base = + ioremap(bamdata->connect.data.phys_base, + bamdata->connect.data.size); + if (!bamdata->connect.data.base) { + ret = -ENOMEM; goto err1; - bamdata->connect.dest_iova = iova; + } } + ret = sps_connect(bamdata->pipe, &bamdata->connect); if (ret) goto err1; @@ -1398,6 +1461,77 @@ int tmc_etr_bam_init(struct amba_device *adev, return sps_register_bam_device(&bamdata->props, &bamdata->handle); } +int tmc_etr_ipa_init(struct amba_device *adev, + struct tmc_drvdata *drvdata) +{ + int ret; + struct device *dev = &adev->dev; + struct device_node *node = adev->dev.of_node; + struct tmc_etr_ipa_data *ipa_data; + u32 value = 0; + + ipa_data = devm_kzalloc(dev, sizeof(*ipa_data), GFP_KERNEL); + if (!ipa_data) + return -ENOMEM; + + drvdata->ipa_data = ipa_data; + + ret = of_property_read_u32(node, "ipa-conn-data-base-pa", &value); + if (ret) { + pr_err("%s: Invalid ipa data base address property\n", + __func__); + return -EINVAL; + } + ipa_data->ipa_qdss_in.data_fifo_base_addr = value; + + ret = of_property_read_u32(node, "ipa-conn-data-size", &value); + if (ret) { + pr_err("%s: Invalid ipa data base size\n", __func__); + return -EINVAL; + } + ipa_data->ipa_qdss_in.data_fifo_size = value; + + ret = of_property_read_u32(node, "ipa-conn-desc-base-pa", &value); + if (ret) { + pr_err("%s: Invalid ipa desc base address property\n", + __func__); + return -EINVAL; + } + ipa_data->ipa_qdss_in.desc_fifo_base_addr = value; + + ret = of_property_read_u32(node, "ipa-conn-desc-size", &value); + if (ret) { + pr_err("%s: Invalid ipa desc size property\n", __func__); + return -EINVAL; + } + ipa_data->ipa_qdss_in.desc_fifo_size = value; + + ret = of_property_read_u32(node, "ipa-peer-evt-reg-pa", &value); + if (ret) { + pr_err("%s: Invalid ipa peer reg pa property\n", __func__); + return -EINVAL; + } + ipa_data->ipa_qdss_in.bam_p_evt_dest_addr = value; + + ipa_data->ipa_qdss_in.bam_p_evt_threshold = 0x4; + ipa_data->ipa_qdss_in.override_eot = 0x1; + return 0; +} + +static int tmc_etr_ipa_conn(struct tmc_drvdata *drvdata) +{ + if (!drvdata->ipa_data) + return -ENOMEM; + + return ipa_qdss_conn_pipes(&drvdata->ipa_data->ipa_qdss_in, + &drvdata->ipa_data->ipa_qdss_out); +} + +static int tmc_etr_ipa_disconn(void) +{ + return ipa_qdss_disconn_pipes(); +} + static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) { int ret = 0; @@ -1422,7 +1556,8 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) spin_unlock_irqrestore(&drvdata->spinlock, flags); if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM || - drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { + (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE && + drvdata->pcie_path == TMC_ETR_PCIE_SW_PATH)) { /* * ETR DDR memory is not allocated until user enables * tmc at least once. If user specifies different ETR @@ -1444,6 +1579,32 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) coresight_cti_map_trigout(drvdata->cti_flush, 3, 0); coresight_cti_map_trigin(drvdata->cti_reset, 2, 0); + } else if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE && + drvdata->pcie_path == TMC_ETR_PCIE_HW_PATH) { + ret = tmc_etr_ipa_conn(drvdata); + if (ret) { + mutex_unlock(&drvdata->mem_lock); + return ret; + } + + ret = tmc_etr_bam_enable(drvdata); + if (ret) { + tmc_etr_ipa_disconn(); + mutex_unlock(&drvdata->mem_lock); + return ret; + } + + spin_lock_irqsave(&drvdata->spinlock, flags); + ret = __tmc_etr_enable_to_bam(drvdata); + if (ret) { + spin_unlock_irqrestore(&drvdata->spinlock, + flags); + tmc_etr_ipa_disconn(); + mutex_unlock(&drvdata->mem_lock); + return ret; + } + spin_unlock_irqrestore(&drvdata->spinlock, flags); + } else { drvdata->usbch = usb_qdss_open("qdss", drvdata, usb_notifier); @@ -1483,7 +1644,8 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) } if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM || - drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { + (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE && + drvdata->pcie_path == TMC_ETR_PCIE_SW_PATH)) { ret = tmc_etr_enable_hw(drvdata, drvdata->sysfs_buf); if (ret) goto out; @@ -1504,7 +1666,8 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev) if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) tmc_etr_byte_cntr_start(drvdata->byte_cntr); - if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) + if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE + && drvdata->pcie_path == TMC_ETR_PCIE_SW_PATH) etr_pcie_start(drvdata->byte_cntr); dev_info(drvdata->dev, "TMC-ETR enabled\n"); @@ -1971,6 +2134,14 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) drvdata->usbch = NULL; drvdata->mode = CS_MODE_DISABLED; goto out; + } else if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE + && drvdata->pcie_path == TMC_ETR_PCIE_HW_PATH) { + __tmc_etr_disable_to_bam(drvdata); + spin_unlock_irqrestore(&drvdata->spinlock, flags); + tmc_etr_bam_disable(drvdata); + tmc_etr_ipa_disconn(); + drvdata->mode = CS_MODE_DISABLED; + goto out; } else { tmc_etr_disable_hw(drvdata); } @@ -1992,7 +2163,8 @@ static int tmc_disable_etr_sink(struct coresight_device *csdev) spin_unlock_irqrestore(&drvdata->spinlock, flags); if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM || - drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { + (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE + && drvdata->pcie_path == TMC_ETR_PCIE_SW_PATH)) { if (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { etr_pcie_stop(drvdata->byte_cntr); flush_workqueue(drvdata->byte_cntr->pcie_wq); @@ -2019,7 +2191,9 @@ static void tmc_abort_etr_sink(struct coresight_device *csdev) if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM) tmc_etr_disable_hw(drvdata); - else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) + else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB + || (drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE && + drvdata->pcie_path == TMC_ETR_PCIE_HW_PATH)) __tmc_etr_disable_to_bam(drvdata); out0: drvdata->enable = false; @@ -2093,7 +2267,8 @@ int tmc_read_prepare_etr(struct tmc_drvdata *drvdata) goto out; } - if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) { + if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB || + drvdata->out_mode == TMC_ETR_OUT_MODE_PCIE) { ret = -EINVAL; goto out; } diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index fab4feed9388..96e50fd70f2c 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -434,6 +434,46 @@ static ssize_t out_mode_store(struct device *dev, } static DEVICE_ATTR_RW(out_mode); +static ssize_t pcie_path_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + + return scnprintf(buf, PAGE_SIZE, "%s\n", + str_tmc_etr_pcie_path[drvdata->pcie_path]); +} + +static ssize_t pcie_path_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent); + char str[10] = ""; + + if (strlen(buf) >= 10) + return -EINVAL; + if (sscanf(buf, "%10s", str) != 1) + return -EINVAL; + + mutex_lock(&drvdata->mem_lock); + if (drvdata->enable) { + mutex_unlock(&drvdata->mem_lock); + pr_err("ETR is in use, disable it to switch the pcie path\n"); + return -EINVAL; + } + + if (!strcmp(str, str_tmc_etr_pcie_path[TMC_ETR_PCIE_SW_PATH])) + drvdata->pcie_path = TMC_ETR_PCIE_SW_PATH; + else if (!strcmp(str, str_tmc_etr_pcie_path[TMC_ETR_PCIE_HW_PATH])) + drvdata->pcie_path = TMC_ETR_PCIE_HW_PATH; + else + size = -EINVAL; + + mutex_unlock(&drvdata->mem_lock); + return size; +} +static DEVICE_ATTR_RW(pcie_path); + static ssize_t available_out_modes_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -586,6 +626,7 @@ static struct attribute *coresight_tmc_etr_attrs[] = { &dev_attr_block_size.attr, &dev_attr_out_mode.attr, &dev_attr_available_out_modes.attr, + &dev_attr_pcie_path.attr, NULL, }; @@ -724,6 +765,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) drvdata->size = SZ_1M; drvdata->out_mode = TMC_ETR_OUT_MODE_MEM; + drvdata->pcie_path = TMC_ETR_PCIE_HW_PATH; } else { drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4; } @@ -793,6 +835,12 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) goto out_iommu_deinit; idr_init(&drvdata->idr); mutex_init(&drvdata->idr_mutex); + + if (of_property_read_bool(drvdata->dev->of_node, + "qcom,qdss-ipa-support")) + ret = tmc_etr_ipa_init(adev, drvdata); + if (ret) + goto out_iommu_deinit; break; case TMC_CONFIG_TYPE_ETF: desc.type = CORESIGHT_DEV_TYPE_LINKSINK; diff --git a/drivers/hwtracing/coresight/coresight-tmc.h b/drivers/hwtracing/coresight/coresight-tmc.h index 92f725e2ea31..b24f30a80f27 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.h +++ b/drivers/hwtracing/coresight/coresight-tmc.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "coresight-byte-cntr.h" @@ -158,6 +159,16 @@ enum tmc_mem_intf_width { #define CORESIGHT_SOC_600_ETR_CAPS \ (TMC_ETR_SAVE_RESTORE | TMC_ETR_AXI_ARCACHE) +enum tmc_etr_pcie_path { + TMC_ETR_PCIE_SW_PATH, + TMC_ETR_PCIE_HW_PATH, +}; + +static const char * const str_tmc_etr_pcie_path[] = { + [TMC_ETR_PCIE_SW_PATH] = "sw", + [TMC_ETR_PCIE_HW_PATH] = "hw", +}; + enum tmc_etr_out_mode { TMC_ETR_OUT_MODE_NONE, TMC_ETR_OUT_MODE_MEM, @@ -172,6 +183,11 @@ static const char * const str_tmc_etr_out_mode[] = { [TMC_ETR_OUT_MODE_PCIE] = "pcie", }; +struct tmc_etr_ipa_data { + struct ipa_qdss_conn_out_params ipa_qdss_out; + struct ipa_qdss_conn_in_params ipa_qdss_in; +}; + struct tmc_etr_bam_data { struct sps_bam_props props; unsigned long handle; @@ -264,6 +280,7 @@ struct tmc_drvdata { u32 etr_caps; u32 delta_bottom; enum tmc_etr_out_mode out_mode; + enum tmc_etr_pcie_path pcie_path; struct usb_qdss_ch *usbch; struct tmc_etr_bam_data *bamdata; bool sticky_enable; @@ -279,6 +296,7 @@ struct tmc_drvdata { struct mutex idr_mutex; struct etr_buf *sysfs_buf; struct etr_buf *perf_buf; + struct tmc_etr_ipa_data *ipa_data; }; struct etr_buf_operations { @@ -346,6 +364,8 @@ void usb_notifier(void *priv, unsigned int event, struct qdss_request *d_req, struct usb_qdss_ch *ch); int tmc_etr_bam_init(struct amba_device *adev, struct tmc_drvdata *drvdata); +int tmc_etr_ipa_init(struct amba_device *adev, + struct tmc_drvdata *drvdata); extern struct byte_cntr *byte_cntr_init(struct amba_device *adev, struct tmc_drvdata *drvdata); extern void tmc_etr_free_mem(struct tmc_drvdata *drvdata); -- GitLab From 7b9945d10f3c510beb8f9149cb8e212848b402d9 Mon Sep 17 00:00:00 2001 From: Chandrasekhar Mattaparthy Date: Wed, 10 Jun 2020 15:21:33 +0530 Subject: [PATCH 0985/1055] ARM: dts: msm: Add bg spi and bg daemon nodes Add bg spi and bg daemon nodes for bg spi communication. Change-Id: I164a97ca79359ad1b3bc0462ae3398d9a133a65e Signed-off-by: Chandrasekhar Mattaparthy --- arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi b/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi index f2e451179235..3d0406775a14 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi @@ -24,4 +24,25 @@ qcom,ap2bg-errfatal-gpio = <&tlmm 62 0>; }; + spi_3: spi@78b7000 { /* BLSP1 QUP3*/ + status = "ok"; + qcom,bg-spi { + compatible = "qcom,bg-spi"; + reg = <0>; + spi-max-frequency = <16000000>; + interrupt-parent = <&tlmm>; + qcom,irq-gpio = <&tlmm 43 1>; + }; + }; + + i2c_3: i2c@78b7000 { /* BLSP1 QUP3 */ + status = "disabled"; + }; + + qcom,bg-daemon { + compatible = "qcom,bg-daemon"; + qcom,bg-reset-gpio = <&pm660_gpios 5 0>; + ssr-reg1-supply = <&pm660_l3>; + ssr-reg2-supply = <&pm660_l9>; + }; }; -- GitLab From 387fda6d5d69d494ef46748a1c1b04b3805eb48b Mon Sep 17 00:00:00 2001 From: Chetan C R Date: Mon, 22 Jun 2020 10:49:10 +0530 Subject: [PATCH 0986/1055] clk: qcom: Add enable_safe_config for gfx3d_clk_src Set enable_safe_config to true for configuring the rcg2 to cxo when disabled. Change-Id: I05d4a85f8c684b4df2ac86c7d70955cd2cecd22e Signed-off-by: Chetan C R --- drivers/clk/qcom/gpucc-sdm660.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/gpucc-sdm660.c b/drivers/clk/qcom/gpucc-sdm660.c index 29db382aa144..3dd807396692 100644 --- a/drivers/clk/qcom/gpucc-sdm660.c +++ b/drivers/clk/qcom/gpucc-sdm660.c @@ -209,6 +209,7 @@ static struct clk_rcg2 gfx3d_clk_src = { .freq_tbl = ftbl_gfx3d_clk_src, .parent_map = gpucc_parent_map_1, .flags = FORCE_ENABLE_RCG, + .enable_safe_config = true, .clkr.hw.init = &gpu_clks_init[0], }; -- GitLab From b0b74268bf917870555726297c51e9c7d9896c24 Mon Sep 17 00:00:00 2001 From: Manohar Vavilapalli Date: Thu, 2 Jul 2020 19:11:45 +0530 Subject: [PATCH 0987/1055] ARM: dts: msm: Remove the extra double quotes in the model name This patch removes the extra quotes in the model name in the SA6155P ADP AIR and STAR Lpass boards. Change-Id: I0594071c74ea30fbc9688e759c979fa94e8a03db Signed-off-by: Manohar Vavilapalli --- arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass-overlay.dts | 2 +- arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass.dts | 2 +- arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass-overlay.dts | 2 +- arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass.dts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass-overlay.dts b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass-overlay.dts index 01b9cf33311c..29503f2972e5 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass-overlay.dts @@ -19,7 +19,7 @@ #include "sa6155-adp-star.dtsi" / { - model = "LPASS Audio PLL sourced from eMAC PPO ("ADP-Star")"; + model = "LPASS Audio PLL sourced from eMAC PPO ADP-Star"; compatible = "qcom,sa6155p-adp-star", "qcom,sa6155p", "qcom,adp-star"; qcom,msm-id = <377 0x0>, <380 0>; qcom,board-id = <0x01010019 0>; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass.dts b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass.dts index c922fbc85318..184057295fa3 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass.dts +++ b/arch/arm64/boot/dts/qcom/sa6155p-adp-star-lpass.dts @@ -17,7 +17,7 @@ / { model = "Qualcomm Technologies, Inc. SA6155P LPASS Audio PLL sourced - from eMAC PPO ("ADP-Star")"; + from eMAC PPO ADP-Star"; compatible = "qcom,sa6155p-adp-star", "qcom,sa6155p", "qcom,adp-star"; qcom,board-id = <0x01010019 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass-overlay.dts b/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass-overlay.dts index 3a8721e8f387..4a30f1529ac5 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass-overlay.dts @@ -19,7 +19,7 @@ #include "sa6155-adp-air.dtsi" / { - model = "LPASS Audio PLL sourced from eMAC PPO ("ADP-Air")"; + model = "LPASS Audio PLL sourced from eMAC PPO ADP-Air"; compatible = "qcom,sa6155p-adp-air", "qcom,sa6155p", "qcom,adp-air"; com,board-id = <0x04010019 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass.dts b/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass.dts index 54b4bf4ab6a7..965969a8354f 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass.dts +++ b/arch/arm64/boot/dts/qcom/sa6155p-v2-adp-air-lpass.dts @@ -17,7 +17,7 @@ / { model = "Qualcomm Technologies, Inc. SA6155P v2 LPASS Audio PLL sourced - from eMAC PPO ("ADP-Air")"; + from eMAC PPO ADP-Air"; compatible = "qcom,sa6155p-adp-air", "qcom,sa6155p", "qcom,adp-air"; qcom,board-id = <0x04010019 0>; }; -- GitLab From 767ea75f3cfea671de3c447a6a0c10c82735ce39 Mon Sep 17 00:00:00 2001 From: Shreyas K K Date: Thu, 2 Jul 2020 19:54:56 +0530 Subject: [PATCH 0988/1055] defconfig: sa2150p-nand: Enable SDX_EXT_IPC Enable SDX_EXT_IPC driver that is required for sideband notifications to and from remote processor. Change-Id: I271f103a8965bb5837a48a1068af49d25850e9b4 Signed-off-by: Shreyas K K --- arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig | 1 + arch/arm64/configs/vendor/sa2150p-nand_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig index 8ad55958506e..fa2267ccc887 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig @@ -405,6 +405,7 @@ CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_DCC_V2=y +CONFIG_SDX_EXT_IPC=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y diff --git a/arch/arm64/configs/vendor/sa2150p-nand_defconfig b/arch/arm64/configs/vendor/sa2150p-nand_defconfig index b215279b7c17..a93cdf7d2a70 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand_defconfig @@ -423,6 +423,7 @@ CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_DCC_V2=y +CONFIG_SDX_EXT_IPC=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y -- GitLab From 7f2d489150a214eb27641c6b61aadb92e55c58a5 Mon Sep 17 00:00:00 2001 From: Amit Kushwaha Date: Mon, 18 May 2020 17:22:11 +0530 Subject: [PATCH 0989/1055] msm: kgsl: Add A504 GPU support for SDM429 Add A504 GPUID and initial settings to support graphics functionality on SDM429. Change-Id: I3e967cea59cd8d5eb687ba5701a80689a24c0475 Signed-off-by: Amit Kushwaha --- drivers/gpu/msm/adreno-gpulist.h | 16 +++++++++++++++- drivers/gpu/msm/adreno.h | 8 +++++--- drivers/gpu/msm/adreno_a5xx.c | 10 +++++++--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index 9385734b3e66..645f10d2a6e2 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, 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 @@ -201,6 +201,20 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .max_power = 5448, .regfw_name = "a530v3_seq.fw2", }, + { + .gpurev = ADRENO_REV_A504, + .core = 5, + .major = 0, + .minor = 4, + .patchid = ANY_ID, + .features = ADRENO_PREEMPTION | ADRENO_64BIT, + .pm4fw_name = "a530_pm4.fw", + .pfpfw_name = "a530_pfp.fw", + .gpudev = &adreno_a5xx_gpudev, + .gmem_size = (SZ_128K + SZ_8K), + .num_protected_regs = 0x20, + .busy_mask = 0xFFFFFFFE, + }, { .gpurev = ADRENO_REV_A505, .core = 5, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 11f7ec68beee..905dd4009a7e 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2020, 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 @@ -212,6 +212,7 @@ enum adreno_gpurev { ADRENO_REV_A418 = 418, ADRENO_REV_A420 = 420, ADRENO_REV_A430 = 430, + ADRENO_REV_A504 = 504, ADRENO_REV_A505 = 505, ADRENO_REV_A506 = 506, ADRENO_REV_A508 = 508, @@ -1274,6 +1275,7 @@ static inline int adreno_is_a5xx(struct adreno_device *adreno_dev) ADRENO_GPUREV(adreno_dev) < 600; } +ADRENO_TARGET(a504, ADRENO_REV_A504) ADRENO_TARGET(a505, ADRENO_REV_A505) ADRENO_TARGET(a506, ADRENO_REV_A506) ADRENO_TARGET(a508, ADRENO_REV_A508) @@ -1300,9 +1302,9 @@ static inline int adreno_is_a530v3(struct adreno_device *adreno_dev) (ADRENO_CHIPID_PATCH(adreno_dev->chipid) == 2); } -static inline int adreno_is_a505_or_a506(struct adreno_device *adreno_dev) +static inline int adreno_is_a504_to_a506(struct adreno_device *adreno_dev) { - return ADRENO_GPUREV(adreno_dev) >= 505 && + return ADRENO_GPUREV(adreno_dev) >= 504 && ADRENO_GPUREV(adreno_dev) <= 506; } diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 671d23691dfa..ba46bd46d450 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -56,6 +56,7 @@ static const struct adreno_vbif_platform a5xx_vbif_platforms[] = { { adreno_is_a512, a540_vbif }, { adreno_is_a510, a530_vbif }, { adreno_is_a508, a530_vbif }, + { adreno_is_a504, a530_vbif }, { adreno_is_a505, a530_vbif }, { adreno_is_a506, a530_vbif }, }; @@ -127,6 +128,7 @@ static const struct { } a5xx_efuse_funcs[] = { { adreno_is_a530, a530_efuse_leakage }, { adreno_is_a530, a530_efuse_speed_bin }, + { adreno_is_a504, a530_efuse_speed_bin }, { adreno_is_a505, a530_efuse_speed_bin }, { adreno_is_a512, a530_efuse_speed_bin }, { adreno_is_a508, a530_efuse_speed_bin }, @@ -152,7 +154,7 @@ static void a5xx_platform_setup(struct adreno_device *adreno_dev) uint64_t addr; struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); - if (adreno_is_a505_or_a506(adreno_dev) || adreno_is_a508(adreno_dev)) { + if (adreno_is_a504_to_a506(adreno_dev) || adreno_is_a508(adreno_dev)) { gpudev->snapshot_data->sect_sizes->cp_meq = 32; gpudev->snapshot_data->sect_sizes->cp_merciu = 1024; gpudev->snapshot_data->sect_sizes->roq = 256; @@ -1181,6 +1183,7 @@ static const struct { { adreno_is_a530, a530_hwcg_regs, ARRAY_SIZE(a530_hwcg_regs) }, { adreno_is_a512, a512_hwcg_regs, ARRAY_SIZE(a512_hwcg_regs) }, { adreno_is_a510, a510_hwcg_regs, ARRAY_SIZE(a510_hwcg_regs) }, + { adreno_is_a504, a50x_hwcg_regs, ARRAY_SIZE(a50x_hwcg_regs) }, { adreno_is_a505, a50x_hwcg_regs, ARRAY_SIZE(a50x_hwcg_regs) }, { adreno_is_a506, a50x_hwcg_regs, ARRAY_SIZE(a50x_hwcg_regs) }, { adreno_is_a508, a50x_hwcg_regs, ARRAY_SIZE(a50x_hwcg_regs) }, @@ -1930,7 +1933,7 @@ static void a5xx_start(struct adreno_device *adreno_dev) * Below CP registers are 0x0 by default, program init * values based on a5xx flavor. */ - if (adreno_is_a505_or_a506(adreno_dev) || adreno_is_a508(adreno_dev)) { + if (adreno_is_a504_to_a506(adreno_dev) || adreno_is_a508(adreno_dev)) { kgsl_regwrite(device, A5XX_CP_MEQ_THRESHOLDS, 0x20); kgsl_regwrite(device, A5XX_CP_MERCIU_SIZE, 0x400); kgsl_regwrite(device, A5XX_CP_ROQ_THRESHOLDS_2, 0x40000030); @@ -1956,7 +1959,7 @@ static void a5xx_start(struct adreno_device *adreno_dev) * vtxFifo and primFifo thresholds default values * are different. */ - if (adreno_is_a505_or_a506(adreno_dev) || adreno_is_a508(adreno_dev)) + if (adreno_is_a504_to_a506(adreno_dev) || adreno_is_a508(adreno_dev)) kgsl_regwrite(device, A5XX_PC_DBG_ECO_CNTL, (0x100 << 11 | 0x100 << 22)); else if (adreno_is_a510(adreno_dev) || adreno_is_a512(adreno_dev)) @@ -2264,6 +2267,7 @@ static int _me_init_ucode_workarounds(struct adreno_device *adreno_dev) switch (ADRENO_GPUREV(adreno_dev)) { case ADRENO_REV_A510: return 0x00000001; /* Ucode workaround for token end syncs */ + case ADRENO_REV_A504: case ADRENO_REV_A505: case ADRENO_REV_A506: case ADRENO_REV_A530: -- GitLab From 4baa26ccd17da1c712b38d9203c62c5f2f5340fd Mon Sep 17 00:00:00 2001 From: Shreyas K K Date: Thu, 2 Jul 2020 19:59:34 +0530 Subject: [PATCH 0990/1055] defconfig: sa2150p: Enable SDX_EXT_IPC Enable SDX_EXT_IPC driver that is required for sideband notifications to and from remote processor. Change-Id: Ibef4fbb79298caa1b2e79e8712c11cfcfbe53043 Signed-off-by: Shreyas K K --- arch/arm64/configs/vendor/sa2150p-perf_defconfig | 1 + arch/arm64/configs/vendor/sa2150p_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/sa2150p-perf_defconfig b/arch/arm64/configs/vendor/sa2150p-perf_defconfig index f5e65eed857b..8ccd6b3f09a6 100644 --- a/arch/arm64/configs/vendor/sa2150p-perf_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-perf_defconfig @@ -417,6 +417,7 @@ CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_DCC_V2=y +CONFIG_SDX_EXT_IPC=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y diff --git a/arch/arm64/configs/vendor/sa2150p_defconfig b/arch/arm64/configs/vendor/sa2150p_defconfig index 3ed8ba7dce30..c5b2630d9bd5 100644 --- a/arch/arm64/configs/vendor/sa2150p_defconfig +++ b/arch/arm64/configs/vendor/sa2150p_defconfig @@ -435,6 +435,7 @@ CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_DCC_V2=y +CONFIG_SDX_EXT_IPC=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y -- GitLab From 91e7e8301dfa4a16e313f29a443fdf0afe4b8bcd Mon Sep 17 00:00:00 2001 From: Dundi Raviteja Date: Thu, 4 Jun 2020 13:11:35 +0530 Subject: [PATCH 0991/1055] ARM: dts: msm: Add wcnss node for sdm429 Add wcnss node entry required for wlan. Change-Id: Iea35cd5cb8d1a2a04c5adeb857e15bec099dae39 CRs-Fixed: 2722174 Signed-off-by: Dundi Raviteja --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 83 ++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index b69c21a4f12c..38db3cd95489 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -1105,6 +1105,89 @@ reg = <0x08600720 0x2000>; }; + qcom,wcnss-wlan@0a000000 { + compatible = "qcom,wcnss_wlan"; + reg = <0x0a000000 0x280000>, + <0xb011008 0x04>, + <0x0a21b000 0x3000>, + <0x03204000 0x00000100>, + <0x03200800 0x00000200>, + <0x0a100400 0x00000200>, + <0x0a205050 0x00000200>, + <0x0a219000 0x00000020>, + <0x0a080488 0x00000008>, + <0x0a080fb0 0x00000008>, + <0x0a08040c 0x00000008>, + <0x0a0120a8 0x00000008>, + <0x0a012448 0x00000008>, + <0x0a080c00 0x00000001>; + + reg-names = "wcnss_mmio", "wcnss_fiq", + "pronto_phy_base", "riva_phy_base", + "riva_ccu_base", "pronto_a2xb_base", + "pronto_ccpu_base", "pronto_saw2_base", + "wlan_tx_phy_aborts","wlan_brdg_err_source", + "wlan_tx_status", "alarms_txctl", + "alarms_tactl", "pronto_mcu_base"; + + interrupts = <0 145 0 0 146 0>; + interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq"; + + qcom,pronto-vddmx-supply = <&pm660_s2_level_ao>; + qcom,pronto-vddcx-supply = <&pm660_s1_level>; + qcom,pronto-vddpx-supply = <&pm660_l13>; + qcom,iris-vddxo-supply = <&pm660_l12>; + qcom,iris-vddrfa-supply = <&pm660_l5>; + qcom,iris-vdddig-supply = <&pm660_l13>; + + qcom,iris-vddxo-voltage-level = <1800000 0 1800000>; + qcom,iris-vddrfa-voltage-level = <1300000 0 1300000>; + qcom,iris-vddpa-voltage-level = <3300000 0 3300000>; + qcom,iris-vdddig-voltage-level = <1800000 0 1800000>; + + qcom,vddmx-voltage-level = ; + qcom,vddcx-voltage-level = ; + qcom,vddpx-voltage-level = <1800000 0 1800000>; + + qcom,iris-vddxo-current = <10000>; + qcom,iris-vddrfa-current = <100000>; + qcom,iris-vddpa-current = <515000>; + qcom,iris-vdddig-current = <10000>; + + qcom,pronto-vddmx-current = <0>; + qcom,pronto-vddcx-current = <0>; + qcom,pronto-vddpx-current = <0>; + + pinctrl-names = "wcnss_default", "wcnss_sleep", + "wcnss_gpio_default"; + pinctrl-0 = <&wcnss_default>; + pinctrl-1 = <&wcnss_sleep>; + pinctrl-2 = <&wcnss_gpio_default>; + + gpios = <&tlmm 76 0>, <&tlmm 77 0>, <&tlmm 78 0>, + <&tlmm 79 0>, <&tlmm 80 0>; + + clocks = <&rpmcc CXO_SMD_WLAN_CLK>, + <&rpmcc RPM_SMD_RF_CLK2>, + <&rpmcc SNOC_WCNSS_A_CLK>; + + clock-names = "xo", "rf_clk", "snoc_wcnss"; + + qcom,smem-states = <&apps_smsm 10>, <&apps_smsm 9>; + qcom,smem-state-names = "tx-enable", "tx-rings-empty"; + + qcom,snoc-wcnss-clock-freq = <200000000>; + + qcom,has-autodetect-xo; + qcom,is-pronto-v3; + qcom,has-pronto-hw; + qcom,has-vsys-adc-channel; + }; + qcom,bam_dmux@4044000 { compatible = "qcom,bam_dmux"; reg = <0x4044000 0x19000>; -- GitLab From 5133acb677f1ab9062e286fbb3a17bc62d3e47b1 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Thu, 2 Jul 2020 11:14:48 -0700 Subject: [PATCH 0992/1055] bindings: qpnp-smb5: add property to show fake charging status Add "qcom,fake-chg-status-on-debug-batt" property to show charging status as unknown when debug battery is present. Change-Id: I7e9052285473f39477f5bf21e0cae10d1fdd8970 Signed-off-by: Subbaraman Narayanamurthy --- .../devicetree/bindings/power/supply/qcom/qpnp-smb5.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt index 073e2e6cb657..b617dc70cc53 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt @@ -178,6 +178,14 @@ Charger specific properties: Definition: Boolean flag which when present enables input suspend for debug battery. +- qcom,fake-chg-status-on-debug-batt + Usage: optional + Value type: + Definition: Boolean flag which when present shows charging status as + unknown for debug battery. This needs to be specified only if + the device needs to be kept powered on always with + "svc power stayon true". + - qcom,min-freq-khz Usage: optional Value type: -- GitLab From 7b304439c675cf4fc7028ca71770c6d729c06285 Mon Sep 17 00:00:00 2001 From: Chaitanya Pratapa Date: Mon, 4 May 2020 16:51:07 -0700 Subject: [PATCH 0993/1055] msm: ipa: Fix updating the doobell for WDI3 For WDI3, requirement is to ring the event ring DB with a value outside of the ring. Currently we are taking the event_ring_size from non SMMU structure which is incorrect. Make a chane to use the value based on SMMU enablement. Also make change to ring the DB with the below logic. Event ring base addr + Event ring size + 1 element size. Change-Id: Ie9e4cad63070d1488d0a36f9d08279d2d566055a Signed-off-by: Chaitanya Pratapa --- drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c | 24 ++++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c index 072d99456b9a..e82a849317bd 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c @@ -446,7 +446,7 @@ int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in, int result = 0; u32 gsi_db_addr_low, gsi_db_addr_high; void __iomem *db_addr; - u32 evt_ring_db_addr_low, evt_ring_db_addr_high; + u32 evt_ring_db_addr_low, evt_ring_db_addr_high, db_val = 0; /* wdi3 only support over gsi */ if (ipa3_get_wdi_version() != IPA_WDI_3) { @@ -612,11 +612,18 @@ int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in, * initialization of the event, with a value that is * outside of the ring range. Eg: ring base = 0x1000, * ring size = 0x100 => AP can write value > 0x1100 - * into the doorbell address. Eg: 0x 1110 + * into the doorbell address. Eg: 0x 1110. + * Use event ring base addr + event ring size + 1 element size. */ - iowrite32(in->u_rx.rx.event_ring_size / 4 + 10, db_addr); + db_val = (u32)ep_rx->gsi_mem_info.evt_ring_base_addr; + db_val += ((in->is_smmu_enabled) ? in->u_rx.rx_smmu.event_ring_size : + in->u_rx.rx.event_ring_size); + db_val += GSI_EVT_RING_RE_SIZE_8B; + iowrite32(db_val, db_addr); gsi_query_evt_ring_db_addr(ep_tx->gsi_evt_ring_hdl, &evt_ring_db_addr_low, &evt_ring_db_addr_high); + IPADBG("RX base_addr 0x%x evt wp val: 0x%x\n", + ep_rx->gsi_mem_info.evt_ring_base_addr, db_val); /* only 32 bit lsb is used */ db_addr = ioremap((phys_addr_t)(evt_ring_db_addr_low), 4); @@ -626,9 +633,16 @@ int ipa3_conn_wdi3_pipes(struct ipa_wdi_conn_in_params *in, * outside of the ring range. Eg: ring base = 0x1000, * ring size = 0x100 => AP can write value > 0x1100 * into the doorbell address. Eg: 0x 1110 + * Use event ring base addr + event ring size + 1 element size. */ - iowrite32(in->u_tx.tx.event_ring_size / 4 + 10, db_addr); - + db_val = (u32)ep_tx->gsi_mem_info.evt_ring_base_addr; + db_val += ((in->is_smmu_enabled) ? in->u_tx.tx_smmu.event_ring_size : + in->u_tx.tx.event_ring_size); + db_val += GSI_EVT_RING_RE_SIZE_16B; + iowrite32(db_val, db_addr); + IPADBG("db_addr %u TX base_addr 0x%x evt wp val: 0x%x\n", + evt_ring_db_addr_low, + ep_tx->gsi_mem_info.evt_ring_base_addr, db_val); fail: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return result; -- GitLab From 48d2887c1a274c3834df30b6ee787e0d49e7a7ec Mon Sep 17 00:00:00 2001 From: Shashi Kant Maurya Date: Wed, 1 Jul 2020 18:18:27 +0530 Subject: [PATCH 0994/1055] ARM: dts: msm: Add to distinguish NO or NC connection in USB Type-C USB Type-C audio headset could be NO or NC. Adding property to distinguish NO/NC. Change-Id: Ie2280b285945127103cbc28ed350f21be9cc1414 Signed-off-by: Shashi Kant Maurya --- arch/arm64/boot/dts/qcom/sdm660-usbc-audio-mtp-overlay.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm660-usbc-audio-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm660-usbc-audio-mtp-overlay.dts index 72dc5c277fd7..661437a49e92 100644 --- a/arch/arm64/boot/dts/qcom/sdm660-usbc-audio-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm660-usbc-audio-mtp-overlay.dts @@ -26,4 +26,6 @@ &tavil_snd { qcom,msm-mbhc-usbc-audio-supported = <1>; qcom,msm-mbhc-moist-cfg = <0>, <0>, <3>; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; }; -- GitLab From 2d7849e7d621b846267503438a82fc00a3f718ef Mon Sep 17 00:00:00 2001 From: Amit Kushwaha Date: Fri, 3 Jul 2020 09:03:41 +0530 Subject: [PATCH 0995/1055] ARM: dts: msm: Add GPU support for sdm429w Add device node for sdm429w GPU and its properties. Change-Id: I79ff9a029b83ff16e5fb256629cf2206a041e881 Signed-off-by: Amit Kushwaha --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 1 + arch/arm64/boot/dts/qcom/sdm429w-gpu.dtsi | 159 ++++++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdm429w-gpu.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index b69c21a4f12c..b8357e6b305d 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -185,6 +185,7 @@ #include "sdm429-cpu.dtsi" #include "sdm429-ion.dtsi" #include "msm-arm-smmu-sdm429.dtsi" +#include "sdm429w-gpu.dtsi" &soc { #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/sdm429w-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm429w-gpu.dtsi new file mode 100644 index 000000000000..7322180d8e3e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm429w-gpu.dtsi @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2020, 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. + */ + +&soc { + msm_bus: qcom,kgsl-busmon { + label = "kgsl-busmon"; + compatible = "qcom,kgsl-busmon"; + }; + + gpubw: qcom,gpubw { + compatible = "qcom,devbw"; + governor = "bw_vbif"; + qcom,src-dst-ports = <26 512>; + /* + * active-only flag is used while registering the bus + * governor.It helps release the bus vote when the CPU + * subsystem is inactive + */ + qcom,active-only; + qcom,bw-tbl = + < 0 >, /* off */ + < 769 >, /* 1. DDR:100.80 MHz BIMC: 50.40 MHz */ + < 1611 >, /* 2. DDR:211.20 MHz BIMC: 105.60 MHz */ + < 2273 >, /* 3. DDR:297.60 MHz BIMC: 148.80 MHz */ + < 2929 >, /* 4. DDR:384.00 MHz BIMC: 192.00 MHz */ + < 4248 >, /* 5. DDR:556.80 MHz BIMC: 278.40 MHz */ + < 5346 >, /* 6. DDR:662.40 MHz BIMC: 331.20 MHz */ + < 5712 >, /* 7. DDR:748.80 MHz BIMC: 374.40 MHz */ + < 6150 >, /* 8. DDR:796.80 MHz BIMC: 398.40 MHz */ + < 7105 >; /* 9. DDR:931.20 MHz BIMC: 465.60 MHz */ + }; + + msm_gpu: qcom,kgsl-3d0@1c00000 { + label = "kgsl-3d0"; + compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; + status = "ok"; + reg = <0x1c00000 0x40000 + 0xa0000 0x6fff>; + reg-names = "kgsl_3d0_reg_memory", "qfprom_memory"; + interrupts = <0 33 0>; + interrupt-names = "kgsl_3d0_irq"; + qcom,id = <0>; + qcom,chipid = <0x05000400>; + + qcom,initial-pwrlevel = <0>; + qcom,idle-timeout = <80>; //msecs + qcom,strtstp-sleepwake; + + qcom,highest-bank-bit = <14>; + qcom,snapshot-size = <1048576>; //bytes + + clocks = <&gcc GCC_OXILI_GFX3D_CLK>, + <&gcc GCC_OXILI_AHB_CLK>, + <&gcc GCC_BIMC_GFX_CLK>, + <&gcc GCC_BIMC_GPU_CLK>, + <&gcc GCC_OXILI_TIMER_CLK>, + <&gcc GCC_OXILI_AON_CLK>; + + clock-names = "core_clk", "iface_clk", + "mem_iface_clk", "alt_mem_iface_clk", + "rbbmtimer_clk", "alwayson_clk"; + + /* Bus Scale Settings */ + qcom,gpubw-dev = <&gpubw>; + qcom,bus-control; + qcom,bus-width = <16>; + qcom,msm-bus,name = "grp3d"; + qcom,msm-bus,num-cases = <10>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, /* off */ + <26 512 0 806400>, /* 1. 100.80 MHz */ + <26 512 0 1689600>, /* 2. 211.20 MHz */ + <26 512 0 2380800>, /* 3. 297.60 MHz */ + <26 512 0 3072000>, /* 4. 384.00 MHz */ + <26 512 0 4454400>, /* 5. 556.80 MHz */ + <26 512 0 5299200>, /* 6. 662.40 MHz */ + <26 512 0 5990400>, /* 7. 748.80 MHz */ + <26 512 0 6374400>, /* 8. 796.80 MHz */ + <26 512 0 7449600>; /* 9. 931.20 MHz */ + + /* GDSC regulator names */ + regulator-names = "vddcx", "vdd"; + /* GDSC oxili regulators */ + vddcx-supply = <&oxili_cx_gdsc>; + vdd-supply = <&oxili_gx_gdsc>; + + /* CPU latency parameter */ + qcom,pm-qos-active-latency = <360>; + qcom,pm-qos-wakeup-latency = <360>; + + /* Quirks */ + qcom,gpu-quirk-two-pass-use-wfi; + qcom,gpu-quirk-dp2clockgating-disable; + qcom,gpu-quirk-lmloadkill-disable; + + /* Enable context aware freq. scaling */ + qcom,enable-ca-jump; + + /* Context aware jump busy penalty in us */ + qcom,ca-busy-penalty = <12000>; + + /* Context aware jump target power level */ + qcom,ca-target-pwrlevel = <1>; + + /* Enable gpu cooling device */ + #cooling-cells = <2>; + + /* Power levels */ + qcom,gpu-pwrlevels { + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <320000000>; + qcom,bus-freq = <2>; + qcom,bus-min = <2>; + qcom,bus-max = <2>; + }; + qcom,gpu-pwrlevel@1{ + reg = <1>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; + + kgsl_msm_iommu: qcom,kgsl-iommu@1c40000 { + compatible = "qcom,kgsl-smmu-v2"; + + reg = <0x1c40000 0x10000>; + qcom,protect = <0x40000 0x10000>; + qcom,micro-mmu-control = <0x6000>; + + clocks = <&gcc GCC_OXILI_AHB_CLK>, + <&gcc GCC_BIMC_GFX_CLK>; + + clock-names = "gpu_ahb_clk", "gcc_bimc_gfx_clk"; + + qcom,secure_align_mask = <0xfff>; + qcom,retention; + gfx3d_user: gfx3d_user { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_user"; + iommus = <&kgsl_smmu 0>; + qcom,gpu-offset = <0x48000>; + }; + }; +}; -- GitLab From e3a66c5e388ae7433bccac5d3f6bab0a3ac094b7 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Fri, 3 Jul 2020 12:51:54 +0530 Subject: [PATCH 0996/1055] usb: host: xhci-plat: Fix IMOD configuration from sysfs Currently config_imod_store function checks for the return value of kstrtouint and bails out if it is not 1. But the success case return value of kstrtouint is 0 instead, with -ERANGE and -EINVAL being error case values. This leads to the IMOD setting failure. Fix this by fixing the return value check of kstrtouint. Change-Id: I723f4efbe9c39fc91d5f57ef657daaab61fba212 Signed-off-by: Ajay Agarwal --- drivers/usb/host/xhci-plat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 36aa81066857..85b3c924f25a 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -159,7 +159,7 @@ static ssize_t config_imod_store(struct device *pdev, u32 imod; unsigned long flags; - if (kstrtouint(buff, 10, &imod) != 1) + if (kstrtouint(buff, 10, &imod) < 0) return 0; imod &= ER_IRQ_INTERVAL_MASK; -- GitLab From bc46387cb27afe40e386044e29a3ed29b27b6eb3 Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Thu, 2 Jul 2020 19:33:41 +0530 Subject: [PATCH 0997/1055] i2c-msm-v2: Make init call as module_init for i2c driver Make init call as module_init for i2c driver instead of subsys_initcall. This is done to prevent clock off which happens in i2c probe, as the same clock is shared by uart (early console). Early console doesn't have a mechanism to vote for clocks so these clocks should be on till kernel console driver is probed which is happening as a module_init call. Change-Id: I10c6e4f0c5227db97bd5d31dc91c3ba4b9a74038 Signed-off-by: Prudhvi Yarlagadda --- drivers/i2c/busses/i2c-msm-v2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c index 3d9f7b925457..69c4a71826c0 100644 --- a/drivers/i2c/busses/i2c-msm-v2.c +++ b/drivers/i2c/busses/i2c-msm-v2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2020, 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 @@ -3037,7 +3037,7 @@ static int i2c_msm_init(void) { return platform_driver_register(&i2c_msm_driver); } -subsys_initcall(i2c_msm_init); +module_init(i2c_msm_init); static void i2c_msm_exit(void) { -- GitLab From 2a6005e3f2094abe356e364a34df907086676fac Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Fri, 3 Jul 2020 14:02:34 +0530 Subject: [PATCH 0998/1055] defconfig: Enable qcom_sps_dma driver for sdm429w Enable qcom_sps_dma driver for spyro(sdm429w) target. Change-Id: I954c6a4ad17abcfa245fe09d15b8b23d713beda6 Signed-off-by: Prudhvi Yarlagadda --- arch/arm/configs/vendor/sdm429-bg-perf_defconfig | 1 + arch/arm/configs/vendor/sdm429-bg_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig index b5270ed9de47..48f1a4866045 100644 --- a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig @@ -489,6 +489,7 @@ CONFIG_LEDS_QPNP_FLASH_V2=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y CONFIG_QCOM_GPI_DMA=y CONFIG_UIO=y CONFIG_UIO_MSM_SHAREDMEM=y diff --git a/arch/arm/configs/vendor/sdm429-bg_defconfig b/arch/arm/configs/vendor/sdm429-bg_defconfig index 8e0eb0c080a2..0aa1cc961671 100644 --- a/arch/arm/configs/vendor/sdm429-bg_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg_defconfig @@ -505,6 +505,7 @@ CONFIG_EDAC=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y CONFIG_QCOM_GPI_DMA=y CONFIG_QCOM_GPI_DMA_DEBUG=y CONFIG_DEBUG_DMA_BUF_REF=y -- GitLab From 15ccc24ddc235a2ea9b6cfa858454e7fef7253e0 Mon Sep 17 00:00:00 2001 From: YUE CHEN Date: Tue, 30 Jun 2020 14:22:30 +0800 Subject: [PATCH 0999/1055] msm: ais: acquire init_frame_drop from userspace add init_frame_drop in csi info, and pass it from user space. Change-Id: Ib98e425be2d9d99eeb375d6612866e747364cc15 Signed-off-by: YUE CHEN --- .../media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c | 3 +-- drivers/media/platform/msm/ais/ais_isp/include/ais_isp_hw.h | 1 + drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c b/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c index 4c7c5a780aff..eaf983776cb0 100644 --- a/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c +++ b/drivers/media/platform/msm/ais/ais_isp/csid_hw/ais_ife_csid_core.c @@ -570,6 +570,7 @@ static int ais_ife_csid_config_rdi_path( path_cfg->end_line = res->in_cfg.crop_bottom; path_cfg->decode_fmt = res->in_cfg.decode_format; path_cfg->plain_fmt = res->in_cfg.pack_type; + path_cfg->init_frame_drop = res->in_cfg.init_frame_drop; if (path_cfg->decode_fmt == 0xF) path_cfg->pix_enable = false; @@ -822,8 +823,6 @@ static int ais_ife_csid_enable_rdi_path( csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; path_data = &csid_hw->rdi_cfg[id]; - - path_data->init_frame_drop = 1; path_data->sof_cnt = 0; /* Enable the required RDI interrupts */ diff --git a/drivers/media/platform/msm/ais/ais_isp/include/ais_isp_hw.h b/drivers/media/platform/msm/ais/ais_isp/include/ais_isp_hw.h index c75e0b5685c2..e09030b2196f 100644 --- a/drivers/media/platform/msm/ais/ais_isp/include/ais_isp_hw.h +++ b/drivers/media/platform/msm/ais/ais_isp/include/ais_isp_hw.h @@ -270,6 +270,7 @@ struct ais_ife_rdi_in_cfg { uint32_t crop_bottom; uint32_t crop_left; uint32_t crop_right; + uint32_t init_frame_drop; uint32_t reserved; }; diff --git a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.c b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.c index 2cee173d2902..73a57ca7ae65 100644 --- a/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.c +++ b/drivers/media/platform/msm/ais/ais_isp/vfe_hw/ais_vfe_core.c @@ -1137,7 +1137,7 @@ static int ais_vfe_dispatch_irq(struct cam_hw_info *vfe_hw, core_info = (struct ais_vfe_hw_core_info *)vfe_hw->core_info; CAM_DBG(CAM_ISP, "VFE[%d] event %d", - core_info->vfe_idx, work_data->evt_type); + core_info->vfe_idx, p_work->evt_type); task = cam_req_mgr_workq_get_task(core_info->workq); if (!task) { -- GitLab From fe6253da0606f2394205b4445073bdfa919080f8 Mon Sep 17 00:00:00 2001 From: Ramendra Kumar Date: Sat, 27 Jun 2020 19:33:15 +0530 Subject: [PATCH 1000/1055] ARM: dts: msm: add display related dt nodes on QCS410 device Add DSI and bridge chip dt nodes on QCS410 device. Change-Id: I55665cb93ec0f462da7abb696b300450d4067fc7 Signed-off-by: Ramendra Kumar --- arch/arm64/boot/dts/qcom/qcs410-iot.dtsi | 129 ++++++++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi b/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi index 275b237c4ebd..237eaee48848 100644 --- a/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs410-iot.dtsi @@ -19,7 +19,9 @@ #include #include #include - +#include "qcs410.dtsi" +#include "sm6150-sde-pll.dtsi" +#include "sm6150-sde-display.dtsi" #include "qcs610-camera-sensor-idp.dtsi" / { @@ -32,6 +34,10 @@ #include "smb1390.dtsi" }; +&fsa4480 { + status = "disabled"; +}; + &pm6150l_gpios { key_vol_up { key_vol_up_default: key_vol_up_default { @@ -235,3 +241,124 @@ &L5C { regulator-max-microvolt = <2912000>; }; + +&sde_dp { + status="disabled"; +}; + +&mdss_dp_pll { + status="disabled"; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dsi>; +}; + +&qupv3_se1_i2c { + status = "ok"; + lt9611: lt,lt9611@3b { + compatible = "lt,lt9611"; + reg = <0x3b>; + interrupt-parent = <&tlmm>; + interrupts = <26 0>; + interrupt-names = "lt_irq"; + lt,irq-gpio = <&tlmm 26 0x0>; + lt,reset-gpio = <&tlmm 20 0x0>; + lt,hdmi-en-gpio = <&tlmm 79 0x0>; + instance_id = <0>; + lt,non-pluggable; + lt,preferred-mode = "1920x1080"; + + pinctrl-names = "default"; + pinctrl-0 = <<9611_pins>; + + vdd-supply = <&pm6150_l13>; + vcc-supply = <&pm6150_l16>; + + lt,supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + lt,supply-entry@0 { + reg = <0>; + lt,supply-name = "vdd"; + lt,supply-min-voltage = <1800000>; + lt,supply-max-voltage = <1800000>; + lt,supply-enable-load = <200000>; + lt,supply-post-on-sleep = <50>; + }; + lt,supply-entry@1 { + reg = <1>; + lt,supply-name = "vcc"; + lt,supply-min-voltage = <3304000>; + lt,supply-max-voltage = <3304000>; + lt,supply-enable-load = <200000>; + lt,supply-post-on-sleep = <50>; + }; + + + }; + + lt,customize-modes { + lt,customize-mode-id@0 { + lt,mode-h-active = <1920>; + lt,mode-h-front-porch = <88>; + lt,mode-h-pulse-width = <44>; + lt,mode-h-back-porch = <148>; + lt,mode-h-active-high; + lt,mode-v-active = <1080>; + lt,mode-v-front-porch = <4>; + lt,mode-v-pulse-width = <5>; + lt,mode-v-back-porch = <36>; + lt,mode-v-active-high; + lt,mode-refresh-rate = <60>; + lt,mode-clock-in-khz = <148500>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lt9611_in: endpoint { + remote-endpoint = <&ext_dsi_out>; + }; + }; + }; + }; +}; + +&dsi_ext_bridge_hdmi_1080p { + qcom,mdss-dsi-ext-bridge = <0>; +}; + +&soc { + ext_dsi_bridge_display: qcom,dsi-display@50 { + label = "ext_dsi_bridge_display hdmi 1080p"; + qcom,dsi-display-active; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + qcom,dsi-panel = <&dsi_ext_bridge_hdmi_1080p>; + }; +}; + +&sde_dsi { + qcom,dsi-display-list = <&ext_dsi_bridge_display>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ext_dsi_out: endpoint { + remote-endpoint = <<9611_in>; + }; + }; + }; +}; -- GitLab From 3719ec27cde92df5feca8b6563ea1dc23f7137f3 Mon Sep 17 00:00:00 2001 From: Timothy Sham Date: Sat, 14 Dec 2019 13:56:00 -0500 Subject: [PATCH 1001/1055] ARM: dts: msm: add gpr and gecko drivers to DT Add GPR and Gecko kernel sound card definition to the device tree. Change-Id: I4a4c6f4cb0304beacc3db4a0157d160106079b36 Signed-off-by: Timothy Sham Signed-off-by: Cong Tang --- arch/arm64/boot/dts/qcom/sa8155-audio.dtsi | 116 +++++++++++++++++++++ arch/arm64/boot/dts/qcom/sm8150.dtsi | 21 ++++ include/dt-bindings/sound/qcom,gpr.h | 39 +++++++ include/linux/mod_devicetable.h | 12 +++ 4 files changed, 188 insertions(+) create mode 100644 include/dt-bindings/sound/qcom,gpr.h diff --git a/arch/arm64/boot/dts/qcom/sa8155-audio.dtsi b/arch/arm64/boot/dts/qcom/sa8155-audio.dtsi index 0d69f1da7258..c369f3e1a1bd 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-audio.dtsi @@ -18,6 +18,10 @@ }; &soc { + gecko_core_platform: gecko_core_platform { + compatible = "qcom,gecko-core-platform"; + }; + tdm_pri_rx: qcom,msm-dai-tdm-pri-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37120>; @@ -596,6 +600,118 @@ qcom,msm-dai-q6 { }; }; +&gecko_core_platform { + msm_gecko_ion: qcom,msm-audio-ion { + compatible = "qcom,msm-audio-ion"; + qcom,smmu-version = <2>; + qcom,smmu-enabled; + iommus = <&apps_smmu 0x1b21 0x0>; + }; + + sound-adp-star { + compatible = "qcom,sa8155-gecko-asoc-snd-adp-star"; + qcom,model = "sa8155-adp-star-gecko-snd-card"; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + + qcom,sec-tdm-gpios = <&tdm_sec_rx>; + qcom,tert-tdm-gpios = <&tdm_tert_rx>; + qcom,quat-tdm-gpios = <&tdm_quat_rx>; + qcom,quin-tdm-gpios = <&tdm_quin_rx>; + + asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, + <&loopback>, <&compress>, <&hostless>, + <&afe>, <&lsm>, <&routing>, <&compr>, + <&pcm_noirq>, <&loopback1>, <&pcm_dtmf>; + asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", + "msm-pcm-dsp.2", "msm-voip-dsp", + "msm-pcm-voice", "msm-pcm-loopback", + "msm-compress-dsp", "msm-pcm-hostless", + "msm-pcm-afe", "msm-lsm-client", + "msm-pcm-routing", "msm-compr-dsp", + "msm-pcm-dsp-noirq", "msm-pcm-loopback.1", + "msm-pcm-dtmf"; + asoc-cpu = <&dai_hdmi>, <&dai_dp>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_mi2s4>, <&dai_pri_auxpcm>, + <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, + <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, + <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, + <&dai_pri_tdm_tx_0>, <&dai_pri_tdm_tx_1>, + <&dai_pri_tdm_tx_2>, <&dai_pri_tdm_tx_3>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_rx_1>, + <&dai_sec_tdm_rx_2>, <&dai_sec_tdm_rx_3>, + <&dai_sec_tdm_rx_7>, <&dai_sec_tdm_tx_0>, + <&dai_sec_tdm_tx_1>, <&dai_sec_tdm_tx_2>, + <&dai_sec_tdm_tx_3>, <&dai_tert_tdm_rx_0>, + <&dai_tert_tdm_rx_1>, <&dai_tert_tdm_rx_2>, + <&dai_tert_tdm_rx_3>, <&dai_tert_tdm_rx_4>, + <&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>, + <&dai_tert_tdm_tx_2>, <&dai_tert_tdm_tx_3>, + <&dai_tert_tdm_tx_7>, <&dai_quat_tdm_rx_0>, + <&dai_quat_tdm_rx_1>, <&dai_quat_tdm_rx_2>, + <&dai_quat_tdm_rx_3>, <&dai_quat_tdm_rx_7>, + <&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>, + <&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>, + <&dai_quat_tdm_tx_7>, <&dai_quin_tdm_rx_0>, + <&dai_quin_tdm_rx_1>, <&dai_quin_tdm_rx_2>, + <&dai_quin_tdm_rx_3>, <&dai_quin_tdm_rx_7>, + <&dai_quin_tdm_tx_0>, <&dai_quin_tdm_tx_1>, + <&dai_quin_tdm_tx_2>, <&dai_quin_tdm_tx_3>, + <&dai_quin_tdm_tx_7>; + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-mi2s.4", "msm-dai-q6-auxpcm.1", + "msm-dai-q6-auxpcm.2", "msm-dai-q6-auxpcm.3", + "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", + "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", + "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", + "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36866", + "msm-dai-q6-tdm.36868", "msm-dai-q6-tdm.36870", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36867", + "msm-dai-q6-tdm.36869", "msm-dai-q6-tdm.36871", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36882", + "msm-dai-q6-tdm.36884", "msm-dai-q6-tdm.36886", + "msm-dai-q6-tdm.36894", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36883", "msm-dai-q6-tdm.36885", + "msm-dai-q6-tdm.36887", "msm-dai-q6-tdm.36896", + "msm-dai-q6-tdm.36898", "msm-dai-q6-tdm.36900", + "msm-dai-q6-tdm.36902", "msm-dai-q6-tdm.36904", + "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899", + "msm-dai-q6-tdm.36901", "msm-dai-q6-tdm.36903", + "msm-dai-q6-tdm.36911", "msm-dai-q6-tdm.36912", + "msm-dai-q6-tdm.36914", "msm-dai-q6-tdm.36916", + "msm-dai-q6-tdm.36918", "msm-dai-q6-tdm.36926", + "msm-dai-q6-tdm.36913", "msm-dai-q6-tdm.36915", + "msm-dai-q6-tdm.36917", "msm-dai-q6-tdm.36919", + "msm-dai-q6-tdm.36927", "msm-dai-q6-tdm.36928", + "msm-dai-q6-tdm.36930", "msm-dai-q6-tdm.36932", + "msm-dai-q6-tdm.36934", "msm-dai-q6-tdm.36942", + "msm-dai-q6-tdm.36929", "msm-dai-q6-tdm.36931", + "msm-dai-q6-tdm.36933", "msm-dai-q6-tdm.36935", + "msm-dai-q6-tdm.36943"; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + }; +}; + +&msm_gecko_ion { + iommus = <&apps_smmu 0x1b21 0x0>; + qcom,smmu-sid-mask = /bits/ 64 <0xf>; +}; + &qupv3_se4_i2c { status = "disabled"; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index aa0d882dad60..bcc15b5f454e 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -2737,6 +2738,26 @@ qcom,intents = <0x200 20>; }; + qcom,gpr { + compatible = "qcom,gpr"; + qcom,glink-channels = "to_apps"; + qcom,intents = <0x200 20>; + reg = ; + gecko_core { + compatible = "qcom,gecko_core"; + reg = ; + }; + audio-pkt { + compatible = "qcom,audio-pkt"; + qcom,audiopkt-ch-name = "apr_audio_svc"; + reg = ; + }; + q6prm { + compatible = "qcom,q6prm"; + reg = ; + }; + }; + qcom,msm_fastrpc_rpmsg { compatible = "qcom,msm-fastrpc-rpmsg"; qcom,glink-channels = "fastrpcglink-apps-dsp"; diff --git a/include/dt-bindings/sound/qcom,gpr.h b/include/dt-bindings/sound/qcom,gpr.h new file mode 100644 index 000000000000..1ab6d2c99a1d --- /dev/null +++ b/include/dt-bindings/sound/qcom,gpr.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2020, 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 __DT_BINDINGS_QCOM_GPR_H +#define __DT_BINDINGS_QCOM_GPR_H + +/* Domain IDs */ +#define GPR_DOMAIN_SIM 0x1 +#define GPR_DOMAIN_PC 0x2 +#define GPR_DOMAIN_MODEM 0x3 +#define GPR_DOMAIN_ADSP 0x4 +#define GPR_DOMAIN_APPS 0x5 +#define GPR_DOMAIN_MAX 0x6 + +/* ADSP service IDs */ +#define GPR_SVC_ADSP_CORE 0x3 +#define GPR_SVC_AFE 0x4 +#define GPR_SVC_VSM 0x5 +#define GPR_SVC_VPM 0x6 +#define GPR_SVC_ASM 0x7 +#define GPR_SVC_ADM 0x8 +#define GPR_SVC_ADSP_MVM 0x09 +#define GPR_SVC_ADSP_CVS 0x0A +#define GPR_SVC_ADSP_CVP 0x0B +#define GPR_SVC_USM 0x0C +#define GPR_SVC_LSM 0x0D +#define GPR_SVC_VIDC 0x16 +#define GPR_SVC_MAX 0x17 + +#endif /* __DT_BINDINGS_QCOM_GPR_H */ diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 7490f2592f3a..129ceb61cfca 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -452,6 +452,18 @@ struct spi_device_id { kernel_ulong_t driver_data; /* Data private to the driver */ }; +/* gpr */ +#define GPR_NAME_SIZE 32 +#define GPR_MODULE_PREFIX "gpr:" + +struct gpr_device_id { + char name[GPR_NAME_SIZE]; + __u32 domain_id; + __u32 svc_id; + __u32 svc_version; + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + #define SPMI_NAME_SIZE 32 #define SPMI_MODULE_PREFIX "spmi:" -- GitLab From 5dda24b09cb1a012989d2b4c0631ba92a7e70fad Mon Sep 17 00:00:00 2001 From: Saurabh Sahu Date: Mon, 11 May 2020 16:52:27 +0530 Subject: [PATCH 1002/1055] clk: qcom: cpu-sdm: Add cpu clock driver for SDM Add support for CPU clock driver for scaling of cpu clocks on sdm targets. Change-Id: I9ab83b02052ab9b3e4342bc72380df799fb86976 Signed-off-by: Saurabh Sahu --- .../bindings/clock/qcom,sdm-cpucc.txt | 95 ++ drivers/clk/qcom/Kconfig | 8 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-cpu-sdm.c | 825 ++++++++++++++++++ drivers/clk/qcom/vdd-level-cpu.h | 35 + include/dt-bindings/clock/qcom,cpu-sdm.h | 21 + 6 files changed, 985 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,sdm-cpucc.txt create mode 100644 drivers/clk/qcom/clk-cpu-sdm.c create mode 100644 drivers/clk/qcom/vdd-level-cpu.h create mode 100644 include/dt-bindings/clock/qcom,cpu-sdm.h diff --git a/Documentation/devicetree/bindings/clock/qcom,sdm-cpucc.txt b/Documentation/devicetree/bindings/clock/qcom,sdm-cpucc.txt new file mode 100644 index 000000000000..483ca3d9e5d7 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sdm-cpucc.txt @@ -0,0 +1,95 @@ +Qualcomm Technologies, Inc. SDM CPU clock driver +--------------------------------------------------- + +It is the clock controller driver which provides higher frequency +clocks and allows CPU frequency scaling on sdm based platforms. + +Required properties: +- compatible: Shall contain following: + "qcom,cpu-clock-sdm" +- clocks: Phandle to the clock device. +- clock-names: Names of the used clocks. Shall contain following: + "xo_ao", "gpll0_ao" +- reg: Shall contain base register offset and size. +- reg-names: Names of the bases for the above registers. Shall contain following: + "apcs-c1-rcg-base", "apcs-cci-rcg-base", "apcs_pll", "efuse" +- vdd_dig_ao-supply: The regulator(active only) powering the digital logic of APSS PLL. +- vdd_hf_pll-supply: The regulator(active only) powering the Analog logic of APSS PLL. +- cpu-vdd-supply: The regulator powering the APSS C1 RCG and APSS CCI RCG. +- qcom,speedX-bin-vY-Z: A table of CPU frequency (Hz) to regulator voltage (uV) mapping. + Format: + This represents the max frequency possible for each possible + power configuration for a CPU that's binned as speed bin X, + speed bin revision Y. Version can be between [0-3]. Z + is the mux id c1 or cci. +- #clock-cells: Shall contain 1. + +Example: + clock_cpu: qcom,clock-cpu@0b011050 { + compatible = "qcom,cpu-clock-sdm"; + clocks = <&rpmcc RPM_SMD_XO_A_CLK_SRC>, + <&gcc GPLL0_AO_OUT_MAIN>; + clock-names = "xo_ao", "gpll0_ao" ; + reg = <0xb011050 0x8>, + <0xb1d1050 0x8>, + <0xb016000 0x34>, + <0x00a412c 0x8>; + reg-names = "apcs-c1-rcg-base", + "apcs-cci-rcg-base", "apcs_pll", "efuse"; + cpu-vdd-supply = <&apc_vreg_corner>; + vdd_dig_ao-supply = <&L12A_AO; + vdd_hf_pll-supply = <&VDD_CX_LEVEL_AO>; + qcom,speed0-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>, + < 1958400000 5>; + + qcom,speed0-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + qcom,speed1-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>, + < 1804800000 5>; + + qcom,speed1-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + qcom,speed4-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>, + < 1958400000 5>, + < 2016000000 6>; + + qcom,speed4-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + qcom,speed5-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>; + + qcom,speed5-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + #clock-cells = <1>; + }; diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index ecae059fdff6..7b0db60cda9f 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -688,3 +688,11 @@ config SDM_DEBUGCC_429W Support for the debug clock controller on Qualcomm Technologies, Inc SDM429W devices. Say Y if you want to support the clock measurement functionality. + +config CLOCK_CPU_SDM + bool "CPU SDM Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the cpu clock controller on SDM based devices(e.g. SDM429). + Say Y if you want to support CPU clock scaling using + CPUfreq drivers for dynamic power management. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 4c1779de5a59..8fe6d4e11a5a 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o obj-$(CONFIG_CLOCK_CPU_OSM) += clk-cpu-osm.o obj-$(CONFIG_CLOCK_CPU_OSM_660) += clk-cpu-osm-660.o obj-$(CONFIG_CLOCK_CPU_QCS405) += clk-cpu-qcs405.o +obj-$(CONFIG_CLOCK_CPU_SDM) += clk-cpu-sdm.o obj-$(CONFIG_CLOCK_CPU_SDXPRAIRIE) += clk-cpu-sdxprairie.o obj-$(CONFIG_DEBUGCC_SDXPRAIRIE) += debugcc-sdxprairie.o obj-$(CONFIG_GCC_SDXPRAIRIE) += gcc-sdxprairie.o diff --git a/drivers/clk/qcom/clk-cpu-sdm.c b/drivers/clk/qcom/clk-cpu-sdm.c new file mode 100644 index 000000000000..c1a00aab2a01 --- /dev/null +++ b/drivers/clk/qcom/clk-cpu-sdm.c @@ -0,0 +1,825 @@ +/* + * Copyright (c) 2020, 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 "clk-pll.h" +#include "clk-debug.h" +#include "clk-rcg.h" +#include "clk-regmap-mux-div.h" +#include "common.h" +#include "vdd-level-cpu.h" + +#define to_clk_regmap_mux_div(_hw) \ + container_of(to_clk_regmap(_hw), struct clk_regmap_mux_div, clkr) + +static DEFINE_VDD_REGULATORS(vdd_hf_pll, VDD_HF_PLL_NUM, 2, vdd_hf_levels); +static DEFINE_VDD_REGS_INIT(vdd_cpu_c1, 1); +static DEFINE_VDD_REGS_INIT(vdd_cpu_cci, 1); + +enum apcs_mux_clk_parent { + P_BI_TCXO_AO, + P_GPLL0_AO_OUT_MAIN, + P_APCS_CPU_PLL, +}; + +static const struct parent_map apcs_mux_clk_parent_map0[] = { + { P_BI_TCXO_AO, 0 }, + { P_GPLL0_AO_OUT_MAIN, 4 }, + { P_APCS_CPU_PLL, 5 }, +}; + +static const char *const apcs_mux_clk_parent_name0[] = { + "bi_tcxo_ao", + "gpll0_ao_out_main", + "apcs_cpu_pll", +}; + +static const struct parent_map apcs_mux_clk_parent_map1[] = { + { P_BI_TCXO_AO, 0 }, + { P_GPLL0_AO_OUT_MAIN, 4 }, +}; + +static const char *const apcs_mux_clk_parent_name1[] = { + "bi_tcxo_ao", + "gpll0_ao_out_main", +}; + +static int cpucc_clk_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, + unsigned long prate, u8 index) +{ + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + + return __mux_div_set_src_div(cpuclk, cpuclk->parent_map[index].cfg, + cpuclk->div); +} + +static int cpucc_clk_set_parent(struct clk_hw *hw, u8 index) +{ + return 0; +} + +static int cpucc_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long prate) +{ + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + + return __mux_div_set_src_div(cpuclk, cpuclk->src, cpuclk->div); +} + +static int cpucc_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_hw *xo, *apcs_gpll0_hw, *apcs_cpu_pll_hw; + struct clk_rate_request parent_req = { }; + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + unsigned long apcs_gpll0_rate, apcs_gpll0_rrate, rate = req->rate; + unsigned long mask = BIT(cpuclk->hid_width) - 1; + u32 div = 1; + int ret; + + xo = clk_hw_get_parent_by_index(hw, P_BI_TCXO_AO); + if (rate == clk_hw_get_rate(xo)) { + req->best_parent_hw = xo; + req->best_parent_rate = rate; + cpuclk->div = div; + cpuclk->src = cpuclk->parent_map[P_BI_TCXO_AO].cfg; + return 0; + } + + apcs_gpll0_hw = clk_hw_get_parent_by_index(hw, P_GPLL0_AO_OUT_MAIN); + apcs_cpu_pll_hw = clk_hw_get_parent_by_index(hw, P_APCS_CPU_PLL); + + apcs_gpll0_rate = clk_hw_get_rate(apcs_gpll0_hw); + apcs_gpll0_rrate = DIV_ROUND_UP(apcs_gpll0_rate, 1000000) * 1000000; + + if (rate <= apcs_gpll0_rrate) { + req->best_parent_hw = apcs_gpll0_hw; + req->best_parent_rate = apcs_gpll0_rrate; + div = DIV_ROUND_CLOSEST(2 * apcs_gpll0_rrate, rate) - 1; + div = min_t(unsigned long, div, mask); + req->rate = clk_rcg2_calc_rate(req->best_parent_rate, 0, + 0, 0, div); + cpuclk->src = cpuclk->parent_map[P_GPLL0_AO_OUT_MAIN].cfg; + } else { + parent_req.rate = rate; + parent_req.best_parent_hw = apcs_cpu_pll_hw; + + req->best_parent_hw = apcs_cpu_pll_hw; + ret = __clk_determine_rate(req->best_parent_hw, &parent_req); + if (ret) + return ret; + + req->best_parent_rate = parent_req.rate; + cpuclk->src = cpuclk->parent_map[P_APCS_CPU_PLL].cfg; + } + + cpuclk->div = div; + + return 0; +} + +static void cpucc_clk_list_registers(struct seq_file *f, struct clk_hw *hw) +{ + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + int i = 0, size = 0, val; + + static struct clk_register_data data[] = { + {"CMD_RCGR", 0x0}, + {"CFG_RCGR", 0x4}, + }; + + size = ARRAY_SIZE(data); + for (i = 0; i < size; i++) { + regmap_read(cpuclk->clkr.regmap, + cpuclk->reg_offset + data[i].offset, &val); + clock_debug_output(f, false, + "%20s: 0x%.8x\n", data[i].name, val); + } +} + +static unsigned long cpucc_clk_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct clk_regmap_mux_div *cpuclk = to_clk_regmap_mux_div(hw); + struct clk_hw *parent; + const char *name = clk_hw_get_name(hw); + unsigned long parent_rate; + u32 i, div, src = 0; + u32 num_parents = clk_hw_get_num_parents(hw); + int ret; + + ret = mux_div_get_src_div(cpuclk, &src, &div); + if (ret) + return ret; + + cpuclk->src = src; + cpuclk->div = div; + + for (i = 0; i < num_parents; i++) { + if (src == cpuclk->parent_map[i].cfg) { + parent = clk_hw_get_parent_by_index(hw, i); + parent_rate = clk_hw_get_rate(parent); + return clk_rcg2_calc_rate(parent_rate, 0, 0, 0, div); + } + } + pr_err("%s: Can't find parent %d\n", name, src); + + return ret; +} + +static int cpucc_clk_enable(struct clk_hw *hw) +{ + return clk_regmap_mux_div_ops.enable(hw); +} + +static void cpucc_clk_disable(struct clk_hw *hw) +{ + clk_regmap_mux_div_ops.disable(hw); +} + +static u8 cpucc_clk_get_parent(struct clk_hw *hw) +{ + return clk_regmap_mux_div_ops.get_parent(hw); +} + +/* + * We use the notifier function for switching to a temporary safe configuration + * (mux and divider), while the APSS pll is reconfigured. + */ +static int cpucc_notifier_cb(struct notifier_block *nb, unsigned long event, + void *data) +{ + struct clk_regmap_mux_div *cpuclk = container_of(nb, + struct clk_regmap_mux_div, clk_nb); + int ret = 0, safe_src = cpuclk->safe_src; + + switch (event) { + case PRE_RATE_CHANGE: + /* set the mux to safe source gpll0_ao_out & div */ + ret = __mux_div_set_src_div(cpuclk, safe_src, 1); + break; + case ABORT_RATE_CHANGE: + pr_err("Error in configuring PLL - stay at safe src only\n"); + } + + return notifier_from_errno(ret); +} + +static const struct clk_ops cpucc_clk_ops = { + .enable = cpucc_clk_enable, + .disable = cpucc_clk_disable, + .get_parent = cpucc_clk_get_parent, + .set_rate = cpucc_clk_set_rate, + .set_parent = cpucc_clk_set_parent, + .set_rate_and_parent = cpucc_clk_set_rate_and_parent, + .determine_rate = cpucc_clk_determine_rate, + .recalc_rate = cpucc_clk_recalc_rate, + .debug_init = clk_debug_measure_add, + .list_registers = cpucc_clk_list_registers, +}; + +/* Initial configuration for 1305.6MHz */ +static const struct pll_config apcs_cpu_pll_config = { + .l = 0x44, + .m = 0, + .n = 1, + .pre_div_val = 0x0, + .pre_div_mask = 0x7 << 12, + .post_div_val = 0x0, + .post_div_mask = 0x3 << 8, + .main_output_mask = BIT(0), + .aux_output_mask = BIT(1), +}; + +static struct clk_pll apcs_cpu_pll = { + .mode_reg = 0x0, + .l_reg = 0x4, + .m_reg = 0x8, + .n_reg = 0xc, + .config_reg = 0x10, + .status_reg = 0x1c, + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "apcs_cpu_pll", + .parent_names = (const char *[]){ "bi_tcxo_ao" }, + .num_parents = 1, + .ops = &clk_pll_hf_ops, + .vdd_class = &vdd_hf_pll, + .rate_max = (unsigned long[VDD_HF_PLL_NUM]) { + [VDD_HF_PLL_SVS] = 1000000000, + [VDD_HF_PLL_NOM] = 2020000000, + }, + .num_rate_max = VDD_HF_PLL_NUM, + }, +}; + +static struct clk_regmap_mux_div apcs_mux_c1_clk = { + .reg_offset = 0x0, + .hid_width = 5, + .hid_shift = 0, + .src_width = 3, + .src_shift = 8, + .safe_src = 4, + .safe_div = 1, + .parent_map = apcs_mux_clk_parent_map0, + .clk_nb.notifier_call = cpucc_notifier_cb, + .clkr.hw.init = &(struct clk_init_data) { + .name = "apcs_mux_c1_clk", + .parent_names = apcs_mux_clk_parent_name0, + .num_parents = 3, + .vdd_class = &vdd_cpu_c1, + .flags = CLK_SET_RATE_PARENT, + .ops = &cpucc_clk_ops, + }, +}; + +static struct clk_regmap_mux_div apcs_mux_cci_clk = { + .reg_offset = 0x0, + .hid_width = 5, + .hid_shift = 0, + .src_width = 3, + .src_shift = 8, + .safe_src = 4, + .safe_div = 1, + .parent_map = apcs_mux_clk_parent_map1, + .clkr.hw.init = &(struct clk_init_data) { + .name = "apcs_mux_cci_clk", + .parent_names = apcs_mux_clk_parent_name1, + .num_parents = 2, + .vdd_class = &vdd_cpu_cci, + .flags = CLK_SET_RATE_PARENT, + .ops = &cpucc_clk_ops, + }, +}; + +static const struct of_device_id match_table[] = { + { .compatible = "qcom,cpu-clock-sdm" }, + {} +}; + +static struct regmap_config cpu_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x34, + .fast_io = true, +}; + +static struct clk_hw *cpu_clks_hws[] = { + [APCS_CPU_PLL] = &apcs_cpu_pll.clkr.hw, + [APCS_MUX_C1_CLK] = &apcs_mux_c1_clk.clkr.hw, + [APCS_MUX_CCI_CLK] = &apcs_mux_cci_clk.clkr.hw, +}; + +static void cpucc_clk_get_speed_bin(struct platform_device *pdev, int *bin, + int *version) +{ + struct resource *res; + void __iomem *base; + u32 pte_efuse; + + *bin = 0; + *version = 0; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "efuse"); + if (!res) { + dev_info(&pdev->dev, + "No speed/PVS binning available. Defaulting to 0!\n"); + return; + } + + base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!base) { + dev_info(&pdev->dev, + "Unable to read efuse data. Defaulting to 0!\n"); + return; + } + + pte_efuse = readl_relaxed(base); + devm_iounmap(&pdev->dev, base); + + *bin = (pte_efuse >> 2) & 0x7; + + dev_info(&pdev->dev, "PVS version: %d speed bin: %d\n", *version, *bin); +} + +static int cpucc_clk_get_fmax_vdd_class(struct platform_device *pdev, + struct clk_init_data *clk_intd, char *prop_name) +{ + struct device_node *of = pdev->dev.of_node; + struct clk_vdd_class *vdd = clk_intd->vdd_class; + u32 *array; + int prop_len, i, j, ret; + int num = vdd->num_regulators + 1; + + if (!of_find_property(of, prop_name, &prop_len)) { + dev_err(&pdev->dev, "missing %s\n", prop_name); + return -EINVAL; + } + + prop_len /= sizeof(u32); + if (prop_len % num) { + dev_err(&pdev->dev, "bad length %d\n", prop_len); + return -EINVAL; + } + + prop_len /= num; + vdd->level_votes = devm_kzalloc(&pdev->dev, prop_len * sizeof(int), + GFP_KERNEL); + if (!vdd->level_votes) + return -ENOMEM; + + vdd->vdd_uv = devm_kzalloc(&pdev->dev, + prop_len * sizeof(int) * (num - 1), GFP_KERNEL); + if (!vdd->vdd_uv) + return -ENOMEM; + + clk_intd->rate_max = devm_kzalloc(&pdev->dev, + prop_len * sizeof(unsigned long), GFP_KERNEL); + if (!clk_intd->rate_max) + return -ENOMEM; + + array = devm_kzalloc(&pdev->dev, + prop_len * sizeof(u32) * num, GFP_KERNEL); + if (!array) + return -ENOMEM; + + ret = of_property_read_u32_array(of, prop_name, array, prop_len * num); + if (ret) + return -ENOMEM; + + for (i = 0; i < prop_len; i++) { + clk_intd->rate_max[i] = array[num * i]; + for (j = 1; j < num; j++) { + vdd->vdd_uv[(num - 1) * i + (j - 1)] = + array[num * i + j]; + } + } + + devm_kfree(&pdev->dev, array); + vdd->num_levels = prop_len; + vdd->cur_level = prop_len; + clk_intd->num_rate_max = prop_len; + + return 0; +} + +static int find_vdd_level(struct clk_init_data *clk_intd, unsigned long rate) +{ + int level; + + for (level = 0; level < clk_intd->num_rate_max; level++) + if (rate <= clk_intd->rate_max[level]) + break; + + if (level == clk_intd->num_rate_max) { + pr_err("Rate %lu for %s is greater than highest Fmax\n", rate, + clk_intd->name); + return -EINVAL; + } + + return level; +} + +static int +cpucc_clk_add_opp(struct clk_hw *hw, struct device *dev, unsigned long max_rate) +{ + struct clk_init_data *clk_intd = (struct clk_init_data *)hw->init; + struct clk_vdd_class *vdd = clk_intd->vdd_class; + int level, uv, j = 1; + unsigned long rate = 0; + long ret; + + if (IS_ERR_OR_NULL(dev)) { + pr_err("%s: Invalid parameters\n", __func__); + return -EINVAL; + } + + while (1) { + rate = clk_intd->rate_max[j++]; + level = find_vdd_level(clk_intd, rate); + if (level <= 0) { + pr_warn("clock-cpu: no corner for %lu.\n", rate); + return -EINVAL; + } + + uv = vdd->vdd_uv[level]; + if (uv < 0) { + pr_warn("clock-cpu: no uv for %lu.\n", rate); + return -EINVAL; + } + + ret = dev_pm_opp_add(dev, rate, uv); + if (ret) { + pr_warn("clock-cpu: failed to add OPP for %lu\n", rate); + return rate; + } + + if (rate >= max_rate) + break; + } + + return 0; +} + +static void cpucc_clk_print_opp_table(int cpu) +{ + struct dev_pm_opp *oppfmax, *oppfmin; + unsigned long apc_c1_fmax, apc_c1_fmin; + u32 max_index = apcs_mux_c1_clk.clkr.hw.init->num_rate_max; + + apc_c1_fmax = apcs_mux_c1_clk.clkr.hw.init->rate_max[max_index - 1]; + apc_c1_fmin = apcs_mux_c1_clk.clkr.hw.init->rate_max[1]; + + oppfmax = dev_pm_opp_find_freq_exact(get_cpu_device(cpu), + apc_c1_fmax, true); + oppfmin = dev_pm_opp_find_freq_exact(get_cpu_device(cpu), + apc_c1_fmin, true); + pr_info("Clock_cpu:(cpu %d) OPP voltage for %lu: %ld\n", cpu, + apc_c1_fmin, dev_pm_opp_get_voltage(oppfmin)); + pr_info("Clock_cpu:(cpu %d) OPP voltage for %lu: %ld\n", cpu, + apc_c1_fmax, dev_pm_opp_get_voltage(oppfmax)); + +} + +static void cpucc_clk_populate_opp_table(struct platform_device *pdev) +{ + unsigned long apc_c1_fmax; + u32 max_index = apcs_mux_c1_clk.clkr.hw.init->num_rate_max; + int cpu, sdm_cpu = 0; + + apc_c1_fmax = apcs_mux_c1_clk.clkr.hw.init->rate_max[max_index - 1]; + + for_each_possible_cpu(cpu) { + sdm_cpu = cpu; + WARN(cpucc_clk_add_opp(&apcs_mux_c1_clk.clkr.hw, + get_cpu_device(cpu), apc_c1_fmax), + "Failed to add OPP levels for apcs_mux_c1_clk\n"); + } + cpucc_clk_print_opp_table(sdm_cpu); +} + +static int cpucc_driver_probe(struct platform_device *pdev) +{ + struct resource *res; + struct clk_hw_onecell_data *data; + struct device *dev = &pdev->dev; + struct clk *clk; + int i, ret, speed_bin, version, cpu; + char prop_name[] = "qcom,speedX-bin-vX-XXX"; + void __iomem *base; + + clk = devm_clk_get(dev, "xo_ao"); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(dev, "Unable to get xo clock\n"); + return PTR_ERR(clk); + } + + clk = devm_clk_get(dev, "gpll0_ao"); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(dev, "Unable to get GPLL0 clock\n"); + return PTR_ERR(clk); + } + + /* Rail Regulator for apcs_pll */ + vdd_hf_pll.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_hf_pll"); + if (IS_ERR(vdd_hf_pll.regulator[0])) { + if (!(PTR_ERR(vdd_hf_pll.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_hf_pll regulator\n"); + return PTR_ERR(vdd_hf_pll.regulator[0]); + } + + vdd_hf_pll.regulator[1] = devm_regulator_get(&pdev->dev, "vdd_dig_ao"); + if (IS_ERR(vdd_hf_pll.regulator[1])) { + if (!(PTR_ERR(vdd_hf_pll.regulator[1]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_dig_ao regulator\n"); + return PTR_ERR(vdd_hf_pll.regulator[1]); + } + + /* Rail Regulator for APCS C1 mux */ + vdd_cpu_c1.regulator[0] = devm_regulator_get(&pdev->dev, "cpu-vdd"); + if (IS_ERR(vdd_cpu_c1.regulator[0])) { + if (!(PTR_ERR(vdd_cpu_c1.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get cpu-vdd regulator\n"); + return PTR_ERR(vdd_cpu_c1.regulator[0]); + } + + /* Rail Regulator for APCS CCI mux */ + vdd_cpu_cci.regulator[0] = devm_regulator_get(&pdev->dev, "cpu-vdd"); + if (IS_ERR(vdd_cpu_cci.regulator[0])) { + if (!(PTR_ERR(vdd_cpu_cci.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get cpu-vdd regulator\n"); + return PTR_ERR(vdd_cpu_cci.regulator[0]); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs_pll"); + if (res == NULL) { + dev_err(&pdev->dev, "Failed to get apcs_pll resources\n"); + return -EINVAL; + } + + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed map apcs_cpu_pll register base\n"); + return PTR_ERR(base); + } + + cpu_regmap_config.name = "apcs_pll"; + apcs_cpu_pll.clkr.regmap = devm_regmap_init_mmio(dev, base, + &cpu_regmap_config); + if (IS_ERR(apcs_cpu_pll.clkr.regmap)) { + dev_err(&pdev->dev, "Couldn't get regmap for apcs_cpu_pll\n"); + return PTR_ERR(apcs_cpu_pll.clkr.regmap); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "apcs-c1-rcg-base"); + if (res == NULL) { + dev_err(&pdev->dev, "Failed to get apcs-c1 resources\n"); + return -EINVAL; + } + + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed map apcs-c1-rcg register base\n"); + return PTR_ERR(base); + } + + cpu_regmap_config.name = "apcs-c1-rcg-base"; + apcs_mux_c1_clk.clkr.regmap = devm_regmap_init_mmio(dev, base, + &cpu_regmap_config); + if (IS_ERR(apcs_mux_c1_clk.clkr.regmap)) { + dev_err(&pdev->dev, "Couldn't get regmap for apcs-c1-rcg\n"); + return PTR_ERR(apcs_mux_c1_clk.clkr.regmap); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "apcs-cci-rcg-base"); + if (res == NULL) { + dev_err(&pdev->dev, "Failed to get apcs-cci resources\n"); + return -EINVAL; + } + + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed map apcs-cci-rcg register base\n"); + return PTR_ERR(base); + } + + cpu_regmap_config.name = "apcs-cci-rcg-base"; + apcs_mux_cci_clk.clkr.regmap = devm_regmap_init_mmio(dev, base, + &cpu_regmap_config); + if (IS_ERR(apcs_mux_cci_clk.clkr.regmap)) { + dev_err(&pdev->dev, "Couldn't get regmap for apcs-cci-rcg\n"); + return PTR_ERR(apcs_mux_cci_clk.clkr.regmap); + } + + /* Get speed bin information */ + cpucc_clk_get_speed_bin(pdev, &speed_bin, &version); + + snprintf(prop_name, ARRAY_SIZE(prop_name), + "qcom,speed%d-bin-v%d-%s", speed_bin, version, "c1"); + + ret = cpucc_clk_get_fmax_vdd_class(pdev, + (struct clk_init_data *)apcs_mux_c1_clk.clkr.hw.init, + prop_name); + if (ret) { + dev_err(&pdev->dev, "Didn't get c1 speed bin\n"); + ret = cpucc_clk_get_fmax_vdd_class(pdev, + (struct clk_init_data *) + apcs_mux_c1_clk.clkr.hw.init, + prop_name); + if (ret) { + dev_err(&pdev->dev, "Unable to get vdd class for c1\n"); + return ret; + } + } + + snprintf(prop_name, ARRAY_SIZE(prop_name), + "qcom,speed%d-bin-v%d-%s", speed_bin, version, "cci"); + + ret = cpucc_clk_get_fmax_vdd_class(pdev, + (struct clk_init_data *)apcs_mux_cci_clk.clkr.hw.init, + prop_name); + if (ret) { + dev_err(&pdev->dev, "Didn't get cci speed bin\n"); + ret = cpucc_clk_get_fmax_vdd_class(pdev, + (struct clk_init_data *) + apcs_mux_cci_clk.clkr.hw.init, + prop_name); + if (ret) { + dev_err(&pdev->dev, "Unable get vdd class for cci\n"); + return ret; + } + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->num = ARRAY_SIZE(cpu_clks_hws); + + for (i = 0; i < ARRAY_SIZE(cpu_clks_hws); i++) { + ret = devm_clk_hw_register(dev, cpu_clks_hws[i]); + if (ret) { + dev_err(&pdev->dev, "Failed to register clock\n"); + return ret; + } + data->hws[i] = cpu_clks_hws[i]; + } + + ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, data); + if (ret) { + dev_err(&pdev->dev, "CPU clock driver registeration failed\n"); + return ret; + } + + /* For safe freq switching during rate change */ + ret = clk_notifier_register(apcs_mux_c1_clk.clkr.hw.clk, + &apcs_mux_c1_clk.clk_nb); + if (ret) { + dev_err(dev, "failed to register clock notifier: %d\n", ret); + return ret; + } + + /* + * To increase the enable count for the clocks so + * that they dont get disabled during late init. + */ + get_online_cpus(); + for_each_online_cpu(cpu) { + WARN(clk_prepare_enable(apcs_mux_c1_clk.clkr.hw.clk), + "Unable to turn on CPU clock\n"); + clk_prepare_enable(apcs_mux_cci_clk.clkr.hw.clk); + } + put_online_cpus(); + + cpucc_clk_populate_opp_table(pdev); + dev_info(dev, "CPU clock Driver probed successfully\n"); + + return ret; +} + +static struct platform_driver cpu_clk_driver = { + .probe = cpucc_driver_probe, + .driver = { + .name = "qcom-cpu-sdm", + .of_match_table = match_table, + }, +}; + +static int __init cpu_clk_init(void) +{ + return platform_driver_register(&cpu_clk_driver); +} +subsys_initcall(cpu_clk_init); + +static void __exit cpu_clk_exit(void) +{ + platform_driver_unregister(&cpu_clk_driver); +} +module_exit(cpu_clk_exit); + +#define REG_OFFSET 0x4 +#define APCS_PLL 0x0b016000 +#define A53SS_MUX_C1 0x0b011050 + +static void config_enable_hf_pll(void __iomem *base) +{ + /* Configure USER_CTL value */ + writel_relaxed(0xf, base + apcs_cpu_pll.config_reg); + + /* Enable the pll */ + writel_relaxed(0x2, base + apcs_cpu_pll.mode_reg); + udelay(2); + writel_relaxed(0x6, base + apcs_cpu_pll.mode_reg); + udelay(50); + writel_relaxed(0x7, base + apcs_cpu_pll.mode_reg); + /* Ensure that the writes go through before enabling PLL */ + mb(); +} + +static int __init cpu_clock_init(void) +{ + struct device_node *dev; + void __iomem *base; + int count, regval = 0; + unsigned long enable_mask = GENMASK(2, 0); + + dev = of_find_compatible_node(NULL, NULL, "qcom,cpu-clock-sdm"); + if (!dev) { + pr_debug("device node not initialized\n"); + return -ENOMEM; + } + + base = ioremap_nocache(APCS_PLL, SZ_64); + if (!base) + return -ENOMEM; + + regval = readl_relaxed(base); + if (!((regval & enable_mask) == enable_mask)) + config_enable_hf_pll(base); + + iounmap(base); + + base = ioremap_nocache(A53SS_MUX_C1, SZ_8); + if (!base) + return -ENOMEM; + + writel_relaxed(0x501, base + REG_OFFSET); + + /* Update bit */ + regval = readl_relaxed(base); + regval |= BIT(0); + writel_relaxed(regval, base); + + /* Wait for update to take effect */ + for (count = 500; count > 0; count--) { + if ((!(readl_relaxed(base))) & BIT(0)) + break; + udelay(1); + } + + /* Update bit */ + regval = readl_relaxed(base); + regval |= BIT(0); + writel_relaxed(regval, base); + + /* Wait for update to take effect */ + for (count = 500; count > 0; count--) { + if ((!(readl_relaxed(base))) & BIT(0)) + break; + udelay(1); + } + + return 0; +} +early_initcall(cpu_clock_init); + +MODULE_ALIAS("platform:cpu"); +MODULE_DESCRIPTION("SDM CPU clock Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/vdd-level-cpu.h b/drivers/clk/qcom/vdd-level-cpu.h new file mode 100644 index 000000000000..5937dde69775 --- /dev/null +++ b/drivers/clk/qcom/vdd-level-cpu.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020, 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 __DRIVERS_CLK_QCOM_VDD_LEVEL_CPU_H +#define __DRIVERS_CLK_QCOM_VDD_LEVEL_CPU_H + +#include +#include + +enum vdd_hf_pll_levels { + VDD_HF_PLL_OFF, + VDD_HF_PLL_SVS, + VDD_HF_PLL_NOM, + VDD_HF_PLL_TUR, + VDD_HF_PLL_NUM, +}; + +static int vdd_hf_levels[] = { + 0, RPM_REGULATOR_LEVEL_NONE, /* VDD_HF_PLL_OFF */ + 1800000, RPM_REGULATOR_LEVEL_SVS, /* VDD_HF_PLL_SVS */ + 1800000, RPM_REGULATOR_LEVEL_NOM, /* VDD_HF_PLL_NOM */ + 1800000, RPM_REGULATOR_LEVEL_TURBO, /* VDD_HF_PLL_TUR */ +}; + +#endif diff --git a/include/dt-bindings/clock/qcom,cpu-sdm.h b/include/dt-bindings/clock/qcom,cpu-sdm.h new file mode 100644 index 000000000000..a9c8b7f65006 --- /dev/null +++ b/include/dt-bindings/clock/qcom,cpu-sdm.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2020, 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 _DT_BINDINGS_CLK_QCOM_CPU_SDM_H +#define _DT_BINDINGS_CLK_QCOM_CPU_SDM_H + +#define APCS_CPU_PLL 0 +#define APCS_MUX_C1_CLK 1 +#define APCS_MUX_CCI_CLK 2 + +#endif -- GitLab From b23b8aad6a1107a63ba8f3eed7122e604ef055c0 Mon Sep 17 00:00:00 2001 From: Saurabh Sahu Date: Wed, 13 May 2020 19:02:19 +0530 Subject: [PATCH 1003/1055] ARM: dts: msm: Add CPU clock support for sdm429w Add clock_cpu node for sdm429w for client to able to request clocks for CPU scaling. Change-Id: Ief6e4ddc7553cd04656347713f62a1299b13935b Signed-off-by: Saurabh Sahu --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 70 ++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index b69c21a4f12c..f98189ea9676 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -17,6 +17,7 @@ #include #include #include +#include / { model = "Qualcomm Technologies, Inc. SDM429"; @@ -341,6 +342,75 @@ #clock-cells = <1>; }; + cpu: qcom,clock-cpu@b011050 { + compatible = "qcom,cpu-clock-sdm"; + reg = <0xb011050 0x8>, + <0xb1d1050 0x8>, + <0xB016000 0x34>, + <0x00a412c 0x8>; + reg-names = "apcs-c1-rcg-base", + "apcs-cci-rcg-base", "apcs_pll", "efuse"; + clocks = <&rpmcc RPM_SMD_XO_A_CLK_SRC>, + <&gcc GPLL0_AO_OUT_MAIN>; + clock-names = "xo_ao", "gpll0_ao" ; + cpu-vdd-supply = <&apc_vreg_corner>; + vdd_hf_pll-supply = <&L12A_AO>; + vdd_dig_ao-supply = <&VDD_CX_LEVEL_AO>; + qcom,speed0-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>, + < 1958400000 5>; + + qcom,speed0-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + qcom,speed1-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>, + < 1804800000 5>; + + qcom,speed1-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + qcom,speed4-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>, + < 1958400000 5>, + < 2016000000 6>; + + qcom,speed4-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + qcom,speed5-bin-v0-c1 = + < 0 0>, + < 960000000 1>, + < 1305600000 1>, + < 1497600000 2>, + < 1708800000 3>; + + qcom,speed5-bin-v0-cci = + < 0 0>, + < 400000000 1>, + < 533333333 3>; + + #clock-cells = <1>; + }; + cpu-pmu { compatible = "arm,armv8-pmuv3"; interrupts = <1 7 0xff00>; -- GitLab From 953d33ad140586debd146708774a857f0cfa1117 Mon Sep 17 00:00:00 2001 From: Saurabh Sahu Date: Wed, 13 May 2020 19:02:37 +0530 Subject: [PATCH 1004/1055] defconfig: sdm: Add support for CPU clocks Enable CPU Clock Controller for sdm targets. Change-Id: Ie700b13b98d8dfcc006709e9baeeb5b91482cee8 Signed-off-by: Saurabh Sahu --- arch/arm/configs/vendor/sdm429-bg-perf_defconfig | 1 + arch/arm/configs/vendor/sdm429-bg_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig index b5270ed9de47..6d6e3e7b4872 100644 --- a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig @@ -506,6 +506,7 @@ CONFIG_QCOM_CLK_SMD_RPM=y CONFIG_SPMI_PMIC_CLKDIV=y CONFIG_SDM_GCC_429W=y CONFIG_SDM_DEBUGCC_429W=y +CONFIG_CLOCK_CPU_SDM=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y diff --git a/arch/arm/configs/vendor/sdm429-bg_defconfig b/arch/arm/configs/vendor/sdm429-bg_defconfig index 8e0eb0c080a2..c81678c06245 100644 --- a/arch/arm/configs/vendor/sdm429-bg_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg_defconfig @@ -521,6 +521,7 @@ CONFIG_USB_BAM=y CONFIG_QCOM_CLK_SMD_RPM=y CONFIG_SDM_GCC_429W=y CONFIG_SDM_DEBUGCC_429W=y +CONFIG_CLOCK_CPU_SDM=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y -- GitLab From 4d51b7c37e9fdd619e7e38ac0ac5412fb1e51e79 Mon Sep 17 00:00:00 2001 From: Saurabh Sahu Date: Fri, 19 Jun 2020 13:01:26 +0530 Subject: [PATCH 1005/1055] clk: qcom: cpu-sdm: Add spm control support Add SPM ctrl support for cpu clocks for SDM targets. Change-Id: I56b43ab325f3e994077e8285b967087ff46ef5d5 Signed-off-by: Saurabh Sahu --- drivers/clk/qcom/clk-cpu-sdm.c | 105 +++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/drivers/clk/qcom/clk-cpu-sdm.c b/drivers/clk/qcom/clk-cpu-sdm.c index c1a00aab2a01..d3d47609e8db 100644 --- a/drivers/clk/qcom/clk-cpu-sdm.c +++ b/drivers/clk/qcom/clk-cpu-sdm.c @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include "clk-pll.h" #include "clk-debug.h" @@ -40,6 +43,19 @@ enum apcs_mux_clk_parent { P_APCS_CPU_PLL, }; +struct pll_spm_ctrl { + u32 offset; + u32 force_event_offset; + u32 event_bit; + void __iomem *spm_base; +}; + +static struct pll_spm_ctrl apcs_pll_spm = { + .offset = 0x50, + .force_event_offset = 0x4, + .event_bit = 0x4, +}; + static const struct parent_map apcs_mux_clk_parent_map0[] = { { P_BI_TCXO_AO, 0 }, { P_GPLL0_AO_OUT_MAIN, 4 }, @@ -200,6 +216,49 @@ static u8 cpucc_clk_get_parent(struct clk_hw *hw) return clk_regmap_mux_div_ops.get_parent(hw); } +static void spm_event(struct pll_spm_ctrl *apcs_pll_spm, bool enable) +{ + void __iomem *base = apcs_pll_spm->spm_base; + u32 offset, force_event_offset, bit, val; + + if (!apcs_pll_spm) + return; + + offset = apcs_pll_spm->offset; + force_event_offset = apcs_pll_spm->force_event_offset; + bit = apcs_pll_spm->event_bit; + + if (enable) { + /* L2_SPM_FORCE_EVENT_EN */ + val = readl_relaxed(base + offset); + val |= BIT(bit); + writel_relaxed(val, (base + offset)); + /* Ensure that the write above goes through. */ + mb(); + + /* L2_SPM_FORCE_EVENT */ + val = readl_relaxed(base + offset + force_event_offset); + val |= BIT(bit); + writel_relaxed(val, (base + offset + force_event_offset)); + /* Ensure that the write above goes through. */ + mb(); + } else { + /* L2_SPM_FORCE_EVENT */ + val = readl_relaxed(base + offset + force_event_offset); + val &= ~BIT(bit); + writel_relaxed(val, (base + offset + force_event_offset)); + /* Ensure that the write above goes through. */ + mb(); + + /* L2_SPM_FORCE_EVENT_EN */ + val = readl_relaxed(base + offset); + val &= ~BIT(bit); + writel_relaxed(val, (base + offset)); + /* Ensure that the write above goes through. */ + mb(); + } +} + /* * We use the notifier function for switching to a temporary safe configuration * (mux and divider), while the APSS pll is reconfigured. @@ -215,6 +274,11 @@ static int cpucc_notifier_cb(struct notifier_block *nb, unsigned long event, case PRE_RATE_CHANGE: /* set the mux to safe source gpll0_ao_out & div */ ret = __mux_div_set_src_div(cpuclk, safe_src, 1); + spm_event(&apcs_pll_spm, true); + break; + case POST_RATE_CHANGE: + if (cpuclk->src != safe_src) + spm_event(&apcs_pll_spm, false); break; case ABORT_RATE_CHANGE: pr_err("Error in configuring PLL - stay at safe src only\n"); @@ -517,6 +581,30 @@ static void cpucc_clk_populate_opp_table(struct platform_device *pdev) cpucc_clk_print_opp_table(sdm_cpu); } +static int clock_pm_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + switch (event) { + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + clk_unprepare(apcs_mux_c1_clk.clkr.hw.clk); + clk_unprepare(apcs_mux_cci_clk.clkr.hw.clk); + break; + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + clk_prepare(apcs_mux_c1_clk.clkr.hw.clk); + clk_prepare(apcs_mux_cci_clk.clkr.hw.clk); + break; + default: + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block clock_pm_notifier = { + .notifier_call = clock_pm_event, +}; + static int cpucc_driver_probe(struct platform_device *pdev) { struct resource *res; @@ -638,6 +726,21 @@ static int cpucc_driver_probe(struct platform_device *pdev) return PTR_ERR(apcs_mux_cci_clk.clkr.regmap); } + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "spm_c1_base"); + if (res == NULL) { + dev_err(&pdev->dev, "Failed to get spm-c1 resources\n"); + return -EINVAL; + } + + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed to ioremap c1 spm registers\n"); + return -ENOMEM; + } + + apcs_pll_spm.spm_base = base; + /* Get speed bin information */ cpucc_clk_get_speed_bin(pdev, &speed_bin, &version); @@ -718,6 +821,8 @@ static int cpucc_driver_probe(struct platform_device *pdev) } put_online_cpus(); + register_pm_notifier(&clock_pm_notifier); + cpucc_clk_populate_opp_table(pdev); dev_info(dev, "CPU clock Driver probed successfully\n"); -- GitLab From 9231d59e035caea0fa33b5f22a8895687c3a3d7f Mon Sep 17 00:00:00 2001 From: Saurabh Sahu Date: Wed, 1 Jul 2020 15:44:35 +0530 Subject: [PATCH 1006/1055] ARM: dts: msm: Add SPM control for sdm429w Add SPM control register for SDM429W target. Change-Id: Id6256776f03d72d5afa640f7a795cfacbad41d29 Signed-off-by: Saurabh Sahu --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index f98189ea9676..6901989bf29c 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -347,9 +347,11 @@ reg = <0xb011050 0x8>, <0xb1d1050 0x8>, <0xB016000 0x34>, - <0x00a412c 0x8>; + <0x00a412c 0x8>, + <0x0b011200 0x100>; reg-names = "apcs-c1-rcg-base", - "apcs-cci-rcg-base", "apcs_pll", "efuse"; + "apcs-cci-rcg-base", "apcs_pll", "efuse", + "spm_c1_base"; clocks = <&rpmcc RPM_SMD_XO_A_CLK_SRC>, <&gcc GPLL0_AO_OUT_MAIN>; clock-names = "xo_ao", "gpll0_ao" ; -- GitLab From ba64d10283cd871117e730f7d781082676bd3b5c Mon Sep 17 00:00:00 2001 From: Ramachandran Venkataramani Date: Thu, 16 Apr 2020 14:19:44 -0700 Subject: [PATCH 1007/1055] ARM: dts: Enable HMP for SA8195, SA8155 and SA6155 VM Add HMP CPU data for SA8195, SA8155 and SA6155 VM. Change-Id: I497b243d00e1a5c8b51b7a36daa07f949162e23a Signed-off-by: subbaramaiah mandava Signed-off-by: Ramachandran Venkataramani Signed-off-by: Venkata Rao kakani --- arch/arm64/boot/dts/qcom/sa6155p-vm.dtsi | 100 +++++++++++++++++ arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dtsi | 2 + arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dtsi | 2 + arch/arm64/boot/dts/qcom/sa8155-vm.dtsi | 101 ++++++++++++++++++ arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dtsi | 1 + arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dtsi | 1 + arch/arm64/boot/dts/qcom/sa8195-vm.dtsi | 99 +++++++++++++++++ 7 files changed, 306 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sa6155p-vm.dtsi b/arch/arm64/boot/dts/qcom/sa6155p-vm.dtsi index 176c0e0f9d54..dba72305096d 100644 --- a/arch/arm64/boot/dts/qcom/sa6155p-vm.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155p-vm.dtsi @@ -23,6 +23,106 @@ qcom,msm-name = "SA6155P"; qcom,msm-id = <377 0x0>; + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + capacity-dmips-mhz = <1024>; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x1>; + capacity-dmips-mhz = <1024>; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + capacity-dmips-mhz = <347>; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + capacity-dmips-mhz = <347>; + }; + + CPU4: cpu@4 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x4>; + capacity-dmips-mhz = <347>; + }; + + CPU5: cpu@5 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x5>; + capacity-dmips-mhz = <347>; + }; + + CPU6: cpu@6 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x6>; + capacity-dmips-mhz = <347>; + }; + + CPU7: cpu@7 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x7>; + capacity-dmips-mhz = <347>; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU2>; + }; + + core1 { + cpu = <&CPU3>; + }; + + core2 { + cpu = <&CPU4>; + }; + + core3 { + cpu = <&CPU5>; + }; + + core4 { + cpu = <&CPU6>; + }; + + core5 { + cpu = <&CPU7>; + }; + }; + }; + }; + + aliases { pci-domain0 = &pcie0; /* PCIe0 domain */ }; diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dtsi index 81db0640bdec..d52ebe853116 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-la-mt.dtsi @@ -19,6 +19,8 @@ label = "pmem_shared_mem"; }; }; + + /delete-node/ cpus; }; &slpi_tlmm { diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dtsi index 6b13c11640df..c2ef8679006a 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-lv-mt.dtsi @@ -19,6 +19,8 @@ label = "pmem_shared_mem"; }; }; + + /delete-node/ cpus; }; &hab { diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi index 5689a863ec98..bc9d35160800 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm.dtsi @@ -16,6 +16,107 @@ qcom,msm-name = "SA8155 V2"; qcom,msm-id = <362 0x20000>; + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + capacity-dmips-mhz = <1024>; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x1>; + capacity-dmips-mhz = <902>; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + capacity-dmips-mhz = <902>; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + capacity-dmips-mhz = <902>; + }; + + CPU4: cpu@4 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x4>; + capacity-dmips-mhz = <320>; + }; + + CPU5: cpu@5 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x5>; + capacity-dmips-mhz = <320>; + }; + + CPU6: cpu@6 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x6>; + capacity-dmips-mhz = <320>; + }; + + CPU7: cpu@7 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x7>; + capacity-dmips-mhz = <320>; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU1>; + }; + + core1 { + cpu = <&CPU2>; + }; + + core2 { + cpu = <&CPU3>; + }; + }; + + cluster2 { + core0 { + cpu = <&CPU4>; + }; + + core1 { + cpu = <&CPU5>; + }; + + core2 { + cpu = <&CPU6>; + }; + + core3 { + cpu = <&CPU7>; + }; + }; + }; + }; + aliases { pci-domain0 = &pcie0; /* PCIe0 domain */ sdhc2 = &sdhc_2; /* SDC2 SD card slot */ diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dtsi b/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dtsi index 2ffc10c40925..49aa13c1e6c9 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-la-mt.dtsi @@ -19,6 +19,7 @@ }; }; + /delete-node/ cpus; }; &slpi_tlmm { diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dtsi b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dtsi index f55efa749ab1..074d40913c28 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-vm-lv-mt.dtsi @@ -19,6 +19,7 @@ }; }; + /delete-node/ cpus; }; &hab { diff --git a/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi b/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi index d79b893c40de..32e1be94cae5 100644 --- a/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195-vm.dtsi @@ -24,6 +24,105 @@ qcom,msm-name = "SA8195P"; qcom,msm-id = <405 0x20000>; + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x0>; + capacity-dmips-mhz = <1024>; + }; + + CPU1: cpu@1 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x1>; + capacity-dmips-mhz = <1024>; + }; + + CPU2: cpu@2 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x2>; + capacity-dmips-mhz = <1024>; + }; + + CPU3: cpu@3 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x3>; + capacity-dmips-mhz = <1024>; + }; + + CPU4: cpu@4 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x4>; + capacity-dmips-mhz = <306>; + }; + + CPU5: cpu@5 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x5>; + capacity-dmips-mhz = <306>; + }; + + CPU6: cpu@6 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x6>; + capacity-dmips-mhz = <306>; + }; + + CPU7: cpu@7 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x0 0x7>; + capacity-dmips-mhz = <306>; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + }; + + cluster2 { + core0 { + cpu = <&CPU4>; + }; + + core1 { + cpu = <&CPU5>; + }; + + core2 { + cpu = <&CPU6>; + }; + + core3 { + cpu = <&CPU7>; + }; + }; + }; + }; + aliases { sdhc2 = &sdhc_2; /* SDC2 SD Card slot */ }; -- GitLab From 9ea6c7f067f9c38bf3cf785cdfbfcff8babbbd66 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Thu, 2 Jul 2020 13:11:48 +0530 Subject: [PATCH 1008/1055] USB: pd: Restart host mode in high speed if no usb3 & dp concurrency It is required to restart usb host mode in high speed on platforms not supporting usb3 ss and DP concurrency. Hence add required support to restart host mode in high speed for those platforms, when dp is detected through discovery of svids. Change-Id: I1bbd9679b9354828d751ed74ef5d99cb8541e698 Signed-off-by: Vijayavardhan Vennapusa --- .../devicetree/bindings/usb/qpnp-pdphy.txt | 1 + drivers/usb/pd/policy_engine.c | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/qpnp-pdphy.txt b/Documentation/devicetree/bindings/usb/qpnp-pdphy.txt index ebbb6d5b4770..f741fafcb912 100644 --- a/Documentation/devicetree/bindings/usb/qpnp-pdphy.txt +++ b/Documentation/devicetree/bindings/usb/qpnp-pdphy.txt @@ -43,6 +43,7 @@ Optional properties: - qcom,default-sink-caps: List of 32-bit values representing the nominal sink capabilities in voltage (millivolts) and current (milliamps) pairs. +- qcom,no-usb3-dp-concurrency: If present, usb3 and dp concurrency is not supported. Example: qcom,qpnp-pdphy@1700 { diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index d24adaca9524..c929f3433997 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -388,6 +388,7 @@ struct usbpd { struct workqueue_struct *wq; struct work_struct sm_work; struct work_struct start_periph_work; + struct work_struct restart_host_work; struct hrtimer timer; bool sm_queued; @@ -415,6 +416,7 @@ struct usbpd { bool peer_usb_comm; bool peer_pr_swap; bool peer_dr_swap; + bool no_usb3dp_concurrency; u32 sink_caps[7]; int num_sink_caps; @@ -583,6 +585,26 @@ static void start_usb_peripheral_work(struct work_struct *w) dual_role_instance_changed(pd->dual_role); } +static void restart_usb_host_work(struct work_struct *w) +{ + struct usbpd *pd = container_of(w, struct usbpd, restart_host_work); + int ret; + + if (!pd->no_usb3dp_concurrency) + return; + + stop_usb_host(pd); + + /* blocks until USB host is completely stopped */ + ret = extcon_blocking_sync(pd->extcon, EXTCON_USB_HOST, 0); + if (ret) { + usbpd_err(&pd->dev, "err(%d) stopping host", ret); + return; + } + + start_usb_host(pd, false); +} + /** * This API allows client driver to request for releasing SS lanes. It should * not be called from atomic context. @@ -1889,6 +1911,7 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) /* Set to USB and DP cocurrency mode */ extcon_blocking_sync(pd->extcon, EXTCON_DISP_DP, 2); + queue_work(pd->wq, &pd->restart_host_work); } /* if it's a supported SVID, pass the message to the handler */ @@ -4526,6 +4549,7 @@ struct usbpd *usbpd_create(struct device *parent) } INIT_WORK(&pd->sm_work, usbpd_sm); INIT_WORK(&pd->start_periph_work, start_usb_peripheral_work); + INIT_WORK(&pd->restart_host_work, restart_usb_host_work); hrtimer_init(&pd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); pd->timer.function = pd_timeout; mutex_init(&pd->swap_lock); @@ -4619,6 +4643,8 @@ struct usbpd *usbpd_create(struct device *parent) pd->num_sink_caps = ARRAY_SIZE(default_snk_caps); } + if (device_property_read_bool(parent, "qcom,no-usb3-dp-concurrency")) + pd->no_usb3dp_concurrency = true; /* * Register the Android dual-role class (/sys/class/dual_role_usb/). * The first instance should be named "otg_default" as that's what -- GitLab From c03debd811de09e10ef7fd4d15c9f7bf13992aa0 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Thu, 2 Jul 2020 13:20:16 +0530 Subject: [PATCH 1009/1055] ARM: msm: dts: Enable restarting usb host mode in HS for SDM660 Enable support for restarting usb host mode in high speed when dp is detected for sdm660. Change-Id: I61fb48f69ae6f7efcce5e58b36d48b9c2a59ef09 Signed-off-by: Vijayavardhan Vennapusa --- arch/arm64/boot/dts/qcom/pm660.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/pm660.dtsi b/arch/arm64/boot/dts/qcom/pm660.dtsi index 2f7f6488d328..7ebb230eb269 100644 --- a/arch/arm64/boot/dts/qcom/pm660.dtsi +++ b/arch/arm64/boot/dts/qcom/pm660.dtsi @@ -365,6 +365,7 @@ qcom,default-sink-caps = <5000 3000>, /* 5V @ 3A */ <9000 3000>; /* 9V @ 3A */ + qcom,no-usb3-dp-concurrency; }; pm660_adc_tm: vadc@3400 { -- GitLab From b0d52fda338b056d25c9bededb254c0a519cecc2 Mon Sep 17 00:00:00 2001 From: Saurabh Sahu Date: Fri, 3 Jul 2020 12:15:51 +0530 Subject: [PATCH 1010/1055] clk: qcom: smd_rpm: Add bb_clk_pin for SDM429 Add bb_clk1_pin and bb_clk2_pin in rpmcc for SDM429. Change-Id: I476186b4bb3b33c8c3965b768d308752860e8297 Signed-off-by: Saurabh Sahu --- drivers/clk/qcom/clk-smd-rpm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index 96e09c8ab74f..895ee8f81eff 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -1038,6 +1038,10 @@ static struct clk_hw *sdm429w_clks[] = { [RPM_SMD_BB_CLK1_A] = &sdm429w_bb_clk1_a.hw, [RPM_SMD_BB_CLK2] = &sdm429w_bb_clk2.hw, [RPM_SMD_BB_CLK2_A] = &sdm429w_bb_clk2_a.hw, + [RPM_SMD_BB_CLK1_PIN] = &sdm429w_bb_clk1_pin.hw, + [RPM_SMD_BB_CLK1_A_PIN] = &sdm429w_bb_clk1_a_pin.hw, + [RPM_SMD_BB_CLK2_PIN] = &sdm429w_bb_clk2_pin.hw, + [RPM_SMD_BB_CLK2_A_PIN] = &sdm429w_bb_clk2_a_pin.hw, [RPM_SMD_RF_CLK2] = &sdm429w_rf_clk2.hw, [RPM_SMD_RF_CLK2_A] = &sdm429w_rf_clk2_a.hw, [RPM_SMD_DIV_CLK2] = &sdm429w_div_clk2.hw, -- GitLab From 3b4cd9f2f8b91909635abe7e3aa074e4f6c56cfc Mon Sep 17 00:00:00 2001 From: Tapas Dey Date: Fri, 3 Jul 2020 18:16:05 +0530 Subject: [PATCH 1011/1055] ARM: dts: Add NFC device node for SDM429W Device node changes required on SDM429W describing the GPIO configuration for Nfc controller chip. Modified corresponding Nfc device node for internal platforms. Change-Id: I8a2044359b9c817faec2922540727a2accb8df9c Signed-off-by: Tapas Dey --- .../dts/qcom/sda429-bg-dvt2-wtp-overlay.dts | 1 + .../boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi | 37 +++++++++++ .../boot/dts/qcom/sda429-wtp-overlay.dts | 1 + arch/arm64/boot/dts/qcom/sda429-wtp.dtsi | 37 +++++++++++ .../dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts | 1 + .../boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi | 37 +++++++++++ arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi | 65 +++++++++++++++++++ .../boot/dts/qcom/sdm429-wtp-overlay.dts | 1 + arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi | 37 +++++++++++ 9 files changed, 217 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts index 898355091fdb..99ef807a633b 100644 --- a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts @@ -14,6 +14,7 @@ /dts-v1/; /plugin/; +#include #include "sda429-bg-dvt2-wtp.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi index a1160641d216..94c407eefe06 100644 --- a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp.dtsi @@ -52,3 +52,40 @@ status = "disabled"; }; +&pm660_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio4"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 93 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&rpmcc RPM_SMD_BB_CLK2_PIN>; + clock-names = "ref_clk"; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts index 138cb9e93292..cda6c267acf8 100644 --- a/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts @@ -14,6 +14,7 @@ /dts-v1/; /plugin/; +#include #include "sda429-wtp.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sda429-wtp.dtsi b/arch/arm64/boot/dts/qcom/sda429-wtp.dtsi index a1160641d216..94c407eefe06 100644 --- a/arch/arm64/boot/dts/qcom/sda429-wtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sda429-wtp.dtsi @@ -52,3 +52,40 @@ status = "disabled"; }; +&pm660_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio4"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 93 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&rpmcc RPM_SMD_BB_CLK2_PIN>; + clock-names = "ref_clk"; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts index 6f5cd9c5b07d..d1879d73f0ef 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts @@ -14,6 +14,7 @@ /dts-v1/; /plugin/; +#include #include "sdm429-bg-dvt2-wtp.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi index a1160641d216..94c407eefe06 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp.dtsi @@ -52,3 +52,40 @@ status = "disabled"; }; +&pm660_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio4"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 93 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&rpmcc RPM_SMD_BB_CLK2_PIN>; + clock-names = "ref_clk"; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi index 292a515a9982..d78b1399d4f0 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi @@ -352,6 +352,71 @@ }; }; + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 17 NFC Read Interrupt */ + pins = "gpio17"; + function = "gpio"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 17 NFC Read Interrupt */ + pins = "gpio17"; + function = "gpio"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_disable_active: nfc_disable_active { + /* active state */ + mux { + /* 16: NFC ENABLE 130: FW DNLD */ + /* 93: ESE Enable */ + pins = "gpio16", "gpio130", "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio16", "gpio130", "gpio93"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_disable_suspend: nfc_disable_suspend { + /* sleep state */ + mux { + /* 16: NFC ENABLE 130: FW DNLD */ + /* 93: ESE Enable */ + pins = "gpio16", "gpio130", "gpio93"; + function = "gpio"; + }; + + config { + pins = "gpio16", "gpio130", "gpio93"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + }; + + i2c_6{ i2c_6_active: i2c_6_active { mux { diff --git a/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts index 403d0b7911af..1fce325544bc 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts @@ -14,6 +14,7 @@ /dts-v1/; /plugin/; +#include #include "sdm429-wtp.dtsi" #include "sdm429-mdss-panels.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi index a1160641d216..94c407eefe06 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-wtp.dtsi @@ -52,3 +52,40 @@ status = "disabled"; }; +&pm660_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio4"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + #address-cells = <1>; + #size-cells = <0>; + + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm660_gpios 4 0x00>; + qcom,nq-esepwr = <&tlmm 93 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&rpmcc RPM_SMD_BB_CLK2_PIN>; + clock-names = "ref_clk"; + }; +}; + -- GitLab From 5a3cc4aeecd0414dce44e33fa6a067fd34a735d8 Mon Sep 17 00:00:00 2001 From: Ashish Kori Date: Mon, 22 Jun 2020 12:54:01 +0530 Subject: [PATCH 1012/1055] spi: spi-geni-qcom: Don't initialize GSI channels for FIFO/SE_DMA mode Don't initialize GSI channels for FIFO/SE_DMA mode in SPI driver. Change-Id: I600cb1a522a09c4e9cd2ee1cad3d3f6d4c66a358 Signed-off-by: Ashish Kori --- drivers/spi/spi-geni-qcom.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 27aebbc4d5c4..5da71321da63 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -938,16 +938,24 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi) /* Transmit an entire FIFO worth of data per IRQ */ mas->tx_wm = 1; - mas->tx = dma_request_slave_channel(mas->dev, "tx"); - if (IS_ERR_OR_NULL(mas->tx)) { - dev_info(mas->dev, "Failed to get tx DMA ch %ld", + + mas->shared_se = + (geni_read_reg(mas->base, GENI_IF_FIFO_DISABLE_RO) & + FIFO_IF_DISABLE); + if (mas->shared_se) { + mas->tx = dma_request_slave_channel(mas->dev, "tx"); + if (IS_ERR_OR_NULL(mas->tx)) { + dev_info(mas->dev, + "Failed to get tx DMA ch %ld", PTR_ERR(mas->tx)); - } else { + goto setup_ipc; + } mas->rx = dma_request_slave_channel(mas->dev, "rx"); if (IS_ERR_OR_NULL(mas->rx)) { dev_info(mas->dev, "Failed to get rx DMA ch %ld", PTR_ERR(mas->rx)); dma_release_channel(mas->tx); + goto setup_ipc; } mas->gsi = devm_kzalloc(mas->dev, (sizeof(struct spi_geni_gsi) * NUM_SPI_XFER), @@ -1006,9 +1014,6 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi) "%s:Major:%d Minor:%d step:%dos%d\n", __func__, major, minor, step, mas->oversampling); } - mas->shared_se = - (geni_read_reg(mas->base, GENI_IF_FIFO_DISABLE_RO) & - FIFO_IF_DISABLE); if (mas->dis_autosuspend) GENI_SE_DBG(mas->ipc, false, mas->dev, "Auto Suspend is disabled\n"); -- GitLab From eddfa526866b789f12d9bbd9d527af8fa5c3818b Mon Sep 17 00:00:00 2001 From: Venkata Prahlad Valluru Date: Thu, 2 Jul 2020 15:44:43 +0530 Subject: [PATCH 1013/1055] defconfig: sdm429: add display configs Add MDSS fb configs and remove sde related configs. Also add dependent configs. Change-Id: Ica1a49e52308c18611ffd37011ef8c42f1f0abd4 Signed-off-by: Venkata Prahlad Valluru --- arch/arm/configs/vendor/sdm429-bg-perf_defconfig | 15 +++++++++------ arch/arm/configs/vendor/sdm429-bg_defconfig | 15 +++++++++------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig index b5270ed9de47..bca4372cddfe 100644 --- a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig @@ -368,6 +368,7 @@ CONFIG_QTI_ADC_TM=y CONFIG_QTI_CX_IPEAK_COOLING_DEVICE=y CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_CPR=y @@ -414,17 +415,16 @@ CONFIG_MSM_FD=y CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y -CONFIG_MSM_SDE_ROTATOR=y -CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_DVB_MPQ=m CONFIG_DVB_MPQ_DEMUX=m CONFIG_DVB_MPQ_SW=y -CONFIG_DRM=y -CONFIG_DRM_MSM_REGISTER_LOGGING=y -CONFIG_DRM_SDE_EVTLOG_DEBUG=y -CONFIG_DRM_SDE_RSC=y +CONFIG_FB=y CONFIG_FB_ARMCLCD=y CONFIG_FB_VIRTUAL=y +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set # CONFIG_LOGO_LINUX_VGA16 is not set @@ -496,6 +496,7 @@ CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_ION=y +CONFIG_MSM_EXT_DISPLAY=y CONFIG_QPNP_REVID=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y @@ -525,6 +526,7 @@ CONFIG_QCOM_SMEM=y CONFIG_QCOM_SMD_RPM=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y +CONFIG_QCOM_SCM=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y @@ -601,6 +603,7 @@ CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y diff --git a/arch/arm/configs/vendor/sdm429-bg_defconfig b/arch/arm/configs/vendor/sdm429-bg_defconfig index 8e0eb0c080a2..1d7eae45e5a5 100644 --- a/arch/arm/configs/vendor/sdm429-bg_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg_defconfig @@ -379,6 +379,7 @@ CONFIG_QTI_ADC_TM=y CONFIG_QTI_CX_IPEAK_COOLING_DEVICE=y CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PROXY_CONSUMER=y CONFIG_REGULATOR_CPR=y @@ -425,16 +426,14 @@ CONFIG_MSM_FD=y CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y -CONFIG_MSM_SDE_ROTATOR=y -CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_DVB_MPQ=m CONFIG_DVB_MPQ_DEMUX=m CONFIG_DVB_MPQ_SW=y -CONFIG_DRM=y -CONFIG_DRM_MSM_REGISTER_LOGGING=y -CONFIG_DRM_SDE_EVTLOG_DEBUG=y -CONFIG_DRM_SDE_RSC=y +CONFIG_FB=y CONFIG_FB_VIRTUAL=y +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_LOGO=y @@ -514,10 +513,12 @@ CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_ION=y +CONFIG_MSM_EXT_DISPLAY=y CONFIG_QPNP_REVID=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_USB_BAM=y +CONFIG_QCOM_MDSS_PLL=y CONFIG_QCOM_CLK_SMD_RPM=y CONFIG_SDM_GCC_429W=y CONFIG_SDM_DEBUGCC_429W=y @@ -543,6 +544,7 @@ CONFIG_QCOM_SMEM=y CONFIG_QCOM_SMD_RPM=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y +CONFIG_QCOM_SCM=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y @@ -625,6 +627,7 @@ CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_ECRYPT_FS=y CONFIG_ECRYPT_FS_MESSAGING=y -- GitLab From 8cc62eca265c0754c36199932e9f1b2f18bf75af Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Fri, 8 May 2020 10:40:43 +0800 Subject: [PATCH 1014/1055] tmc-etr: Add ETR status check in usb_notifier It is possible that notify call is called after etr is disabled or after mode switch from usb to etr. Add etr status check to avoid exception. Change-Id: I4feb36df28b6fc059598af98b6fb9ccf698d3aaf Signed-off-by: Mao Jinlong --- drivers/hwtracing/coresight/coresight-tmc-etr.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-tmc-etr.c b/drivers/hwtracing/coresight/coresight-tmc-etr.c index 745fcaad4348..7f830f41e8c6 100644 --- a/drivers/hwtracing/coresight/coresight-tmc-etr.c +++ b/drivers/hwtracing/coresight/coresight-tmc-etr.c @@ -1340,6 +1340,14 @@ void usb_notifier(void *priv, unsigned int event, struct qdss_request *d_req, int ret = 0; mutex_lock(&drvdata->mem_lock); + if (drvdata->out_mode != TMC_ETR_OUT_MODE_USB + || drvdata->mode == CS_MODE_DISABLED) { + dev_err(&drvdata->csdev->dev, + "%s: ETR is not USB mode, or ETR is disabled.\n", __func__); + mutex_unlock(&drvdata->mem_lock); + return; + } + if (event == USB_QDSS_CONNECT) { ret = tmc_etr_fill_usb_bam_data(drvdata); if (ret) -- GitLab From 7dcfe5a81e1562b78a67b33b431072dd0d5c7cd4 Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Fri, 8 May 2020 12:51:06 +0530 Subject: [PATCH 1015/1055] rpmsg: Add glink-bgcom driver for rpmsg framework Add glink-bgcom driver which relies on bgcom as a transport layer for sending data between various sub systems. Add documentation file for the glink-bgcom driver. Change-Id: I5eee03e6347a661dcefd083cea738b5d35fca848 Signed-off-by: Prudhvi Yarlagadda --- .../soc/qcom/qcom,glink-bgcom-xprt.txt | 24 + drivers/rpmsg/Kconfig | 9 + drivers/rpmsg/Makefile | 1 + drivers/rpmsg/qcom_glink_bgcom.c | 2264 +++++++++++++++++ drivers/soc/qcom/Kconfig | 2 +- 5 files changed, 2299 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,glink-bgcom-xprt.txt create mode 100644 drivers/rpmsg/qcom_glink_bgcom.c diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,glink-bgcom-xprt.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,glink-bgcom-xprt.txt new file mode 100644 index 000000000000..c6e46f38e4e7 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,glink-bgcom-xprt.txt @@ -0,0 +1,24 @@ +Qualcomm Technologies, Inc GLINK BGCOM transport (glink_bgcom_xprt) binding + +This binding describes the Qualcomm Technologies, Inc glink bgcom transport +driver, a bgcom-spi based communication channel for sending data between the +various subsystems in Qualcomm Technologies, Inc platforms. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,glink-bgcom-xprt" + +- label: + Usage: required + Value type: + Definition: must be "bg" + += EXAMPLE + +The following example reprsents a glink_bgcom node. + + qcom,glink-bgcom-xprt-bg { + compatible = "qcom,glink-bgcom-xprt"; + label = "bg"; + }; diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig index 36d3443af640..02d3560b1d1f 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig @@ -59,6 +59,15 @@ config RPMSG_QCOM_GLINK_SPI data to the appropriate SPI bus wire format and allows for GLINK communication with remote subsystems that are external to the SoC. +config RPMSG_QCOM_GLINK_BGCOM + tristate "Qualcomm Technologies, Inc. BGCOM Glink driver" + help + Say y here to enable support for the GLINK BGCOM driver, + which provides support for using the GLINK communication protocol + over BGCOM. This transport performs marshaling of GLINK commands and + data to the appropriate BGCOM format and allows for GLINK + communication with remote subsystems that are external to the SoC. + config RPMSG_QCOM_SMD tristate "Qualcomm Shared Memory Driver (SMD)" depends on QCOM_SMEM diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile index 131052abeaf5..53583a28cb05 100644 --- a/drivers/rpmsg/Makefile +++ b/drivers/rpmsg/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o obj-$(CONFIG_RPMSG_QCOM_GLINK_SPSS) += qcom_glink_spss.o obj-$(CONFIG_RPMSG_QCOM_GLINK_SPI) += qcom_glink_spi.o +obj-$(CONFIG_RPMSG_QCOM_GLINK_BGCOM) += qcom_glink_bgcom.o obj-$(CONFIG_RPMSG_QCOM_SMD) += qcom_smd.o obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o diff --git a/drivers/rpmsg/qcom_glink_bgcom.c b/drivers/rpmsg/qcom_glink_bgcom.c new file mode 100644 index 000000000000..74bf2e54dbba --- /dev/null +++ b/drivers/rpmsg/qcom_glink_bgcom.c @@ -0,0 +1,2264 @@ +/* Copyright (c) 2020, 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 +#include +#include +#include +#include +#include +#include +#include +#include "../soc/qcom/bgcom.h" + +#include + +#include "rpmsg_internal.h" +#include "qcom_glink_native.h" + +#define GLINK_LOG_PAGE_CNT 2 +#define GLINK_INFO(ctxt, x, ...) \ +do { \ + if (ctxt->ilc) \ + ipc_log_string(ctxt->ilc, "[%s]: "x, __func__, ##__VA_ARGS__); \ +} while (0) + +#define CH_INFO(ch, x, ...) \ +do { \ + if (ch->glink && ch->glink->ilc) \ + ipc_log_string(ch->glink->ilc, "%s[%d:%d] %s: "x, ch->name, \ + ch->lcid, ch->rcid, __func__, ##__VA_ARGS__); \ +} while (0) + + +#define GLINK_ERR(ctxt, x, ...) \ +do { \ + pr_err_ratelimited("[%s]: "x, __func__, ##__VA_ARGS__); \ + if (ctxt->ilc) \ + ipc_log_string(ctxt->ilc, "[%s]: "x, __func__, ##__VA_ARGS__); \ +} while (0) + +#define BGCOM_ALIGNMENT 16 +#define TX_BLOCKED_CMD_RESERVE 16 +#define DEFAULT_FIFO_SIZE 1024 +#define SHORT_SIZE 16 +#define XPRT_ALIGNMENT 4 + +#define ACTIVE_TX BIT(0) +#define ACTIVE_RX BIT(1) + +#define ID_MASK 0xFFFFFF + +#define GLINK_NAME_SIZE 32 +#define GLINK_VERSION_1 1 + +#define BGCOM_GLINK_CID_MIN 1 +#define BGCOM_GLINK_CID_MAX 65536 + +#define TX_WAIT_US 500 +#define BGCOM_RESET 0x00000000 +#define BGCOM_APPLICATION_RUNNING 0x00000001 +#define BGCOM_TO_SLAVE_FIFO_READY 0x00000002 +#define BGCOM_TO_MASTER_FIFO_READY 0x00000004 +#define BGCOM_AHB_READY 0x00000008 +#define WORD_SIZE 4 +#define TX_BLOCKED_CMD_RESERVE 16 +#define FIFO_FULL_RESERVE (TX_BLOCKED_CMD_RESERVE/WORD_SIZE) +#define BGCOM_LINKUP (BGCOM_APPLICATION_RUNNING \ + | BGCOM_TO_SLAVE_FIFO_READY \ + | BGCOM_TO_MASTER_FIFO_READY \ + | BGCOM_AHB_READY) + +struct glink_bgcom_msg { + __le16 cmd; + __le16 param1; + __le32 param2; + __le32 param3; + __le32 param4; + u8 data[]; +} __packed; + +/** + * struct glink_bgcom_defer_cmd - deferred incoming control message + * @node: list node + * @msg: message header + * data: payload of the message + * + * Copy of a received control message, to be added to @rx_queue and processed + * by @rx_work of @glink_bgcom. + */ +struct glink_bgcom_defer_cmd { + struct list_head node; + + struct glink_bgcom_msg msg; + u8 data[]; +}; + +/** + * struct glink_bgcom_rx_intent - RX intent + * RX intent + * + * @data: pointer to the data (may be NULL for zero-copy) + * @id: remote or local intent ID + * @size: size of the original intent (do not modify) + * @addr: addr to read/write the data from + * @reuse: To mark if the intent can be reused after first use + * @in_use: To mark if intent is already in use for the channel + * @offset: next write offset (initially 0) + */ +struct glink_bgcom_rx_intent { + void *data; + u32 id; + size_t size; + u32 addr; + bool reuse; + bool in_use; + u32 offset; + + struct list_head node; +}; + +struct bgcom_fifo_size { + uint32_t to_master:16; + uint32_t to_slave:16; +}; + +struct bgcom_fifo_fill { + uint32_t rx_avail:16; + uint32_t tx_avail:16; +}; + +/** + * struct glink_bgcom - driver context, relates to one remote subsystem + * @dev: reference to the associated struct device + * @name: name of this edge + * @rx_pipe: pipe object for receive FIFO + * @rx_worker: worker struct for handling received control messages + * @rx_task: task that runs the rx_worker + * @rx_lock: protects the @rx_queue + * @rx_queue: queue of received control messages to be processed in @rx_work + * @tx_lock: synchronizes operations on the tx fifo + * @idr_lock: synchronizes @lcids and @rcids modifications + * @lcids: idr of all channels with a known local channel id + * @rcids: idr of all channels with a known remote channel id + * @spi_ops: spi ops for sending data to the remote + * @cmpnt: component to be registered with the wdsp component manager + * @in_reset indicates that remote processor is in reset + * @ilc: ipc logging context reference + * @sent_read_notify: flag to check cmd sent or not + */ +struct glink_bgcom { + struct device *dev; + + const char *name; + + struct kthread_worker rx_worker; + struct task_struct *rx_task; + + spinlock_t rx_lock; + struct list_head rx_queue; + struct work_struct rx_defer_work; + + struct mutex tx_lock; + + struct mutex idr_lock; + struct idr lcids; + struct idr rcids; + u32 features; + + atomic_t activity_cnt; + atomic_t in_reset; + + void *ilc; + bool sent_read_notify; + + struct bgcom_fifo_fill fifo_fill; + struct bgcom_fifo_size fifo_size; + struct mutex tx_avail_lock; + struct kthread_worker kworker; + + uint32_t bgcom_status; + struct bgcom_open_config_type bgcom_config; + void *bgcom_handle; + bool water_mark_reached; +}; + +enum { + GLINK_STATE_CLOSED, + GLINK_STATE_OPENING, + GLINK_STATE_OPEN, + GLINK_STATE_CLOSING, +}; + +/** + * struct glink_bgcom_channel - internal representation of a channel + * @rpdev: rpdev reference, only used for primary endpoints + * @ept: rpmsg endpoint this channel is associated with + * @glink: glink_bgcom context handle + * @refcount: refcount for the channel object + * @recv_lock: guard for @ept.cb + * @name: unique channel name/identifier + * @lcid: channel id, in local space + * @rcid: channel id, in remote space + * @intent_lock: lock for protection of @liids, @riids + * @liids: idr of all local intents + * @riids: idr of all remote intents + * @open_ack: completed once remote has acked the open-request + * @open_req: completed once open-request has been received + * @intent_req_lock: Synchronises multiple intent requests + * @intent_req_result: Result of intent request + * @intent_req_comp: Completion for intent_req signalling + */ +struct glink_bgcom_channel { + struct rpmsg_endpoint ept; + + struct rpmsg_device *rpdev; + struct glink_bgcom *glink; + + struct kref refcount; + + spinlock_t recv_lock; + + char *name; + unsigned int lcid; + unsigned int rcid; + + struct mutex intent_lock; + struct idr liids; + struct idr riids; + + unsigned int lsigs; + unsigned int rsigs; + + struct completion open_ack; + struct completion open_req; + + struct mutex intent_req_lock; + bool intent_req_result; + struct completion intent_req_comp; +}; + +struct rx_pkt { + void *rx_buf; + uint32_t rx_len; + struct glink_bgcom *glink; + struct kthread_work kwork; +}; + +#define to_glink_channel(_ept) container_of(_ept, \ + struct glink_bgcom_channel, ept) + +static const struct rpmsg_endpoint_ops glink_endpoint_ops; + +#define BGCOM_CMD_VERSION 0 +#define BGCOM_CMD_VERSION_ACK 1 +#define BGCOM_CMD_OPEN 2 +#define BGCOM_CMD_CLOSE 3 +#define BGCOM_CMD_OPEN_ACK 4 +#define BGCOM_CMD_CLOSE_ACK 5 +#define BGCOM_CMD_INTENT 6 +#define BGCOM_CMD_RX_DONE 7 +#define BGCOM_CMD_RX_DONE_W_REUSE 8 +#define BGCOM_CMD_RX_INTENT_REQ 9 +#define BGCOM_CMD_RX_INTENT_REQ_ACK 10 +#define BGCOM_CMD_TX_DATA 11 +#define BGCOM_CMD_TX_DATA_CONT 12 +#define BGCOM_CMD_READ_NOTIF 13 +#define BGCOM_CMD_SIGNALS 14 +#define BGCOM_CMD_TX_SHORT_DATA 17 + +static struct glink_bgcom_channel * +glink_bgcom_alloc_channel(struct glink_bgcom *glink, const char *name) +{ + struct glink_bgcom_channel *channel; + + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) + return ERR_PTR(-ENOMEM); + + /* Setup glink internal glink_spi_channel data */ + spin_lock_init(&channel->recv_lock); + mutex_init(&channel->intent_lock); + mutex_init(&channel->intent_req_lock); + + channel->glink = glink; + channel->name = kstrdup(name, GFP_KERNEL); + + init_completion(&channel->open_req); + init_completion(&channel->open_ack); + init_completion(&channel->intent_req_comp); + + idr_init(&channel->liids); + idr_init(&channel->riids); + kref_init(&channel->refcount); + + return channel; +} + +static void glink_bgcom_channel_release(struct kref *ref) +{ + struct glink_bgcom_channel *channel; + struct glink_bgcom_rx_intent *tmp; + int iid; + + channel = container_of(ref, struct glink_bgcom_channel, refcount); + CH_INFO(channel, "\n"); + + channel->intent_req_result = 0; + complete(&channel->intent_req_comp); + + mutex_lock(&channel->intent_lock); + idr_for_each_entry(&channel->liids, tmp, iid) { + kfree(tmp->data); + kfree(tmp); + } + idr_destroy(&channel->liids); + + idr_for_each_entry(&channel->riids, tmp, iid) + kfree(tmp); + idr_destroy(&channel->riids); + mutex_unlock(&channel->intent_lock); + + kfree(channel->name); + kfree(channel); +} + +static struct glink_bgcom_rx_intent * +glink_bgcom_alloc_intent(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel, + size_t size, + bool reuseable) +{ + struct glink_bgcom_rx_intent *intent; + int ret; + + intent = kzalloc(sizeof(*intent), GFP_KERNEL); + if (!intent) + return NULL; + + intent->data = kzalloc(size, GFP_KERNEL); + if (!intent->data) + goto free_intent; + + mutex_lock(&channel->intent_lock); + ret = idr_alloc_cyclic(&channel->liids, intent, 1, -1, GFP_ATOMIC); + if (ret < 0) { + mutex_unlock(&channel->intent_lock); + goto free_data; + } + mutex_unlock(&channel->intent_lock); + + intent->id = ret; + intent->size = size; + intent->reuse = reuseable; + + return intent; + +free_data: + kfree(intent->data); +free_intent: + kfree(intent); + return NULL; +} + +/** + * tx_wakeup_worker() - worker function to wakeup tx blocked thread + * @work: kwork associated with the edge to process commands on. + */ +static void tx_wakeup_worker(struct glink_bgcom *glink) +{ + struct bgcom_fifo_fill fifo_fill; + + mutex_lock(&glink->tx_avail_lock); + bgcom_reg_read(glink->bgcom_handle, BGCOM_REG_FIFO_FILL, 1, + &fifo_fill); + glink->fifo_fill.tx_avail = fifo_fill.tx_avail; + if (glink->fifo_fill.tx_avail > glink->fifo_size.to_slave/2) + glink->water_mark_reached = false; + mutex_unlock(&glink->tx_avail_lock); + + if (atomic_read(&glink->in_reset)) + return; +} + +static void glink_bgcom_update_tx_avail(struct glink_bgcom *glink, + uint32_t size) +{ + mutex_lock(&glink->tx_avail_lock); + glink->fifo_fill.tx_avail -= size; + if (glink->fifo_fill.tx_avail < glink->fifo_size.to_slave/2) + glink->water_mark_reached = true; + mutex_unlock(&glink->tx_avail_lock); +} + +size_t glink_bgcom_tx_avail(struct glink_bgcom *glink) +{ + u32 tx_avail; + + mutex_lock(&glink->tx_avail_lock); + tx_avail = glink->fifo_fill.tx_avail; + if (tx_avail < FIFO_FULL_RESERVE) + tx_avail = 0; + else + tx_avail -= FIFO_FULL_RESERVE; + + mutex_unlock(&glink->tx_avail_lock); + return tx_avail; +} + +static int glink_bgcom_tx_write_one(struct glink_bgcom *glink, void *src, + uint32_t size) +{ + u32 tx_avail = glink_bgcom_tx_avail(glink); + int ret; + uint32_t size_in_words = size/WORD_SIZE; + + if (size_in_words > tx_avail) { + GLINK_ERR(glink, "%s: No Space in Fifo\n", __func__); + return -ENOSPC; + } + + ret = bgcom_fifo_write(glink->bgcom_handle, size_in_words, src); + if (ret < 0) { + GLINK_ERR(glink, "%s: Error %d writing data\n", + __func__, ret); + return ret; + } + + glink_bgcom_update_tx_avail(glink, size_in_words); + return ret; +} + +static void glink_bgcom_tx_write(struct glink_bgcom *glink, + void *data, size_t dlen) +{ + int ret; + + if (dlen) { + ret = glink_bgcom_tx_write_one(glink, data, dlen); + if (ret < 0) + GLINK_ERR(glink, "Error %d writing tx data\n", ret); + } +} + +static void glink_bgcom_send_read_notify(struct glink_bgcom *glink) +{ + struct glink_bgcom_msg msg = { 0 }; + int ret; + + msg.cmd = cpu_to_le16(BGCOM_CMD_READ_NOTIF); + msg.param1 = 0; + msg.param2 = 0; + + GLINK_INFO(glink, "Cmd size in words = %d\n", sizeof(msg)/WORD_SIZE); + + ret = bgcom_fifo_write(glink->bgcom_handle, sizeof(msg)/WORD_SIZE, + &msg); + if (ret < 0) { + GLINK_ERR(glink, "%s: Error %d writing data\n", + __func__, ret); + return; + } + + glink_bgcom_update_tx_avail(glink, sizeof(msg)/WORD_SIZE); +} + +static int glink_bgcom_tx(struct glink_bgcom *glink, void *data, + size_t dlen, bool wait) +{ + int ret = 0; + + mutex_lock(&glink->tx_lock); + + while (glink_bgcom_tx_avail(glink) < dlen/WORD_SIZE) { + if (!wait) { + ret = -EAGAIN; + goto out; + } + + if (atomic_read(&glink->in_reset)) { + ret = -ENXIO; + goto out; + } + + if (!glink->sent_read_notify) { + glink->sent_read_notify = true; + glink_bgcom_send_read_notify(glink); + } + /* Wait without holding the tx_lock */ + mutex_unlock(&glink->tx_lock); + + usleep_range(TX_WAIT_US, TX_WAIT_US + 50); + + mutex_lock(&glink->tx_lock); + + if (glink_bgcom_tx_avail(glink) >= dlen/WORD_SIZE) + glink->sent_read_notify = false; + } + + glink_bgcom_tx_write(glink, data, dlen); + +out: + mutex_unlock(&glink->tx_lock); + + return ret; +} + +/** + * glink_bgcom_send_intent_req_ack() - convert an rx intent request ack cmd to + wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @granted: The request response to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int glink_bgcom_send_intent_req_ack(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel, + bool granted) +{ + struct glink_bgcom_msg msg = { 0 }; + + msg.cmd = cpu_to_le16(BGCOM_CMD_RX_INTENT_REQ_ACK); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(granted); + + CH_INFO(channel, "\n"); + glink_bgcom_tx(glink, &msg, sizeof(msg), true); + + return 0; +} + +static int glink_bgcom_send_data(struct glink_bgcom_channel *channel, + void *data, int chunk_size, int left_size, + struct glink_bgcom_rx_intent *intent, bool wait) +{ + struct glink_bgcom *glink = channel->glink; + struct { + struct glink_bgcom_msg msg; + __le32 chunk_size; + __le32 left_size; + } __packed req; + + CH_INFO(channel, "chunk:%d, left:%d\n", chunk_size, left_size); + + memset(&req, 0, sizeof(req)); + if (intent->offset) + req.msg.cmd = cpu_to_le16(BGCOM_CMD_TX_DATA_CONT); + else + req.msg.cmd = cpu_to_le16(BGCOM_CMD_TX_DATA); + + req.msg.param1 = cpu_to_le16(channel->lcid); + req.msg.param2 = cpu_to_le32(intent->id); + req.chunk_size = cpu_to_le32(chunk_size); + req.left_size = cpu_to_le32(left_size); + + mutex_lock(&glink->tx_lock); + while (glink_bgcom_tx_avail(glink) < sizeof(req)/WORD_SIZE) { + if (!wait) { + mutex_unlock(&glink->tx_lock); + return -EAGAIN; + } + + if (atomic_read(&glink->in_reset)) { + mutex_unlock(&glink->tx_lock); + return -EINVAL; + } + + if (!glink->sent_read_notify) { + glink->sent_read_notify = true; + glink_bgcom_send_read_notify(glink); + } + + /* Wait without holding the tx_lock */ + mutex_unlock(&glink->tx_lock); + + usleep_range(TX_WAIT_US, TX_WAIT_US + 50); + + mutex_lock(&glink->tx_lock); + + if (glink_bgcom_tx_avail(glink) >= sizeof(req)/WORD_SIZE) + glink->sent_read_notify = false; + } + + bgcom_ahb_write(glink->bgcom_handle, + (uint32_t)(size_t)(intent->addr + intent->offset), + ALIGN(chunk_size, WORD_SIZE)/WORD_SIZE, data); + + intent->offset += chunk_size; + glink_bgcom_tx_write(glink, &req, sizeof(req)); + + mutex_unlock(&glink->tx_lock); + return 0; +} + +static void glink_bgcom_handle_intent_req_ack(struct glink_bgcom *glink, + unsigned int cid, bool granted) +{ + struct glink_bgcom_channel *channel; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, cid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + dev_err(glink->dev, "unable to find channel\n"); + return; + } + + channel->intent_req_result = granted; + complete(&channel->intent_req_comp); + CH_INFO(channel, "\n"); +} + +/** + * glink_bgcom_advertise_intent - convert an rx intent cmd to wire format and + * transmit + * @glink: The transport to transmit on. + * @channel: The local channel + * @size: The intent to pass on to remote. + * + * Return: 0 on success or standard Linux error code. + */ +static int glink_bgcom_advertise_intent(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel, + struct glink_bgcom_rx_intent *intent) +{ + struct command { + struct glink_bgcom_msg msg; + __le32 size; + __le32 liid; + __le64 addr; + } __packed; + struct command cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.msg.cmd = cpu_to_le16(BGCOM_CMD_INTENT); + cmd.msg.param1 = cpu_to_le16(channel->lcid); + cmd.msg.param2 = cpu_to_le32(1); + cmd.size = cpu_to_le32(intent->size); + cmd.liid = cpu_to_le32(intent->id); + + glink_bgcom_tx(glink, &cmd, sizeof(cmd), true); + + CH_INFO(channel, "count:%d size:%lu liid:%d\n", 1, + intent->size, intent->id); + + return 0; +} + +/** + * glink_bgcom_handle_intent_req() - Receive a request for rx_intent + * from remote side + * if_ptr: Pointer to the transport interface + * rcid: Remote channel ID + * size: size of the intent + * + * The function searches for the local channel to which the request for + * rx_intent has arrived and allocates and notifies the remote back + */ +static void glink_bgcom_handle_intent_req(struct glink_bgcom *glink, + u32 cid, size_t size) +{ + struct glink_bgcom_rx_intent *intent; + struct glink_bgcom_channel *channel; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, cid); + mutex_unlock(&glink->idr_lock); + + if (!channel) { + pr_err("%s channel not found for cid %d\n", __func__, cid); + return; + } + + intent = glink_bgcom_alloc_intent(glink, channel, size, false); + if (intent) + glink_bgcom_advertise_intent(glink, channel, intent); + + glink_bgcom_send_intent_req_ack(glink, channel, !!intent); +} + +static int glink_bgcom_send_short(struct glink_bgcom_channel *channel, + void *data, int len, + struct glink_bgcom_rx_intent *intent, + bool wait) +{ + struct glink_bgcom *glink = channel->glink; + struct { + struct glink_bgcom_msg msg; + u8 data[SHORT_SIZE]; + } __packed req; + + CH_INFO(channel, "intent offset:%d len:%d\n", intent->offset, len); + + req.msg.cmd = cpu_to_le16(BGCOM_CMD_TX_SHORT_DATA); + req.msg.param1 = cpu_to_le16(channel->lcid); + req.msg.param2 = cpu_to_le32(intent->id); + req.msg.param3 = cpu_to_le32(len); + req.msg.param4 = cpu_to_be32(0); + memcpy(req.data, data, len); + + mutex_lock(&glink->tx_lock); + while (glink_bgcom_tx_avail(glink) < sizeof(req)/WORD_SIZE) { + + if (!wait) { + mutex_unlock(&glink->tx_lock); + return -EAGAIN; + } + + if (atomic_read(&glink->in_reset)) { + mutex_unlock(&glink->tx_lock); + return -EINVAL; + } + + if (!glink->sent_read_notify) { + glink->sent_read_notify = true; + glink_bgcom_send_read_notify(glink); + } + + /* Wait without holding the tx_lock */ + mutex_unlock(&glink->tx_lock); + + usleep_range(TX_WAIT_US, TX_WAIT_US + 50); + + mutex_lock(&glink->tx_lock); + + if (glink_bgcom_tx_avail(glink) >= sizeof(req)/WORD_SIZE) + glink->sent_read_notify = false; + } + glink_bgcom_tx_write(glink, &req, sizeof(req)); + + mutex_unlock(&glink->tx_lock); + return 0; +} + +static int glink_bgcom_request_intent(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel, + size_t size) +{ + struct glink_bgcom_msg req = { 0 }; + int ret; + + kref_get(&channel->refcount); + mutex_lock(&channel->intent_req_lock); + + reinit_completion(&channel->intent_req_comp); + + req.cmd = cpu_to_le16(BGCOM_CMD_RX_INTENT_REQ); + req.param1 = cpu_to_le16(channel->lcid); + req.param2 = cpu_to_le32(size); + + CH_INFO(channel, "size:%lu\n", size); + + ret = glink_bgcom_tx(glink, &req, sizeof(req), true); + if (ret) + goto unlock; + + ret = wait_for_completion_timeout(&channel->intent_req_comp, 10 * HZ); + if (!ret) { + dev_err(glink->dev, "intent request timed out\n"); + ret = -ETIMEDOUT; + } else { + ret = channel->intent_req_result ? 0 : -ECANCELED; + } + +unlock: + mutex_unlock(&channel->intent_req_lock); + kref_put(&channel->refcount, glink_bgcom_channel_release); + return ret; +} + +static int __glink_bgcom_send(struct glink_bgcom_channel *channel, + void *data, int len, bool wait) +{ + struct glink_bgcom *glink = channel->glink; + struct glink_bgcom_rx_intent *intent = NULL; + struct glink_bgcom_rx_intent *tmp; + int size = len; + int iid = 0; + int ret = 0; + + CH_INFO(channel, "size:%d, wait:%d\n", len, wait); + + atomic_inc(&glink->activity_cnt); + bgcom_resume(glink->bgcom_handle); + while (!intent) { + mutex_lock(&channel->intent_lock); + idr_for_each_entry(&channel->riids, tmp, iid) { + if (tmp->size >= len && !tmp->in_use) { + if (!intent) + intent = tmp; + else if (intent->size > tmp->size) + intent = tmp; + if (intent->size == len) + break; + } + } + if (intent) + intent->in_use = true; + mutex_unlock(&channel->intent_lock); + + /* We found an available intent */ + if (intent) + break; + + if (!wait) { + ret = -EBUSY; + goto tx_exit; + } + + ret = glink_bgcom_request_intent(glink, channel, len); + if (ret < 0) + goto tx_exit; + } + + if (len <= SHORT_SIZE) + size = 0; + else if (size & (XPRT_ALIGNMENT - 1)) + size = ALIGN(len - SHORT_SIZE, XPRT_ALIGNMENT); + + if (size) { + ret = glink_bgcom_send_data(channel, data, size, len - size, + intent, wait); + if (ret) + goto tx_exit; + } + + data = (char *)data + size; + size = len - size; + if (size) + ret = glink_bgcom_send_short(channel, data, size, intent, wait); + +tx_exit: + /* Mark intent available if we failed */ + if (ret && intent) + intent->in_use = false; + + atomic_dec(&glink->activity_cnt); + + return ret; +} + +/** + * glink_spi_send_signals() - convert a signal cmd to wire format and transmit + * @glink: The transport to transmit on. + * @channel: The glink channel + * @sigs: The signals to encode. + * + * Return: 0 on success or standard Linux error code. + */ +static int glink_bgcom_send_signals(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel, + u32 sigs) +{ + struct glink_bgcom_msg msg; + + msg.cmd = cpu_to_le16(BGCOM_CMD_SIGNALS); + msg.param1 = cpu_to_le16(channel->lcid); + msg.param2 = cpu_to_le32(sigs); + + GLINK_INFO(glink, "sigs:%d\n", sigs); + return glink_bgcom_tx(glink, &msg, sizeof(msg), true); +} + +static int glink_bgcom_handle_signals(struct glink_bgcom *glink, + unsigned int rcid, unsigned int signals) +{ + struct glink_bgcom_channel *channel; + u32 old; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, rcid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + dev_err(glink->dev, "signal for non-existing channel\n"); + return -EINVAL; + } + + old = channel->rsigs; + channel->rsigs = signals; + + if (channel->ept.sig_cb) + channel->ept.sig_cb(channel->ept.rpdev, old, channel->rsigs); + + CH_INFO(channel, "old:%d new:%d\n", old, channel->rsigs); + + return 0; +} + +static int glink_bgcom_send_version(struct glink_bgcom *glink) +{ + struct glink_bgcom_msg msg = { 0 }; + + msg.cmd = cpu_to_le16(BGCOM_CMD_VERSION); + msg.param1 = cpu_to_le16(GLINK_VERSION_1); + msg.param2 = cpu_to_le32(glink->features); + + GLINK_INFO(glink, "vers:%d features:%d\n", msg.param1, msg.param2); + return glink_bgcom_tx(glink, &msg, sizeof(msg), true); +} + +static void glink_bgcom_send_version_ack(struct glink_bgcom *glink) +{ + struct glink_bgcom_msg msg = { 0 }; + + msg.cmd = cpu_to_le16(BGCOM_CMD_VERSION_ACK); + msg.param1 = cpu_to_le16(GLINK_VERSION_1); + msg.param2 = cpu_to_le32(glink->features); + + GLINK_INFO(glink, "vers:%d features:%d\n", msg.param1, msg.param2); + glink_bgcom_tx(glink, &msg, sizeof(msg), true); +} + +static void glink_bgcom_send_close_req(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel) +{ + struct glink_bgcom_msg req = { 0 }; + + req.cmd = cpu_to_le16(BGCOM_CMD_CLOSE); + req.param1 = cpu_to_le16(channel->lcid); + + CH_INFO(channel, "\n"); + glink_bgcom_tx(glink, &req, sizeof(req), true); +} + +/** + * glink_bgcom_send_open_req() - send a BGCOM_CMD_OPEN request to the remote + * @glink: Ptr to the glink edge + * @channel: Ptr to the channel that the open req is sent + * + * Allocates a local channel id and sends a BGCOM_CMD_OPEN message to the + * remote. Will return with refcount held, regardless of outcome. + * + * Returns 0 on success, negative errno otherwise. + */ +static int glink_bgcom_send_open_req(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel) +{ + + struct cmd_msg { + __le16 cmd; + __le16 lcid; + __le16 length; + __le16 req_xprt; + __le64 reserved; + }; + struct { + struct cmd_msg msg; + u8 name[GLINK_NAME_SIZE]; + } __packed req; + int name_len = strlen(channel->name) + 1; + int req_len = ALIGN(sizeof(req.msg) + name_len, BGCOM_ALIGNMENT); + int ret; + + kref_get(&channel->refcount); + + mutex_lock(&glink->idr_lock); + ret = idr_alloc_cyclic(&glink->lcids, channel, + BGCOM_GLINK_CID_MIN, BGCOM_GLINK_CID_MAX, + GFP_ATOMIC); + mutex_unlock(&glink->idr_lock); + if (ret < 0) + return ret; + + channel->lcid = ret; + CH_INFO(channel, "\n"); + + memset(&req, 0, sizeof(req)); + req.msg.cmd = cpu_to_le16(BGCOM_CMD_OPEN); + req.msg.lcid = cpu_to_le16(channel->lcid); + req.msg.length = cpu_to_le16(name_len); + strlcpy(req.name, channel->name, GLINK_NAME_SIZE); + + ret = glink_bgcom_tx(glink, &req, req_len, true); + if (ret) + goto remove_idr; + + return 0; + +remove_idr: + CH_INFO(channel, "remove_idr\n"); + + mutex_lock(&glink->idr_lock); + idr_remove(&glink->lcids, channel->lcid); + channel->lcid = 0; + mutex_unlock(&glink->idr_lock); + + return ret; +} + +static void glink_bgcom_send_open_ack(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel) +{ + struct glink_bgcom_msg msg = { 0 }; + + msg.cmd = cpu_to_le16(BGCOM_CMD_OPEN_ACK); + msg.param1 = cpu_to_le16(channel->rcid); + + CH_INFO(channel, "\n"); + glink_bgcom_tx(glink, &msg, sizeof(msg), true); +} + +static int glink_bgcom_rx_open_ack(struct glink_bgcom *glink, + unsigned int lcid) +{ + struct glink_bgcom_channel *channel; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->lcids, lcid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + GLINK_ERR(glink, "Invalid open ack packet %d\n", lcid); + return -EINVAL; + } + + CH_INFO(channel, "\n"); + complete_all(&channel->open_ack); + + return 0; +} + +/* Remote initiated rpmsg_create_ept */ +static int glink_bgcom_create_remote(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel) +{ + int ret; + + CH_INFO(channel, "\n"); + + glink_bgcom_send_open_ack(glink, channel); + + ret = glink_bgcom_send_open_req(glink, channel); + if (ret) + goto close_link; + + ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ); + if (!ret) { + ret = -ETIMEDOUT; + goto close_link; + } + + return 0; + +close_link: + CH_INFO(channel, "close_link %d\n", ret); + + /* + * Send a close request to "undo" our open-ack. The close-ack will + * release glink_bgcom_send_open_req() reference and the last reference + * will be release after rx_close or transport unregister by calling + * glink_bgcom_remove(). + */ + glink_bgcom_send_close_req(glink, channel); + + return ret; +} + +/* Locally initiated rpmsg_create_ept */ +static struct glink_bgcom_channel +*glink_bgcom_create_local(struct glink_bgcom *glink, const char *name) +{ + struct glink_bgcom_channel *channel; + int ret; + + channel = glink_bgcom_alloc_channel(glink, name); + if (IS_ERR(channel)) + return ERR_CAST(channel); + + CH_INFO(channel, "\n"); + ret = glink_bgcom_send_open_req(glink, channel); + if (ret) + goto release_channel; + + ret = wait_for_completion_timeout(&channel->open_ack, 5 * HZ); + if (!ret) + goto err_timeout; + + ret = wait_for_completion_timeout(&channel->open_req, 5 * HZ); + if (!ret) + goto err_timeout; + + glink_bgcom_send_open_ack(glink, channel); + + return channel; + +err_timeout: + CH_INFO(channel, "err_timeout\n"); + + /* glink_bgcom_send_open_req() did register the channel in lcids*/ + mutex_lock(&glink->idr_lock); + idr_remove(&glink->lcids, channel->lcid); + mutex_unlock(&glink->idr_lock); + +release_channel: + CH_INFO(channel, "release_channel\n"); + /* Release glink_bgcom_send_open_req() reference */ + kref_put(&channel->refcount, glink_bgcom_channel_release); + /* Release glink_bgcom_alloc_channel() reference */ + kref_put(&channel->refcount, glink_bgcom_channel_release); + + return ERR_PTR(-ETIMEDOUT); +} + +static struct rpmsg_endpoint * +glink_bgcom_create_ept(struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, + void *priv, struct rpmsg_channel_info chinfo) +{ + struct glink_bgcom_channel *parent = to_glink_channel(rpdev->ept); + struct glink_bgcom_channel *channel; + struct glink_bgcom *glink = parent->glink; + struct rpmsg_endpoint *ept; + const char *name = chinfo.name; + int cid; + int ret; + + mutex_lock(&glink->idr_lock); + idr_for_each_entry(&glink->rcids, channel, cid) { + if (!strcmp(channel->name, name)) + break; + } + mutex_unlock(&glink->idr_lock); + + if (!channel) { + channel = glink_bgcom_create_local(glink, name); + if (IS_ERR(channel)) + return NULL; + } else { + ret = glink_bgcom_create_remote(glink, channel); + if (ret) + return NULL; + } + + ept = &channel->ept; + ept->rpdev = rpdev; + ept->cb = cb; + ept->priv = priv; + ept->ops = &glink_endpoint_ops; + + return ept; +} + +static int glink_bgcom_announce_create(struct rpmsg_device *rpdev) +{ + struct glink_bgcom_channel *channel = to_glink_channel(rpdev->ept); + struct device_node *np = rpdev->dev.of_node; + struct glink_bgcom *glink = channel->glink; + struct glink_bgcom_rx_intent *intent; + const struct property *prop = NULL; + __be32 defaults[] = { cpu_to_be32(SZ_1K), cpu_to_be32(5) }; + int num_intents; + int num_groups = 1; + __be32 *val = defaults; + int size; + + if (!completion_done(&channel->open_ack)) + return 0; + + prop = of_find_property(np, "qcom,intents", NULL); + if (prop) { + val = prop->value; + num_groups = prop->length / sizeof(u32) / 2; + } + + /* Channel is now open, advertise base set of intents */ + while (num_groups--) { + size = be32_to_cpup(val++); + num_intents = be32_to_cpup(val++); + while (num_intents--) { + intent = glink_bgcom_alloc_intent(glink, channel, size, + true); + if (!intent) + break; + + glink_bgcom_advertise_intent(glink, channel, intent); + } + } + return 0; +} + +static void glink_bgcom_destroy_ept(struct rpmsg_endpoint *ept) +{ + struct glink_bgcom_channel *channel = to_glink_channel(ept); + struct glink_bgcom *glink = channel->glink; + unsigned long flags; + + spin_lock_irqsave(&channel->recv_lock, flags); + channel->ept.cb = NULL; + spin_unlock_irqrestore(&channel->recv_lock, flags); + + /* Decouple the potential rpdev from the channel */ + channel->rpdev = NULL; + + glink_bgcom_send_close_req(glink, channel); +} + +static void glink_bgcom_send_close_ack(struct glink_bgcom *glink, + unsigned int rcid) +{ + struct glink_bgcom_msg req = { 0 }; + + req.cmd = cpu_to_le16(BGCOM_CMD_CLOSE_ACK); + req.param1 = cpu_to_le16(rcid); + + GLINK_INFO(glink, "rcid:%d\n", rcid); + glink_bgcom_tx(glink, &req, sizeof(req), true); +} + +static void glink_bgcom_rx_close(struct glink_bgcom *glink, unsigned int rcid) +{ + struct rpmsg_channel_info chinfo; + struct glink_bgcom_channel *channel; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, rcid); + mutex_unlock(&glink->idr_lock); + if (WARN(!channel, "close request on unknown channel\n")) + return; + CH_INFO(channel, "\n"); + + if (channel->rpdev) { + strlcpy(chinfo.name, channel->name, sizeof(chinfo.name)); + chinfo.src = RPMSG_ADDR_ANY; + chinfo.dst = RPMSG_ADDR_ANY; + + rpmsg_unregister_device(glink->dev, &chinfo); + } + + glink_bgcom_send_close_ack(glink, channel->rcid); + + mutex_lock(&glink->idr_lock); + idr_remove(&glink->rcids, channel->rcid); + channel->rcid = 0; + mutex_unlock(&glink->idr_lock); + + kref_put(&channel->refcount, glink_bgcom_channel_release); +} + +static void glink_bgcom_rx_close_ack(struct glink_bgcom *glink, + unsigned int lcid) +{ + struct glink_bgcom_channel *channel; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->lcids, lcid); + if (WARN(!channel, "close ack on unknown channel\n")) { + mutex_unlock(&glink->idr_lock); + return; + } + CH_INFO(channel, "\n"); + + idr_remove(&glink->lcids, channel->lcid); + channel->lcid = 0; + mutex_unlock(&glink->idr_lock); + + kref_put(&channel->refcount, glink_bgcom_channel_release); +} + +static int glink_bgcom_send(struct rpmsg_endpoint *ept, void *data, int len) +{ + struct glink_bgcom_channel *channel = to_glink_channel(ept); + + return __glink_bgcom_send(channel, data, len, true); +} + +static int glink_bgcom_trysend(struct rpmsg_endpoint *ept, void *data, + int len) +{ + struct glink_bgcom_channel *channel = to_glink_channel(ept); + + return __glink_bgcom_send(channel, data, len, false); +} + +/** + * glink_bgcom_receive_version_ack() - receive negotiation ack from remote + * system + * + * @glink: pointer to transport interface + * @r_version: remote version response + * @r_features: remote features response + * + * This function is called in response to a local-initiated version/feature + * negotiation sequence and is the counter-offer from the remote side based + * upon the initial version and feature set requested. + */ +static void glink_bgcom_receive_version_ack(struct glink_bgcom *glink, + u32 version, + u32 features) +{ + GLINK_INFO(glink, "vers:%d features:%d\n", version, features); + + switch (version) { + case 0: + /* Version negotiation failed */ + break; + case GLINK_VERSION_1: + if (features == glink->features) + break; + + glink->features &= features; + /* FALLTHROUGH */ + default: + glink_bgcom_send_version(glink); + break; + } +} + +/** + * glink_bgcom_receive_version() - receive version/features from remote system + * + * @glink: pointer to transport interface + * @r_version: remote version + * @r_features: remote features + * + * This function is called in response to a remote-initiated version/feature + * negotiation sequence. + */ +static void glink_bgcom_receive_version(struct glink_bgcom *glink, + u32 version, + u32 features) +{ + GLINK_INFO(glink, "vers:%d features:%d\n", version, features); + + switch (version) { + case 0: + break; + case GLINK_VERSION_1: + glink->features &= features; + /* FALLTHROUGH */ + default: + glink_bgcom_send_version_ack(glink); + break; + } +} + +static const struct rpmsg_device_ops glink_device_ops = { + .create_ept = glink_bgcom_create_ept, + .announce_create = glink_bgcom_announce_create, +}; + +/* + * Finds the device_node for the glink child interested in this channel. + */ +static struct device_node *glink_bgcom_match_channel(struct device_node *node, + const char *channel) +{ + struct device_node *child; + const char *name; + const char *key; + int ret; + + for_each_available_child_of_node(node, child) { + key = "qcom,glink-channels"; + ret = of_property_read_string(child, key, &name); + if (ret) + continue; + + if (strcmp(name, channel) == 0) + return child; + } + + return NULL; +} + +static void glink_bgcom_rpdev_release(struct device *dev) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + struct glink_bgcom_channel *channel = to_glink_channel(rpdev->ept); + + channel->rpdev = NULL; + kfree(rpdev); + +} +static int glink_bgcom_rx_open(struct glink_bgcom *glink, unsigned int rcid, + char *name) +{ + struct glink_bgcom_channel *channel; + struct rpmsg_device *rpdev; + bool create_device = false; + struct device_node *node; + int lcid; + int ret; + + mutex_lock(&glink->idr_lock); + idr_for_each_entry(&glink->lcids, channel, lcid) { + if (!strcmp(channel->name, name)) + break; + } + mutex_unlock(&glink->idr_lock); + + if (!channel) { + channel = glink_bgcom_alloc_channel(glink, name); + if (IS_ERR(channel)) + return PTR_ERR(channel); + + /* The opening dance was initiated by the remote */ + create_device = true; + } + + mutex_lock(&glink->idr_lock); + ret = idr_alloc(&glink->rcids, channel, rcid, rcid + 1, GFP_ATOMIC); + if (ret < 0) { + dev_err(glink->dev, "Unable to insert channel into rcid list\n"); + mutex_unlock(&glink->idr_lock); + goto free_channel; + } + channel->rcid = ret; + mutex_unlock(&glink->idr_lock); + + complete_all(&channel->open_req); + + if (create_device) { + rpdev = kzalloc(sizeof(*rpdev), GFP_KERNEL); + if (!rpdev) { + ret = -ENOMEM; + goto rcid_remove; + } + + rpdev->ept = &channel->ept; + strlcpy(rpdev->id.name, name, RPMSG_NAME_SIZE); + rpdev->src = RPMSG_ADDR_ANY; + rpdev->dst = RPMSG_ADDR_ANY; + rpdev->ops = &glink_device_ops; + + node = glink_bgcom_match_channel(glink->dev->of_node, name); + rpdev->dev.of_node = node; + rpdev->dev.parent = glink->dev; + rpdev->dev.release = glink_bgcom_rpdev_release; + + ret = rpmsg_register_device(rpdev); + if (ret) + goto free_rpdev; + + channel->rpdev = rpdev; + } + CH_INFO(channel, "\n"); + + return 0; + +free_rpdev: + CH_INFO(channel, "free_rpdev\n"); + kfree(rpdev); +rcid_remove: + CH_INFO(channel, "rcid_remove\n"); + mutex_lock(&glink->idr_lock); + idr_remove(&glink->rcids, channel->rcid); + channel->rcid = 0; + mutex_unlock(&glink->idr_lock); +free_channel: + CH_INFO(channel, "free_channel\n"); + /* Release the reference, iff we took it */ + if (create_device) + kref_put(&channel->refcount, glink_bgcom_channel_release); + + return ret; +} + +static void glink_bgcom_defer_work(struct work_struct *work) +{ + struct glink_bgcom *glink = container_of(work, struct glink_bgcom, + rx_defer_work); + + struct glink_bgcom_defer_cmd *dcmd; + struct glink_bgcom_msg *msg; + unsigned long flags; + unsigned int param1; + unsigned int param2; + unsigned int param3; + unsigned int param4; + unsigned int cmd; + + atomic_inc(&glink->activity_cnt); + bgcom_resume(glink->bgcom_handle); + for (;;) { + spin_lock_irqsave(&glink->rx_lock, flags); + if (list_empty(&glink->rx_queue)) { + spin_unlock_irqrestore(&glink->rx_lock, flags); + break; + } + dcmd = list_first_entry(&glink->rx_queue, + struct glink_bgcom_defer_cmd, node); + list_del(&dcmd->node); + spin_unlock_irqrestore(&glink->rx_lock, flags); + + msg = &dcmd->msg; + cmd = le16_to_cpu(msg->cmd); + param1 = le16_to_cpu(msg->param1); + param2 = le32_to_cpu(msg->param2); + param3 = le32_to_cpu(msg->param3); + param4 = le32_to_cpu(msg->param4); + + switch (cmd) { + case BGCOM_CMD_OPEN: + glink_bgcom_rx_open(glink, param1, msg->data); + break; + case BGCOM_CMD_CLOSE: + glink_bgcom_rx_close(glink, param1); + break; + case BGCOM_CMD_CLOSE_ACK: + glink_bgcom_rx_close_ack(glink, param1); + break; + default: + WARN(1, "Unknown defer object %d\n", cmd); + break; + } + + kfree(dcmd); + } + atomic_dec(&glink->activity_cnt); +} + +static int glink_bgcom_rx_defer(struct glink_bgcom *glink, + void *rx_data, u32 rx_avail, size_t extra) +{ + struct glink_bgcom_defer_cmd *dcmd; + + extra = ALIGN(extra, BGCOM_ALIGNMENT); + + if (rx_avail < sizeof(struct glink_bgcom_msg) + extra) { + dev_dbg(glink->dev, "Insufficient data in rx fifo"); + return -ENXIO; + } + + dcmd = kzalloc(sizeof(*dcmd) + extra, GFP_KERNEL); + if (!dcmd) + return -ENOMEM; + + INIT_LIST_HEAD(&dcmd->node); + + memcpy(&dcmd->msg, rx_data, sizeof(dcmd->msg) + extra); + + spin_lock(&glink->rx_lock); + list_add_tail(&dcmd->node, &glink->rx_queue); + spin_unlock(&glink->rx_lock); + + schedule_work(&glink->rx_defer_work); + + return 0; +} + +/** + * glink_bgcom_send_rx_done() - send a rx done to remote side + * glink: The transport to transmit on + * channel: The glink channel + * intent: the intent to send rx done for + * + * This function assumes the intent lock is held + */ +static void glink_bgcom_send_rx_done(struct glink_bgcom *glink, + struct glink_bgcom_channel *channel, + struct glink_bgcom_rx_intent *intent) +{ + struct { + u16 id; + u16 lcid; + u32 liid; + u64 reserved; + } __packed cmd; + unsigned int cid = channel->lcid; + unsigned int iid = intent->id; + bool reuse = intent->reuse; + + cmd.id = reuse ? BGCOM_CMD_RX_DONE_W_REUSE : BGCOM_CMD_RX_DONE; + cmd.lcid = cid; + cmd.liid = iid; + glink_bgcom_tx(glink, &cmd, sizeof(cmd), true); + CH_INFO(channel, "reuse:%d liid:%d", reuse, iid); +} + +/** + * glink_bgcom_free_intent() - Reset and free intent if not reusuable + * channel: The glink channel + * intent: the intent to send rx done for + * + * This function assumes the intent lock is held + */ +static void glink_bgcom_free_intent(struct glink_bgcom_channel *channel, + struct glink_bgcom_rx_intent *intent) +{ + CH_INFO(channel, "reuse:%d liid:%d", intent->reuse, intent->id); + intent->offset = 0; + if (!intent->reuse) { + idr_remove(&channel->liids, intent->id); + kfree(intent->data); + kfree(intent); + } +} + +static int glink_bgcom_rx_data(struct glink_bgcom *glink, + unsigned int rcid, unsigned int liid, + void *rx_data, size_t avail) +{ + struct glink_bgcom_rx_intent *intent; + struct glink_bgcom_channel *channel; + struct data_desc { + __le32 chunk_size; + __le32 left_size; + __le64 addr; + }; + struct data_desc *hdr; + unsigned int chunk_size; + unsigned int left_size; + u32 addr; + size_t msglen; + unsigned long flags; + int rc; + + msglen = sizeof(*hdr); + if (avail < msglen) { + dev_dbg(glink->dev, "Not enough data in fifo\n"); + return avail; + } + hdr = (struct data_desc *)rx_data; + + chunk_size = le32_to_cpu(hdr->chunk_size); + left_size = le32_to_cpu(hdr->left_size); + addr = (u32)le64_to_cpu(hdr->addr); + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, rcid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + dev_dbg(glink->dev, "Data on non-existing channel\n"); + return msglen; + } + CH_INFO(channel, "chunk_size:%d left_size:%d\n", chunk_size, left_size); + + mutex_lock(&channel->intent_lock); + intent = idr_find(&channel->liids, liid); + + if (!intent) { + dev_err(glink->dev, + "no intent found for channel %s intent %d", + channel->name, liid); + mutex_unlock(&channel->intent_lock); + + return msglen; + } + + if (intent->size - intent->offset < chunk_size) { + dev_err(glink->dev, "Insufficient space in intent\n"); + mutex_unlock(&channel->intent_lock); + + /* The packet header lied, drop payload */ + return msglen; + } + + rc = bgcom_ahb_read(glink->bgcom_handle, (uint32_t)(size_t)addr, + ALIGN(chunk_size, WORD_SIZE)/WORD_SIZE, + intent->data + intent->offset); + if (rc < 0) { + GLINK_ERR(glink, "%s: Error %d receiving data\n", + __func__, rc); + } + + intent->offset += chunk_size; + + /* Handle message when no fragments remain to be received */ + if (!left_size) { + glink_bgcom_send_rx_done(glink, channel, intent); + + spin_lock_irqsave(&channel->recv_lock, flags); + if (channel->ept.cb) { + channel->ept.cb(channel->ept.rpdev, + intent->data, + intent->offset, + channel->ept.priv, + RPMSG_ADDR_ANY); + } + spin_unlock_irqrestore(&channel->recv_lock, flags); + + glink_bgcom_free_intent(channel, intent); + } + mutex_unlock(&channel->intent_lock); + + return msglen; +} + +static int glink_bgcom_rx_short_data(struct glink_bgcom *glink, + unsigned int rcid, unsigned int liid, + unsigned int chunk_size, + unsigned int left_size, + void *src, size_t avail) +{ + struct glink_bgcom_rx_intent *intent; + struct glink_bgcom_channel *channel; + size_t msglen = SHORT_SIZE; + unsigned long flags; + + if (avail < msglen) { + dev_dbg(glink->dev, "Not enough data in fifo\n"); + return avail; + } + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, rcid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + dev_dbg(glink->dev, "Data on non-existing channel\n"); + return msglen; + } + CH_INFO(channel, "chunk_size:%d left_size:%d\n", chunk_size, left_size); + + mutex_lock(&channel->intent_lock); + intent = idr_find(&channel->liids, liid); + + if (!intent) { + dev_err(glink->dev, + "no intent found for channel %s intent %d", + channel->name, liid); + mutex_unlock(&channel->intent_lock); + return msglen; + } + + if (intent->size - intent->offset < chunk_size) { + dev_err(glink->dev, "Insufficient space in intent\n"); + mutex_unlock(&channel->intent_lock); + + /* The packet header lied, drop payload */ + return msglen; + } + + /* Read message from addr sent by WDSP */ + memcpy(intent->data + intent->offset, src, chunk_size); + intent->offset += chunk_size; + + /* Handle message when no fragments remain to be received */ + if (!left_size) { + glink_bgcom_send_rx_done(glink, channel, intent); + + spin_lock_irqsave(&channel->recv_lock, flags); + if (channel->ept.cb) { + channel->ept.cb(channel->ept.rpdev, + intent->data, + intent->offset, + channel->ept.priv, + RPMSG_ADDR_ANY); + } + spin_unlock_irqrestore(&channel->recv_lock, flags); + + glink_bgcom_free_intent(channel, intent); + } + mutex_unlock(&channel->intent_lock); + + return msglen; +} + +static int glink_bgcom_handle_intent(struct glink_bgcom *glink, + unsigned int cid, + unsigned int count, + void *rx_data, + size_t avail) +{ + struct glink_bgcom_rx_intent *intent; + struct glink_bgcom_channel *channel; + struct intent_pair { + __le32 size; + __le32 iid; + __le64 addr; + }; + struct intent_pair *intents; + const size_t msglen = sizeof(struct intent_pair) * count; + int ret; + int i; + + if (avail < msglen) { + dev_err(glink->dev, "Not enough data in buf\n"); + return avail; + } + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, cid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + dev_err(glink->dev, "intents for non-existing channel\n"); + return msglen; + } + + intents = (struct intent_pair *)rx_data; + for (i = 0; i < count; ++i) { + intent = kzalloc(sizeof(*intent), GFP_ATOMIC); + if (!intent) + break; + + intent->id = le32_to_cpu(intents[i].iid); + intent->size = le32_to_cpu(intents[i].size); + intent->addr = (u32)le64_to_cpu(intents[i].addr); + + CH_INFO(channel, "riid:%d size:%lu\n", intent->id, + intent->size); + + mutex_lock(&channel->intent_lock); + ret = idr_alloc(&channel->riids, intent, + intent->id, intent->id + 1, GFP_ATOMIC); + mutex_unlock(&channel->intent_lock); + + if (ret < 0) + dev_err(glink->dev, "failed to store remote intent\n"); + } + + return msglen; +} + +static void glink_bgcom_handle_rx_done(struct glink_bgcom *glink, + u32 cid, uint32_t iid, + bool reuse) +{ + struct glink_bgcom_rx_intent *intent; + struct glink_bgcom_channel *channel; + + mutex_lock(&glink->idr_lock); + channel = idr_find(&glink->rcids, cid); + mutex_unlock(&glink->idr_lock); + if (!channel) { + dev_err(glink->dev, "invalid channel id received\n"); + return; + } + + mutex_lock(&channel->intent_lock); + intent = idr_find(&channel->riids, iid); + + if (!intent) { + mutex_unlock(&channel->intent_lock); + dev_err(glink->dev, "invalid intent id received\n"); + return; + } + + intent->offset = 0; + intent->in_use = false; + CH_INFO(channel, "reuse:%d iid:%d\n", reuse, intent->id); + + if (!reuse) { + idr_remove(&channel->riids, intent->id); + kfree(intent); + } + mutex_unlock(&channel->intent_lock); +} + +static void glink_bgcom_process_cmd(struct glink_bgcom *glink, void *rx_data, + u32 rx_size) +{ + struct glink_bgcom_msg *msg; + unsigned int param1; + unsigned int param2; + unsigned int param3; + unsigned int param4; + unsigned int cmd; + int offset = 0; + int ret; + u16 name_len; + char *name; + + while (offset < rx_size) { + msg = (struct glink_bgcom_msg *)(rx_data + offset); + offset += sizeof(*msg); + + cmd = le16_to_cpu(msg->cmd); + param1 = le16_to_cpu(msg->param1); + param2 = le32_to_cpu(msg->param2); + param3 = le32_to_cpu(msg->param3); + param4 = le32_to_cpu(msg->param4); + + switch (cmd) { + case BGCOM_CMD_VERSION: + glink_bgcom_receive_version(glink, param1, param2); + break; + case BGCOM_CMD_VERSION_ACK: + glink_bgcom_receive_version_ack(glink, param1, param2); + break; + case BGCOM_CMD_CLOSE: + case BGCOM_CMD_CLOSE_ACK: + glink_bgcom_rx_defer(glink, + rx_data + offset - sizeof(*msg), + rx_size + offset - sizeof(*msg), 0); + break; + case BGCOM_CMD_RX_INTENT_REQ: + glink_bgcom_handle_intent_req(glink, param1, param2); + break; + case BGCOM_CMD_OPEN_ACK: + ret = glink_bgcom_rx_open_ack(glink, param1); + break; + case BGCOM_CMD_OPEN: + name_len = (u16)(param2 & 0xFFFF); + name = rx_data + offset; + glink_bgcom_rx_defer(glink, + rx_data + offset - sizeof(*msg), + rx_size + offset - sizeof(*msg), + ALIGN(name_len, BGCOM_ALIGNMENT)); + + offset += ALIGN(name_len, BGCOM_ALIGNMENT); + break; + case BGCOM_CMD_TX_DATA: + case BGCOM_CMD_TX_DATA_CONT: + ret = glink_bgcom_rx_data(glink, param1, param2, + rx_data + offset, + rx_size - offset); + offset += ALIGN(ret, BGCOM_ALIGNMENT); + break; + case BGCOM_CMD_TX_SHORT_DATA: + ret = glink_bgcom_rx_short_data(glink, + param1, param2, + param3, param4, + rx_data + offset, + rx_size - offset); + offset += ALIGN(ret, BGCOM_ALIGNMENT); + break; + case BGCOM_CMD_READ_NOTIF: + break; + case BGCOM_CMD_INTENT: + ret = glink_bgcom_handle_intent(glink, + param1, param2, + rx_data + offset, + rx_size - offset); + offset += ALIGN(ret, BGCOM_ALIGNMENT); + break; + case BGCOM_CMD_RX_DONE: + glink_bgcom_handle_rx_done(glink, param1, param2, + false); + break; + case BGCOM_CMD_RX_DONE_W_REUSE: + glink_bgcom_handle_rx_done(glink, param1, param2, + true); + break; + case BGCOM_CMD_RX_INTENT_REQ_ACK: + glink_bgcom_handle_intent_req_ack(glink, param1, + param2); + break; + case BGCOM_CMD_SIGNALS: + glink_bgcom_handle_signals(glink, param1, param2); + break; + default: + dev_err(glink->dev, "unhandled rx cmd: %d\n", cmd); + break; + } + } +} + +/** + * __rx_worker() - Receive commands on a specific edge + * @einfo: Edge to process commands on. + * + * This function checks the size of data to be received, allocates the + * buffer for that data and reads the data from the remote subsytem + * into that buffer. This function then calls the glink_bgcom_process_cmd() + * to parse the received G-Link command sequence. This function will also + * poll for the data for a predefined duration for performance reasons. + */ +static void __rx_worker(struct rx_pkt *rx_pkt_info) +{ + struct glink_bgcom *glink = rx_pkt_info->glink; + + if (atomic_read(&glink->in_reset)) + return; + + glink_bgcom_process_cmd(glink, rx_pkt_info->rx_buf, + rx_pkt_info->rx_len*WORD_SIZE); + kfree(rx_pkt_info->rx_buf); + kfree(rx_pkt_info); +} + +/** + * rx_worker() - Worker function to process received commands + * @work: kwork associated with the edge to process commands on. + */ +static void rx_worker(struct kthread_work *work) +{ + struct rx_pkt *rx_pkt_info; + + rx_pkt_info = container_of(work, struct rx_pkt, kwork); + __rx_worker(rx_pkt_info); +}; + +static void glink_bgcom_linkup(struct glink_bgcom *glink) +{ + int ret; + + if (glink->bgcom_status != BGCOM_LINKUP) + return; + atomic_set(&glink->in_reset, 0); + bgcom_reg_read(glink->bgcom_handle, BGCOM_REG_FIFO_SIZE, 1, + &glink->fifo_size); + mutex_lock(&glink->tx_avail_lock); + glink->fifo_fill.tx_avail = glink->fifo_size.to_master; + mutex_unlock(&glink->tx_avail_lock); + + ret = glink_bgcom_send_version(glink); + if (ret) + GLINK_ERR(glink, "Failed to link up %d\n", ret); +} + +static void glink_bgcom_event_handler(void *handle, + void *priv_data, enum bgcom_event_type event, + union bgcom_event_data_type *data) +{ + struct glink_bgcom *glink = (struct glink_bgcom *)priv_data; + struct rx_pkt *rx_pkt_info; + + switch (event) { + case BGCOM_EVENT_APPLICATION_RUNNING: + if (data->application_running && + glink->bgcom_status != BGCOM_LINKUP) { + glink->bgcom_status |= BGCOM_APPLICATION_RUNNING; + glink_bgcom_linkup(glink); + } + break; + case BGCOM_EVENT_TO_SLAVE_FIFO_READY: + if (data->to_slave_fifo_ready && + glink->bgcom_status != BGCOM_LINKUP) { + glink->bgcom_status |= BGCOM_TO_SLAVE_FIFO_READY; + glink_bgcom_linkup(glink); + } + break; + case BGCOM_EVENT_TO_MASTER_FIFO_READY: + if (data->to_master_fifo_ready && + glink->bgcom_status != BGCOM_LINKUP) { + glink->bgcom_status |= BGCOM_TO_MASTER_FIFO_READY; + glink_bgcom_linkup(glink); + } + break; + case BGCOM_EVENT_AHB_READY: + if (data->ahb_ready && + glink->bgcom_status != BGCOM_LINKUP) { + glink->bgcom_status |= BGCOM_AHB_READY; + glink_bgcom_linkup(glink); + } + break; + case BGCOM_EVENT_TO_MASTER_FIFO_USED: + rx_pkt_info = kzalloc(sizeof(struct rx_pkt), GFP_KERNEL); + rx_pkt_info->rx_buf = data->fifo_data.data; + rx_pkt_info->rx_len = data->fifo_data.to_master_fifo_used; + rx_pkt_info->glink = glink; + kthread_init_work(&rx_pkt_info->kwork, rx_worker); + kthread_queue_work(&glink->kworker, &rx_pkt_info->kwork); + break; + case BGCOM_EVENT_TO_SLAVE_FIFO_FREE: + if (glink->water_mark_reached) + tx_wakeup_worker(glink); + break; + case BGCOM_EVENT_RESET_OCCURRED: + glink->bgcom_status = BGCOM_RESET; + atomic_set(&glink->in_reset, 1); + break; + case BGCOM_EVENT_ERROR_WRITE_FIFO_OVERRUN: + case BGCOM_EVENT_ERROR_WRITE_FIFO_BUS_ERR: + case BGCOM_EVENT_ERROR_WRITE_FIFO_ACCESS: + case BGCOM_EVENT_ERROR_READ_FIFO_UNDERRUN: + case BGCOM_EVENT_ERROR_READ_FIFO_BUS_ERR: + case BGCOM_EVENT_ERROR_READ_FIFO_ACCESS: + case BGCOM_EVENT_ERROR_TRUNCATED_READ: + case BGCOM_EVENT_ERROR_TRUNCATED_WRITE: + case BGCOM_EVENT_ERROR_AHB_ILLEGAL_ADDRESS: + case BGCOM_EVENT_ERROR_AHB_BUS_ERR: + GLINK_ERR(glink, "%s: ERROR %d", __func__, event); + break; + default: + GLINK_ERR(glink, "%s: unhandled event %d", __func__, event); + break; + } +} + +static int glink_bgcom_get_sigs(struct rpmsg_endpoint *ept, + u32 *lsigs, u32 *rsigs) +{ + struct glink_bgcom_channel *channel = to_glink_channel(ept); + + *lsigs = channel->lsigs; + *rsigs = channel->rsigs; + + return 0; +} + +static int glink_bgcom_set_sigs(struct rpmsg_endpoint *ept, u32 sigs) +{ + struct glink_bgcom_channel *channel = to_glink_channel(ept); + struct glink_bgcom *glink = channel->glink; + + channel->lsigs = sigs; + + return glink_bgcom_send_signals(glink, channel, sigs); +} + +static const struct rpmsg_endpoint_ops glink_endpoint_ops = { + .destroy_ept = glink_bgcom_destroy_ept, + .send = glink_bgcom_send, + .trysend = glink_bgcom_trysend, + .get_sigs = glink_bgcom_get_sigs, + .set_sigs = glink_bgcom_set_sigs, +}; + +static void glink_bgcom_release(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct glink_bgcom *glink = platform_get_drvdata(pdev); + + kfree(glink); +} + +static int glink_bgcom_probe(struct platform_device *pdev) +{ + struct glink_bgcom *glink; + struct device *dev; + int ret; + + glink = kzalloc(sizeof(*glink), GFP_KERNEL); + if (!glink) + return -ENOMEM; + + glink->dev = &pdev->dev; + dev = glink->dev; + dev->of_node = pdev->dev.of_node; + dev->release = glink_bgcom_release; + dev_set_name(dev, "%s", dev->of_node->name); + dev_set_drvdata(dev, glink); + + ret = of_property_read_string(dev->of_node, "label", &glink->name); + if (ret < 0) + glink->name = dev->of_node->name; + + glink->features = GLINK_FEATURE_INTENT_REUSE; + + mutex_init(&glink->tx_lock); + mutex_init(&glink->tx_avail_lock); + spin_lock_init(&glink->rx_lock); + INIT_LIST_HEAD(&glink->rx_queue); + INIT_WORK(&glink->rx_defer_work, glink_bgcom_defer_work); + + kthread_init_worker(&glink->kworker); + + mutex_init(&glink->idr_lock); + idr_init(&glink->lcids); + idr_init(&glink->rcids); + + atomic_set(&glink->in_reset, 1); + atomic_set(&glink->activity_cnt, 0); + + glink->rx_task = kthread_run(kthread_worker_fn, &glink->kworker, + "bgcom_%s", glink->name); + if (IS_ERR(glink->rx_task)) { + ret = PTR_ERR(glink->rx_task); + dev_err(glink->dev, "kthread run failed %d\n", ret); + goto err_put_dev; + } + + glink->ilc = ipc_log_context_create(GLINK_LOG_PAGE_CNT, glink->name, 0); + + glink->bgcom_config.priv = (void *)glink; + glink->bgcom_config.bgcom_notification_cb = glink_bgcom_event_handler; + glink->bgcom_handle = NULL; + if (!strcmp(glink->name, "bg")) { + glink->bgcom_handle = bgcom_open(&glink->bgcom_config); + if (!glink->bgcom_handle) { + GLINK_ERR(glink, "%s: bgcom open failed\n", __func__); + ret = -ENODEV; + goto err_bg_handle; + } + } + + return 0; + +err_bg_handle: + kthread_stop(glink->rx_task); +err_put_dev: + dev_set_drvdata(dev, NULL); + put_device(dev); + + return ret; +} +EXPORT_SYMBOL(glink_bgcom_probe); + +static int glink_bgcom_remove_device(struct device *dev, void *data) +{ + device_unregister(dev); + + return 0; +} + +static int glink_bgcom_remove(struct platform_device *pdev) +{ + struct glink_bgcom *glink = platform_get_drvdata(pdev); + struct glink_bgcom_channel *channel; + int cid; + int ret; + + GLINK_INFO(glink, "\n"); + + atomic_set(&glink->in_reset, 1); + + bgcom_close(glink->bgcom_handle); + + kthread_flush_worker(&glink->kworker); + kthread_stop(glink->rx_task); + cancel_work_sync(&glink->rx_defer_work); + + ret = device_for_each_child(glink->dev, NULL, + glink_bgcom_remove_device); + if (ret) + dev_warn(glink->dev, "Can't remove GLINK devices: %d\n", ret); + + mutex_lock(&glink->idr_lock); + /* Release any defunct local channels, waiting for close-ack */ + idr_for_each_entry(&glink->lcids, channel, cid) { + /* Wakeup threads waiting for intent*/ + complete(&channel->intent_req_comp); + kref_put(&channel->refcount, glink_bgcom_channel_release); + idr_remove(&glink->lcids, cid); + } + + /* Release any defunct local channels, waiting for close-req */ + idr_for_each_entry(&glink->rcids, channel, cid) { + kref_put(&channel->refcount, glink_bgcom_channel_release); + idr_remove(&glink->rcids, cid); + } + + idr_destroy(&glink->lcids); + idr_destroy(&glink->rcids); + mutex_unlock(&glink->idr_lock); + + return ret; +} +EXPORT_SYMBOL(glink_bgcom_remove); + +static const struct of_device_id glink_bgcom_of_match[] = { + { .compatible = "qcom,glink-bgcom-xprt" }, + {} +}; +MODULE_DEVICE_TABLE(of, glink_bgcom_of_match); + +static struct platform_driver glink_bgcom_driver = { + .probe = glink_bgcom_probe, + .remove = glink_bgcom_remove, + .driver = { + .name = "qcom_glink_bgcom", + .of_match_table = glink_bgcom_of_match, + }, +}; + +static int __init glink_bgcom_init(void) +{ + return platform_driver_register(&glink_bgcom_driver); +} +postcore_initcall(glink_bgcom_init); + +static void __exit glink_bgcom_exit(void) +{ + platform_driver_unregister(&glink_bgcom_driver); +} +module_exit(glink_bgcom_exit); + +MODULE_DESCRIPTION("QTI GLINK BGCOM Transport"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 0fca3afa0618..4067035e1f64 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -723,7 +723,7 @@ config QCOM_GLINK config QCOM_GLINK_PKT tristate "Enable device interface for GLINK packet channels" - depends on QCOM_GLINK + depends on QCOM_GLINK || RPMSG_QCOM_GLINK_BGCOM help G-link packet driver provides the interface for the userspace clients to communicate over G-Link via device nodes. -- GitLab From 51f5bf87db9416c6f87f00ad8fd54cd98973387a Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Wed, 10 Jun 2020 18:41:46 +0530 Subject: [PATCH 1016/1055] ARM: dts: msm: Add glink bgcom dtsi node for sdm429 Add glink bgcom dtsi node for sdm429. Change-Id: Ie5b78cbd44829fbf222461b3ad41ec2d5222ea35 Signed-off-by: Prudhvi Yarlagadda --- arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi | 52 +++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi b/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi index 3d0406775a14..6ac3d71f82f5 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-bg-soc.dtsi @@ -45,4 +45,56 @@ ssr-reg1-supply = <&pm660_l3>; ssr-reg2-supply = <&pm660_l9>; }; + + qcom,glink-bgcom-xprt-bg { + compatible = "qcom,glink-bgcom-xprt"; + label = "bg"; + }; + + qcom,glink_pkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-bg-daemon { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "bg-daemon"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_daemon"; + }; + + qcom,glinkpkt-bg-daemon-ctrl { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "bg-daemon-ctl"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_daemon_ctrl"; + }; + + qcom,glinkpkt-bg-display-ctrl { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "display-ctrl"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_display_ctrl"; + }; + + qcom,glinkpkt-bg-display-data { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "display-data"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_display_data"; + }; + + qcom,glinkpkt-bg-rsb-ctrl { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "RSB_CTRL"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_rsb_ctrl"; + }; + + qcom,glinkpkt-bg-sso-ctrl { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "sso-ctrl"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_sso_ctrl"; + }; + + qcom,glinkpkt-bg-buzzer-ctrl { + qcom,glinkpkt-edge = "bg"; + qcom,glinkpkt-ch-name = "buzzer-ctrl"; + qcom,glinkpkt-dev-name = "glink_pkt_bg_buzzer_ctrl"; + }; + }; + }; -- GitLab From b6a650c99971e1ae80c27393b806af87d15a9fb4 Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Fri, 3 Jul 2020 20:13:38 +0530 Subject: [PATCH 1017/1055] ARM: dts: msm: Disable BAM mode for spi dtsi node Disable BAM mode for spi dtsi node which is used by bg. This is done to avoid the spi-BAM transaction timeouts that are happening only in BAM mode. Change-Id: I3585dc6002057b9e2f1ee1477c995c3b6642d6c9 Signed-off-by: Prudhvi Yarlagadda --- arch/arm64/boot/dts/qcom/sdm429-blsp.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm429-blsp.dtsi b/arch/arm64/boot/dts/qcom/sdm429-blsp.dtsi index 06f9e76d7983..e661a4f1db0b 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-blsp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-blsp.dtsi @@ -198,7 +198,6 @@ interrupts = <0 97 IRQ_TYPE_LEVEL_HIGH>, <0 238 IRQ_TYPE_LEVEL_HIGH>; spi-max-frequency = <50000000>; - qcom,use-bam; qcom,ver-reg-exists; qcom,bam-consumer-pipe-index = <8>; qcom,bam-producer-pipe-index = <9>; -- GitLab From a6fd3d7daf3e7e96af98fb17c3d80677bfecf1f6 Mon Sep 17 00:00:00 2001 From: Huicheng Liu Date: Fri, 3 Jul 2020 00:53:54 -0400 Subject: [PATCH 1018/1055] ARM: dts: qcom: vm: Add device nodes for second AFE rx and proxy tx devices * Add afe_proxy_tx_2 node for proxy capture frontend device. * Add afe_pcm_rx_2 node for afe playback backend device. * Add the new nodes to the ADP soundcard. Change-Id: Ie0f64fcbd1ff1d86107985a8ebe8c84776d2fb0f Signed-off-by: Han Lu --- arch/arm64/boot/dts/qcom/sa8155-vm-audio.dtsi | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-audio.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-audio.dtsi index ed42cb2d5ee6..3713d9262e23 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-audio.dtsi @@ -440,6 +440,20 @@ }; }; + qcom,msm-dai-q6 { + compatible = "qcom,msm-dai-q6"; + + afe_pcm_rx_1: qcom,msm-dai-q6-be-afe-pcm-rx-1 { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <226>; + }; + + afe_proxy_tx_1: qcom,msm-dai-q6-afe-proxy-tx-1 { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <242>; + }; + }; + qcom,avtimer@170f7000 { compatible = "qcom,avtimer"; reg = <0x170f700c 0x4>, @@ -482,10 +496,11 @@ <&dai_mi2s4>, <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, <&dai_quin_auxpcm>, - <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, - <&afe_proxy_tx>, <&incall_record_rx>, - <&incall_record_tx>, <&incall_music_rx>, - <&incall_music_2_rx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, + <&afe_proxy_rx>, <&afe_proxy_tx>, + <&afe_pcm_rx_1>, <&afe_proxy_tx_1>, + <&incall_record_rx>, <&incall_record_tx>, + <&incall_music_rx>, <&incall_music_2_rx>, <&usb_audio_rx>, <&usb_audio_tx>, <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_rx_1>, <&dai_pri_tdm_rx_2>, <&dai_pri_tdm_rx_3>, @@ -519,6 +534,7 @@ "msm-dai-q6-auxpcm.4", "msm-dai-q6-auxpcm.5", "msm-dai-q6-dev.224", "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", "msm-dai-q6-dev.240", + "msm-dai-q6-dev.226", "msm-dai-q6-dev.242", "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770", "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", -- GitLab From 69f55e049d7439920fb90df25537aefc58280356 Mon Sep 17 00:00:00 2001 From: Shubham Talekar Date: Tue, 30 Jun 2020 19:24:36 +0530 Subject: [PATCH 1019/1055] ARM: msm: dts: enable touch node for wearable Add raydium touch nodes in dtv2. Add pinctrl in its parent dtsi. Enable i2c_4 node to enable its slave. Change-Id: I6d0bd9651bb6692b04979a719fdfa48ae0366095 Signed-off-by: Shubham Talekar --- .../dts/qcom/sda429-bg-dvt2-wtp-overlay.dts | 27 +++++++ .../boot/dts/qcom/sda429-wtp-overlay.dts | 3 - .../dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts | 27 +++++++ arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi | 75 +++++++++++++++++++ .../boot/dts/qcom/sdm429-wtp-overlay.dts | 3 - 5 files changed, 129 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts index 898355091fdb..12fff714ca4a 100644 --- a/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sda429-bg-dvt2-wtp-overlay.dts @@ -24,3 +24,30 @@ qcom,pmic-id = <0x0002001b 0x0 0x0 0x0>; }; +&i2c_4 { + status = "ok"; + + raydium_ts@39 { + compatible = "raydium,raydium-ts"; + reg = <0x39>; + interrupt-parent = <&tlmm>; + interrupts = <13 0x2008>; + vdd_ana-supply = <&pm660_l11>; + vcc_i2c-supply = <&pm660_l13>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + raydium,reset-gpio = <&tlmm 64 0x00>; + raydium,irq-gpio = <&tlmm 65 0x00>; + raydium,num-max-touches = <2>; + raydium,soft-reset-delay-ms = <50>; + raydium,hard-reset-delay-ms = <100>; + raydium,x_max = <416>; + raydium,y_max = <416>; + raydium,display-coords= <0 0 416 416>; + raydium,fw_id = <0x2202>; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts index 138cb9e93292..4a5e4336eef7 100644 --- a/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sda429-wtp-overlay.dts @@ -26,9 +26,6 @@ &i2c_4 { status = "ok"; - tsc@24 { - status = "disabled"; - }; raydium_ts@39 { compatible = "raydium,raydium-ts"; diff --git a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts index 6f5cd9c5b07d..e655e2895daf 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts @@ -25,3 +25,30 @@ }; +&i2c_4 { + status = "ok"; + + raydium_ts@39 { + compatible = "raydium,raydium-ts"; + reg = <0x39>; + interrupt-parent = <&tlmm>; + interrupts = <13 0x2008>; + vdd_ana-supply = <&pm660_l11>; + vcc_i2c-supply = <&pm660_l13>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + raydium,reset-gpio = <&tlmm 64 0x00>; + raydium,irq-gpio = <&tlmm 65 0x00>; + raydium,num-max-touches = <2>; + raydium,soft-reset-delay-ms = <50>; + raydium,hard-reset-delay-ms = <100>; + raydium,x_max = <416>; + raydium,y_max = <416>; + raydium,display-coords= <0 0 416 416>; + raydium,fw_id = <0x2202>; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi index 292a515a9982..c07b29cd4d0d 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-pinctrl.dtsi @@ -904,5 +904,80 @@ }; }; }; + + pmx_ts_int_active { + ts_int_active: ts_int_active { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_active { + ts_reset_active: ts_reset_active { + mux { + pins = "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio64"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio64"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_release { + ts_release: ts_release { + mux { + pins = "gpio65", "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio65", "gpio64"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts index 403d0b7911af..68a8dbcf0c3a 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts @@ -45,9 +45,6 @@ &i2c_4 { status = "ok"; - tsc@24 { - status = "disabled"; - }; raydium_ts@39 { compatible = "raydium,raydium-ts"; -- GitLab From d1ba0190e19f53b1252ca5cc904af9262d40e2f1 Mon Sep 17 00:00:00 2001 From: Sanjay Dwivedi Date: Mon, 29 Jun 2020 13:19:00 +0530 Subject: [PATCH 1020/1055] ARM: dts: msm: Update mpss_adsp carved memory for sa515m platform New memory map is proposed for mapping 248 MB of memory to MPSS. Change-Id: I78daef916ce6f9aeb04560eab0ca889aa4a46a82 Signed-off-by: Sanjay Dwivedi --- arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi | 4 ++++ arch/arm64/boot/dts/qcom/sa515m-flashless.dtsi | 4 ++-- arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi b/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi index 5057a518c4c8..69f4da650cec 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi +++ b/arch/arm64/boot/dts/qcom/sa515m-ccard.dtsi @@ -80,6 +80,10 @@ }; }; +&mpss_adsp_mem { + reg = <0x90800000 0xf800000>; +}; + /* delete pm8150b nodes */ &thermal_zones { /delete-node/ pm8150b-wp-therm; diff --git a/arch/arm64/boot/dts/qcom/sa515m-flashless.dtsi b/arch/arm64/boot/dts/qcom/sa515m-flashless.dtsi index 13697f3235c6..9b3b3cf860d5 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-flashless.dtsi +++ b/arch/arm64/boot/dts/qcom/sa515m-flashless.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2019-2020, 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 @@ -13,7 +13,7 @@ #include "sdxprairie.dtsi" &mpss_adsp_mem { - reg = <0x90800000 0xdc00000>; + reg = <0x90800000 0xf800000>; }; &pil_modem { diff --git a/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi b/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi index ff584090a004..cd13e45e4145 100644 --- a/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi +++ b/arch/arm64/boot/dts/qcom/sa515m-v2-ttp.dtsi @@ -13,6 +13,10 @@ #include "sdxprairie-v2.dtsi" #include "sdxprairie-mtp.dtsi" +&mpss_adsp_mem { + reg = <0x90800000 0xf800000>; +}; + /* delete pm8150b nodes */ &thermal_zones { /delete-node/ pm8150b-wp-therm; -- GitLab From f5e8631a85e60f57f382a13e0deb50691e415e45 Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Sun, 5 Jul 2020 11:51:08 +0530 Subject: [PATCH 1021/1055] ARM: dts: sa2150p: remove incorrect msm-id inclusion QCS405 and SA2150P are quad core while QCS403 and SA2145P are dual core. There are separate device tree files for quad and dual core SoCs hence remove msm-id for dual core from quad core dtsi include file. Change-Id: I708a942076ebcfbcde2a4786175fb7a6166c23b5 Signed-off-by: Rishi Gupta --- arch/arm64/boot/dts/qcom/qcs405.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs405.dtsi b/arch/arm64/boot/dts/qcom/qcs405.dtsi index e405bf8a6226..dfbb2146b1c9 100644 --- a/arch/arm64/boot/dts/qcom/qcs405.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs405.dtsi @@ -28,7 +28,7 @@ / { model = "Qualcomm Technologies, Inc. QCS405"; compatible = "qcom,qcs405"; - qcom,msm-id = <352 0x0>, <451 0x0>, <452 0x0>; + qcom,msm-id = <352 0x0>, <452 0x0>; interrupt-parent = <&wakegic>; chosen { -- GitLab From 864ddaf82fbbef1965c1e9a957994bd8fa9fc199 Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Sun, 5 Jul 2020 13:09:44 +0530 Subject: [PATCH 1022/1055] ARM: dts: sa2145p: add msm-id for sa2145p chip The qcs403.dtsi file can be common for both SoCs qcs403 and sa2145p hence add msm-id for sa2145p in qcs403.dtsi file itself. Change-Id: I5c6eb00c37e8f5b62115fbdd1bd21c22490e8fbc Signed-off-by: Rishi Gupta --- arch/arm64/boot/dts/qcom/qcs403.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs403.dtsi b/arch/arm64/boot/dts/qcom/qcs403.dtsi index 70f1c135f7db..0bf174ea10ce 100644 --- a/arch/arm64/boot/dts/qcom/qcs403.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs403.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2020, 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 @@ -16,7 +16,7 @@ / { model = "Qualcomm Technologies, Inc. QCS403"; qcom,msm-name = "QCS403"; - qcom,msm-id = <373 0x0>; + qcom,msm-id = <373 0x0>, <451 0x0>; cpus { /delete-node/ cpu@102; -- GitLab From 5f2987eeb1e9f9041c3bfcf46725d1bb8406256b Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Tue, 23 Jun 2020 16:09:32 +0530 Subject: [PATCH 1023/1055] defconfig: sdm429: Add MPROC GLINK defconfig for SDM429W Enable the MPROC drivers like BGCOM_Glink and glink_pkt for SDM429W. Change-Id: I197f7c17f9ab746075a1efcb5b3ee08ee8ca4ced Signed-off-by: Prudhvi Yarlagadda --- arch/arm/configs/vendor/sdm429-bg-perf_defconfig | 2 ++ arch/arm/configs/vendor/sdm429-bg_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig index ab40f32e345b..3926873c112d 100644 --- a/arch/arm/configs/vendor/sdm429-bg-perf_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg-perf_defconfig @@ -517,6 +517,7 @@ CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_BGCOM=y CONFIG_RPMSG_QCOM_SMD=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y @@ -553,6 +554,7 @@ CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_EARLY_RANDOM=y CONFIG_MSM_TZ_SMMU=y CONFIG_QSEE_IPC_IRQ=y +CONFIG_QCOM_GLINK_PKT=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y CONFIG_QCOM_SMCINVOKE=y diff --git a/arch/arm/configs/vendor/sdm429-bg_defconfig b/arch/arm/configs/vendor/sdm429-bg_defconfig index 158a5ab5fdbc..269cb6d33864 100644 --- a/arch/arm/configs/vendor/sdm429-bg_defconfig +++ b/arch/arm/configs/vendor/sdm429-bg_defconfig @@ -535,6 +535,7 @@ CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_BGCOM=y CONFIG_RPMSG_QCOM_SMD=y CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y @@ -577,6 +578,7 @@ CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_EARLY_RANDOM=y CONFIG_MSM_TZ_SMMU=y CONFIG_QSEE_IPC_IRQ=y +CONFIG_QCOM_GLINK_PKT=y # CONFIG_MSM_JTAGV8 is not set CONFIG_QTI_RPM_STATS_LOG=y CONFIG_MSM_CDSP_LOADER=y -- GitLab From 33bfbc5fa8e16c47f2fe40432c79888690489b83 Mon Sep 17 00:00:00 2001 From: Saurabh Sahu Date: Tue, 7 Jul 2020 10:22:04 +0530 Subject: [PATCH 1024/1055] clk: qcom: smd_rpm: Change rpm clk_id for SDM429 Change the rpm clock id for the sysmmnoc clk for SDM429 target. Change-Id: I436bb37ab786d4cde4aa7573b38a35009362a999 Signed-off-by: Saurabh Sahu --- drivers/clk/qcom/clk-smd-rpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index 895ee8f81eff..6d3b3b548ec2 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -1003,7 +1003,7 @@ DEFINE_CLK_SMD_RPM(sdm429w, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1); DEFINE_CLK_SMD_RPM(sdm429w, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0); DEFINE_CLK_SMD_RPM(sdm429w, sysmmnoc_clk, sysmmnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, - 0); + 2); DEFINE_CLK_SMD_RPM_QDSS(sdm429w, qdss_clk, qdss_a_clk, QCOM_SMD_RPM_MISC_CLK, 1); -- GitLab From 77caa236389b65557b5886fc83928997a32f6f33 Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Tue, 16 Jun 2020 14:25:41 +0530 Subject: [PATCH 1025/1055] soc: qcom: sideband: add helper APIs for sideband notifications This commit introduces helper APIs and header file to be used by sideband events publishers and subscribers. Communication is through standard kernel APIs. Change-Id: I12114bdf3e1e0e6c3fe0677e313bd7ad8e1649b7 Signed-off-by: Rishi Gupta --- drivers/soc/qcom/Kconfig | 9 +++++ drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/sideband_notify.c | 50 ++++++++++++++++++++++++++ include/soc/qcom/sb_notification.h | 57 ++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+) create mode 100644 drivers/soc/qcom/sideband_notify.c create mode 100644 include/soc/qcom/sb_notification.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 0fca3afa0618..f8fb47546a47 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -525,6 +525,15 @@ config SDX_EXT_IPC If unsure, say N. +config QTI_NOTIFY_SIDEBAND + tristate "QCOM sideband signalling helper" + help + This provides helper APIs and a header file through which + transport layer driver can talk to the sideband driver to + assert appropriate sideband signal. + + If unsure, say N. + config PANIC_ON_GLADIATOR_ERROR depends on MSM_GLADIATOR_ERP bool "Panic on GLADIATOR error report" diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 64316c5dfe17..9c2a3fb9fd36 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_MSM_CDSP_LOADER) += qdsp6v2/ obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o obj-$(CONFIG_SDX_EXT_IPC) += sdx_ext_ipc.o obj-$(CONFIG_MSM_PIL_SSR_BG) += subsys-pil-bg.o +obj-$(CONFIG_QTI_NOTIFY_SIDEBAND) += sideband_notify.o ifdef CONFIG_MSM_SUBSYSTEM_RESTART obj-y += subsystem_notif.o diff --git a/drivers/soc/qcom/sideband_notify.c b/drivers/soc/qcom/sideband_notify.c new file mode 100644 index 000000000000..190720329405 --- /dev/null +++ b/drivers/soc/qcom/sideband_notify.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020, 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 + +static BLOCKING_NOTIFIER_HEAD(sb_notifier_list); + +/** + * sb_register_evt_listener - registers a notifier callback + * @nb: pointer to the notifier block for the callback events + */ +int sb_register_evt_listener(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&sb_notifier_list, nb); +} +EXPORT_SYMBOL(sb_register_evt_listener); + +/** + * sb_unregister_evt_listener - un-registers a notifier callback + * registered previously. + * @nb: pointer to the notifier block for the callback events + */ +int sb_unregister_evt_listener(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&sb_notifier_list, nb); +} +EXPORT_SYMBOL(sb_unregister_evt_listener); + +/** + * sb_notifier_call_chain - send events to all registered listeners + * as received from publishers. + * @nb: pointer to the notifier block for the callback events + */ +int sb_notifier_call_chain(unsigned long val, void *v) +{ + return blocking_notifier_call_chain(&sb_notifier_list, val, v); +} +EXPORT_SYMBOL(sb_notifier_call_chain); diff --git a/include/soc/qcom/sb_notification.h b/include/soc/qcom/sb_notification.h new file mode 100644 index 000000000000..20bbe7334419 --- /dev/null +++ b/include/soc/qcom/sb_notification.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020, 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 _SB_NOTIFICATION_H +#define _SB_NOTIFICATION_H + +/* Indicates a system wake up event */ +#define EVT_WAKE_UP 0x01 + +#ifdef CONFIG_QTI_NOTIFY_SIDEBAND +/** + * sb_register_evt_listener - registers a notifier callback + * @nb: pointer to the notifier block for the callback events + */ +int sb_register_evt_listener(struct notifier_block *nb); + +/** + * sb_unregister_evt_listener - un-registers a notifier callback + * registered previously. + * @nb: pointer to the notifier block for the callback events + */ +int sb_unregister_evt_listener(struct notifier_block *nb); + +/** + * sb_notifier_call_chain - send events to all registered listeners + * as received from publishers. + * @nb: pointer to the notifier block for the callback events + */ +int sb_notifier_call_chain(unsigned long val, void *v); + +#else +static inline int sb_register_evt_listener(struct notifier_block *nb) +{ + return -EINVAL; +} +static inline int sb_unregister_evt_listener(struct notifier_block *nb) +{ + return -EINVAL; +} +static inline int sb_notifier_call_chain(unsigned long val, void *v) +{ + return -EINVAL; +} +#endif /* !CONFIG_QTI_NOTIFY_SIDEBAND */ + +#endif /* _SB_NOTIFICATION_H */ -- GitLab From d04c9a84d4dc34257092b6ca2dfdf03f33fb75fb Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Mon, 29 Jun 2020 11:48:05 +0530 Subject: [PATCH 1026/1055] defconfig: sa515m: enable helper APIs for sideband notifications This commit enables driver which provides helper APIs so that transport layer drivers like USB can talk to sideband driver using kernel notifiers mechanism. Change-Id: Ifb6e4c2d89783aad61f4aaa91cee0e9a10e19135 Signed-off-by: Rishi Gupta --- arch/arm/configs/vendor/sa515m-perf_defconfig | 1 + arch/arm/configs/vendor/sa515m_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/vendor/sa515m-perf_defconfig b/arch/arm/configs/vendor/sa515m-perf_defconfig index 5135e90bc2a3..8b002ff2c108 100644 --- a/arch/arm/configs/vendor/sa515m-perf_defconfig +++ b/arch/arm/configs/vendor/sa515m-perf_defconfig @@ -402,6 +402,7 @@ CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_DCC_V2=y CONFIG_SDX_EXT_IPC=y +CONFIG_QTI_NOTIFY_SIDEBAND=y CONFIG_QCOM_SECURE_BUFFER=y CONFIG_QCOM_EUD=y CONFIG_QCOM_BUS_SCALING=y diff --git a/arch/arm/configs/vendor/sa515m_defconfig b/arch/arm/configs/vendor/sa515m_defconfig index 7139ab69238e..98c80cfb7720 100644 --- a/arch/arm/configs/vendor/sa515m_defconfig +++ b/arch/arm/configs/vendor/sa515m_defconfig @@ -407,6 +407,7 @@ CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_DCC_V2=y CONFIG_SDX_EXT_IPC=y +CONFIG_QTI_NOTIFY_SIDEBAND=y CONFIG_QCOM_SECURE_BUFFER=y CONFIG_QCOM_EUD=y CONFIG_QCOM_BUS_SCALING=y -- GitLab From eba978f5a5684f38c635a018b86b0b4c738c4eea Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Sun, 5 Jul 2020 17:00:00 +0530 Subject: [PATCH 1027/1055] ARM: dts: sa2145p: add support for NAND based SOM This commit adds initial device tree required for sa2145p based SOM having NAND storage. Change-Id: I2341bf73cc07aeb9d4ac38b6781ee3e56e371086 Signed-off-by: Rishi Gupta --- .../devicetree/bindings/arm/msm/msm.txt | 4 + arch/arm64/boot/dts/qcom/Makefile | 1 + .../boot/dts/qcom/sa2145p-ccard-nand-dc.dts | 30 ++ arch/arm64/boot/dts/qcom/sa2145p-ccard.dtsi | 296 ++++++++++++++++++ 4 files changed, 331 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts create mode 100644 arch/arm64/boot/dts/qcom/sa2145p-ccard.dtsi diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index 2f70a74ddd54..fc67586e70a1 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -112,6 +112,9 @@ SoCs: - QCS6125 compatible = "qcom,qcs6125" +- SA2145P + compatible = "qcom,sa2145p" + Generic board variants: - CDP device: @@ -229,6 +232,7 @@ compatible = "qcom,sa6155p-adp-air" compatible = "qcom,qcs405-rumi" compatible = "qcom,qcs405-iot" compatible = "qcom,sa2150p-ccard" +compatible = "qcom,sa2145p-ccard" compatible = "qcom,qcs403-iot" compatible = "qcom,qcs401-iot" compatible = "qcom,qcs404-iot" diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index b2d9cacbd674..f7d79f43c7dc 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -102,6 +102,7 @@ dtb-$(CONFIG_ARCH_QCS405) += qcs405-iot-sku1.dtb \ qcs405-iot-sku12.dtb \ qcs407-iot-sku12.dtb \ sa2150p-ccard-emmc.dtb \ + sa2145p-ccard-nand-dc.dtb \ sa2150p-ccard-nand.dtb \ qcs405-iot-sku13.dtb \ qcs407-iot-sku13.dtb \ diff --git a/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts b/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts new file mode 100644 index 000000000000..125df3f74061 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts @@ -0,0 +1,30 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "sa2145p-ccard.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA2145P CCARD NAND DC"; + compatible = "qcom,sa2145p-ccard", "qcom,qcs403", "qcom,sa2145p", + "qcom,ccard"; + qcom,board-id = <25 2>, <25 0x102>; +}; + +&qnand_1 { + status = "okay"; +}; + +&sdhc_1 { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/sa2145p-ccard.dtsi b/arch/arm64/boot/dts/qcom/sa2145p-ccard.dtsi new file mode 100644 index 000000000000..fe397be6067b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa2145p-ccard.dtsi @@ -0,0 +1,296 @@ +/* Copyright (c) 2020, 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 "qcs403.dtsi" + +&tlmm { + pinctrl-0 = <&status_gpio>; + pinctrl-names = "default"; + status_gpio: status_gpio { + ap2mdm_status { + pins = "gpio80"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + output-high; + }; + }; +}; + +&pcie0_perst_default { + mux { + pins = "gpio107"; + function = "gpio"; + }; + + config { + pins = "gpio107"; + drive-strength = <2>; + bias-disable; + }; +}; + +&pcie0_wake_default { + mux { + pins = "gpio115"; + function = "gpio"; + }; + + config { + pins = "gpio115"; + drive-strength = <2>; + bias-pull-down; + }; +}; + +&usb3_id_det_default { + mux { + pins = "gpio113"; + function = "gpio"; + }; + + config { + pins = "gpio113"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; +}; + +&spi_1 { + status = "disabled"; +}; + +&i2c_3 { + status = "disabled"; +}; + +&smb1351_otg_supply { + status = "disabled"; +}; + +&cnss_sdio { + status = "disabled"; +}; + +&spi_2 { + status = "okay"; + + can-controller@0 { + compatible = "qcom,nxp,mpc5746c"; + reg = <0>; + interrupt-parent = <&tlmm>; + interrupts = <34 0>; + spi-max-frequency = <5000000>; + qcom,clk-freq-mhz = <40000000>; + qcom,max-can-channels = <2>; + qcom,bits-per-word = <8>; + qcom,support-can-fd; + }; +}; + +&spi_6 { + status = "okay"; + + spidev0: spidev@0 { + compatible = "qcom,spi-msm-codec-slave"; + reg = <0>; + spi-max-frequency = <50000000>; + }; +}; + +&i2c_5 { + status = "okay"; + qcom,clk-freq-out = <100000>; +}; + +&soc { + gpio_keys { + status = "disabled"; + }; + + vreg_emac_phy: emac_phy_regulator { + compatible = "regulator-fixed"; + regulator-name = "emac_phy"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-enable-ramp-delay = <100>; + gpio = <&tlmm 92 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + vreg_rgmii_io_pads: rgmii_io_pads_regulator { + compatible = "regulator-fixed"; + regulator-name = "rgmii_io_pads"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <100>; + gpio = <&tlmm 15 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + usb2_extcon: usb2_extcon { + compatible = "linux,extcon-usb-gpio"; + id-gpio = <&tlmm 53 GPIO_ACTIVE_HIGH>; + vbus-gpio = <&tlmm 116 GPIO_ACTIVE_HIGH>; + vbus-out-gpio = <&tlmm 108 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&usb2_vbus_det_default + &usb2_id_det_default + &usb2_vbus_boost_default>; + }; + + pps { + compatible = "pps-gpio"; + gpios = <&tlmm 96 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; + + qmi-tmd-devices { + adsp { + qcom,instance-id = <0x1>; + + adsp_vdd: adsp-vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; +}; + +&thermal_zones { + aoss-lowf { + cooling-maps { + adsp_vdd_cdev { + trip = <&aoss_lowf>; + cooling-device = <&adsp_vdd 0 0>; + }; + }; + }; +}; + +&usb3 { + qcom,ignore-wakeup-src-in-hostmode; +}; + +&usb3_extcon { + id-gpio = <&tlmm 113 GPIO_ACTIVE_HIGH>; +}; + +&usb2s { + extcon = <&usb2_extcon>; +}; + +ðqos_hw { + status = "okay"; + vreg_emac_phy-supply = <&vreg_emac_phy>; + vreg_rgmii_io_pads-supply = <&vreg_rgmii_io_pads>; + rxc-skew-ps = <0>; + + pinctrl-names = "dev-emac-mdc", "dev-emac-mdio", + "dev-emac-rgmii_txd0_state", "dev-emac-rgmii_txd1_state", + "dev-emac-rgmii_txd2_state", "dev-emac-rgmii_txd3_state", + "dev-emac-rgmii_txc_state", "dev-emac-rgmii_tx_ctl_state", + "dev-emac-rgmii_rxd0_state", "dev-emac-rgmii_rxd1_state", + "dev-emac-rgmii_rxd2_state", "dev-emac-rgmii_rxd3_state", + "dev-emac-rgmii_rxc_state", "dev-emac-rgmii_rx_ctl_state", + "dev-emac-phy_intr", "dev-emac-phy_reset_state"; + pinctrl-15 = <&emac_phy_reset_state>; +}; + +&emac_hw { + status = "okay"; + vreg_emac_phy-supply = <&vreg_emac_phy>; + vreg_rgmii_io_pads-supply = <&vreg_rgmii_io_pads>; + qcom,phy-reset-delay-msecs = <10>; + rxc-skew-ps = <0>; + + pinctrl-names = "dev-emac-mdc", "dev-emac-mdio", + "dev-emac-rgmii_txd0_state", "dev-emac-rgmii_txd1_state", + "dev-emac-rgmii_txd2_state", "dev-emac-rgmii_txd3_state", + "dev-emac-rgmii_txc_state", "dev-emac-rgmii_tx_ctl_state", + "dev-emac-rgmii_rxd0_state", "dev-emac-rgmii_rxd1_state", + "dev-emac-rgmii_rxd2_state", "dev-emac-rgmii_rxd3_state", + "dev-emac-rgmii_rxc_state", "dev-emac-rgmii_rx_ctl_state", + "dev-emac-phy_intr", "dev-emac-phy_reset_state"; + pinctrl-15 = <&emac_phy_reset_state>; +}; + +&pcie0 { + pinctrl-0 = <&pcie0_perst_default + &pcie0_wake_default>; + + perst-gpio = <&tlmm 107 0>; + wake-gpio = <&tlmm 115 0>; +}; + +&sdhc_2 { + /delete-property/ qcom,nonhotplug; + /delete-property/ qcom,nonremovable; + + vdd-io-supply = <&pms405_l11>; + qcom,vdd-io-voltage-level = <2950000 2950000>; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_cd_off>; + cd-gpios = <&tlmm 21 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&gpu_bw_tbl { + status = "disabled"; +}; + +&gpubw { + status = "disabled"; +}; + +&msm_gpu { + status = "disabled"; +}; + +&kgsl_msm_iommu { + status = "disabled"; +}; + +&rpm_bus { + rpm-regulator-ldoa1 { + status = "disabled"; + pms405_l1: regulator-l1 { + status = "disabled"; + }; + }; + + rpm-regulator-ldoa2 { + status = "disabled"; + pms405_l2: regulator-l2 { + status = "disabled"; + }; + }; + + rpm-regulator-ldoa7 { + status = "disabled"; + pms405_l7: regulator-l7 { + status = "disabled"; + }; + }; + + rpm-regulator-ldoa10 { + status = "disabled"; + pms405_l10: regulator-l10 { + status = "disabled"; + }; + }; +}; -- GitLab From 9b1b1dbd970b407638e0cc8b086c61f6751a6edf Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Sun, 5 Jul 2020 17:18:12 +0530 Subject: [PATCH 1028/1055] ARM: dts: sa2150p: add support for NAND based SOM This commit adds initial device tree required for sa2150p based SOM having NAND storage. Although the SoC is quad core but it is made to operate in dual core mode as board's PDN specifications are exceeded. Change-Id: Ie32687222e817b325833e55dd9cc16477ced7e5c Signed-off-by: Rishi Gupta --- .../devicetree/bindings/arm/msm/msm.txt | 3 + arch/arm64/boot/dts/qcom/Makefile | 1 + .../boot/dts/qcom/sa2150p-ccard-nand-dc.dts | 98 +++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index fc67586e70a1..5b614f215d22 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -115,6 +115,9 @@ SoCs: - SA2145P compatible = "qcom,sa2145p" +- SA2150P + compatible = "qcom,sa2150p" + Generic board variants: - CDP device: diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index f7d79f43c7dc..afd6433706da 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -103,6 +103,7 @@ dtb-$(CONFIG_ARCH_QCS405) += qcs405-iot-sku1.dtb \ qcs407-iot-sku12.dtb \ sa2150p-ccard-emmc.dtb \ sa2145p-ccard-nand-dc.dtb \ + sa2150p-ccard-nand-dc.dtb \ sa2150p-ccard-nand.dtb \ qcs405-iot-sku13.dtb \ qcs407-iot-sku13.dtb \ diff --git a/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts b/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts new file mode 100644 index 000000000000..825766f25f94 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts @@ -0,0 +1,98 @@ +/* Copyright (c) 2020, 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. + */ + +/dts-v1/; + +#include "sa2150p-ccard.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SA2150P CCARD NAND DC"; + compatible = "qcom,sa2150p-ccard", "qcom,qcs405", "qcom,sa2150p", + "qcom,ccard"; + qcom,board-id = <25 2>, <25 0x102>; + + cpus { + /delete-node/ cpu@102; + /delete-node/ cpu@103; + + cpu-map { + cluster0 { + /delete-node/ core2; + /delete-node/ core3; + }; + }; + }; +}; + +&soc { + cpuss_dump { + /delete-node/ qcom,l1_i_cache102; + /delete-node/ qcom,l1_i_cache103; + /delete-node/ qcom,l1_d_cache102; + /delete-node/ qcom,l1_d_cache103; + }; + + qcom,spm@b012000 { + qcom,cpu-vctl-list = <&CPU0 &CPU1>; + }; + + qcom,lpm-levels { + qcom,pm-cluster@0{ + qcom,pm-cpu { + qcom,cpu = <&CPU0 &CPU1>; + }; + }; + }; + + /delete-node/ cti@61ba000; + /delete-node/ cti@61bb000; + /delete-node/ etm@61be000; + /delete-node/ etm@61bf000; + + funnel@61a1000 { + ports { + /delete-node/ port@3; + /delete-node/ port@4; + }; + }; + + /delete-node/ qcom,cpu0-computemon; + + cpu0_computemon: qcom,cpu0-computemon { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU0 &CPU1>; + qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 1094400 MHZ_TO_MBPS( 297, 8) >, + < 1248000 MHZ_TO_MBPS( 597, 8) >, + < 1401600 MHZ_TO_MBPS( 710, 8) >; + }; +}; + +&thermal_zones { + cpuss-max-step { + cooling-maps { + /delete-node/ cpu2_cdev; + /delete-node/ cpu3_cdev; + }; + }; + /delete-node/ cpuss-2-step; + /delete-node/ cpuss-3-step; +}; + +&qnand_1 { + status = "okay"; +}; + +&sdhc_1 { + status = "disabled"; +}; -- GitLab From d5d8a16f438fe3f3a8debe29f730a240bf809e4b Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Sun, 5 Jul 2020 21:49:38 +0530 Subject: [PATCH 1029/1055] ARM: dts: sa2150p: enable BLSP0 UART and free up GPIO 83 The commit disables BLSP3 to be used as UART to free up GPIO 83 to be used for other purpose. Additionally, it enables BLSP0 to be used as standard UART. Change-Id: I472f93e8d946e42ea3dd89ccb2b834c308377377 Signed-off-by: Rishi Gupta --- arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts | 8 ++++++++ arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts b/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts index 125df3f74061..3ebad18c8340 100644 --- a/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts +++ b/arch/arm64/boot/dts/qcom/sa2145p-ccard-nand-dc.dts @@ -28,3 +28,11 @@ &sdhc_1 { status = "disabled"; }; + +&blsp1_uart1_hs { + status = "ok"; +}; + +&blsp1_uart4_hs { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts b/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts index 825766f25f94..a6183bd11c49 100644 --- a/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts +++ b/arch/arm64/boot/dts/qcom/sa2150p-ccard-nand-dc.dts @@ -96,3 +96,11 @@ &sdhc_1 { status = "disabled"; }; + +&blsp1_uart1_hs { + status = "ok"; +}; + +&blsp1_uart4_hs { + status = "disabled"; +}; -- GitLab From 083dd7168bef74ee8edf6d357e7edd7058fe5cea Mon Sep 17 00:00:00 2001 From: Jiacheng Zheng Date: Tue, 7 Jul 2020 19:18:05 +0800 Subject: [PATCH 1030/1055] mm/memblock.c: fix bug in early_dyn_memhotplug memblock.memory.cnt will decrease if we remove all memory blocks in a region. We will lose the next region in this condition. The solution is we save memblock.memory.cnt before we scan through a region and compare the new counter with the old one after that, we decrease the idx if we find counter changes. This way, we are always using the correct idx before we enter next loop. Change-Id: Id6bf83497f1048cf614e50e23484f2dea7ffcd07 Signed-off-by: Jiacheng Zheng --- mm/memblock.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mm/memblock.c b/mm/memblock.c index deaf4c018e1e..dc202c7702c8 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -1833,12 +1833,14 @@ static bool __init memblock_in_no_hotplug_area(phys_addr_t addr) static int __init early_dyn_memhotplug(char *p) { - int idx = 0; + unsigned long idx = 0; + unsigned long old_cnt; phys_addr_t addr, rgn_end; struct memblock_region *rgn; int blk = 0; while (idx < memblock.memory.cnt) { + old_cnt = memblock.memory.cnt; rgn = &memblock.memory.regions[idx++]; addr = ALIGN(rgn->base, MIN_MEMORY_BLOCK_SIZE); rgn_end = rgn->base + rgn->size; @@ -1849,6 +1851,8 @@ static int __init early_dyn_memhotplug(char *p) } addr += MIN_MEMORY_BLOCK_SIZE; } + if (old_cnt != memblock.memory.cnt) + idx--; } return 0; } -- GitLab From e91f53103432e1dcb7baad8ffe803567e34a74e0 Mon Sep 17 00:00:00 2001 From: Yadu MG Date: Tue, 7 Jul 2020 17:25:36 +0530 Subject: [PATCH 1031/1055] soc: qcom: dcc_v2: Add NULL check before using dcc driver data Add NULL check to avoid potential NULL pointer dereference in restore pm callback. Change-Id: I6457ef2135b6ab9af7fcbd95c5b668b68ac1e088 Signed-off-by: Yadu MG --- drivers/soc/qcom/dcc_v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c index d7cd6e074db6..4ce4eb0bddb3 100644 --- a/drivers/soc/qcom/dcc_v2.c +++ b/drivers/soc/qcom/dcc_v2.c @@ -1923,7 +1923,7 @@ static int dcc_v2_restore(struct device *dev) struct dcc_save_state *state; struct dcc_drvdata *drvdata = dev_get_drvdata(dev); - if (!drvdata && !drvdata->sram_save_state && !drvdata->reg_save_state) + if (!drvdata || !drvdata->sram_save_state || !drvdata->reg_save_state) return -EINVAL; data = drvdata->sram_save_state; -- GitLab From 0ae816bcac11f87403ac9d18f7ab11a93b4ee6e6 Mon Sep 17 00:00:00 2001 From: Venkata Prahlad Valluru Date: Wed, 10 Jun 2020 12:40:00 +0530 Subject: [PATCH 1032/1055] ARM: dts: qcom: update display dts nodes for sdm429w WTP Add board specific dt nodes and update MDSS nodes. Change-Id: I54b4f536f863b3a5d92dae6f7bcde07b44ae6ff3 Signed-off-by: Venkata Prahlad Valluru --- .../dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts | 54 ++++++++++++++++++- arch/arm64/boot/dts/qcom/sdm429-mdss.dtsi | 11 ++-- .../boot/dts/qcom/sdm429-wtp-overlay.dts | 34 ++++++++++++ 3 files changed, 92 insertions(+), 7 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts index e655e2895daf..c71211fd8edb 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-bg-dvt2-wtp-overlay.dts @@ -15,6 +15,7 @@ /plugin/; #include "sdm429-bg-dvt2-wtp.dtsi" +#include "sdm429-mdss-panels.dtsi" / { model = "Qualcomm Technologies, Inc. SDM429 QRD BG WTP Overlay"; @@ -25,6 +26,58 @@ }; +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + /delete-property/ vdda-supply; + /delete-property/ vddio-supply; + vdda-supply = <&L6A>; /* 0.8v */ + vddio-supply = <&L13A>; /* 1.8v */ + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda"; + qcom,supply-min-voltage = <800000>; + qcom,supply-max-voltage = <800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_auo_416p_amoled_cmd>; + /delete-property/ vdd-supply; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_te_active>; + pinctrl-1 = <&mdss_te_suspend>; + vddio-supply = <&L11A>; + qcom,platform-te-gpio = <&tlmm 24 0>; + qcom,platform-reset-gpio = <&tlmm 60 0>; + qcom,platform-enable-gpio = <&pm660_gpios 12 0>; + +}; + +&mdss_dsi0_pll { + /delete-property/ vddio-supply; + vddio-supply = <&L13A>; +}; + +&mdss_dsi1 { + status = "disabled"; +}; + +&mdss_dsi1_pll { + status = "disabled"; +}; + &i2c_4 { status = "ok"; @@ -51,4 +104,3 @@ raydium,fw_id = <0x2202>; }; }; - diff --git a/arch/arm64/boot/dts/qcom/sdm429-mdss.dtsi b/arch/arm64/boot/dts/qcom/sdm429-mdss.dtsi index a6e35db6f54c..c6452438728a 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-mdss.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-mdss.dtsi @@ -185,12 +185,11 @@ <22 512 0 1000>; }; - /*TODO*/ smmu_mdp_unsec: qcom,smmu_mdp_unsec_cb { compatible = "qcom,smmu_mdp_unsec"; iommus = <&apps_iommu 0x2800 0>; /* For NS ctx bank */ }; - /*TODO*/ + smmu_mdp_sec: qcom,smmu_mdp_sec_cb { compatible = "qcom,smmu_mdp_sec"; iommus = <&apps_iommu 0x2801 0>; /* For SEC Ctx Bank */ @@ -243,10 +242,10 @@ clocks = <&gcc_mdss MDSS_MDP_VOTE_CLK>, <&gcc GCC_MDSS_AHB_CLK>, <&gcc GCC_MDSS_AXI_CLK>, - <&gcc_mdss BYTE0_CLK_SRC>, /*TODO*/ - <&gcc_mdss BYTE1_CLK_SRC>, /*TODO*/ - <&gcc_mdss PCLK0_CLK_SRC>, /*TODO*/ - <&gcc_mdss PCLK1_CLK_SRC>; /*TODO*/ + <&mdss_dsi0_pll BYTE_CLK_SRC_0_CLK>, + <&mdss_dsi1_pll BYTE_CLK_SRC_1_CLK>, + <&mdss_dsi0_pll PCLK_SRC_MUX_0_CLK>, + <&mdss_dsi1_pll PCLK_SRC_MUX_1_CLK>; clock-names = "mdp_core_clk", "iface_clk", "bus_clk", "ext_byte0_clk", "ext_byte1_clk", "ext_pixel0_clk", "ext_pixel1_clk"; diff --git a/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts index 68a8dbcf0c3a..b324f0c7bed8 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-wtp-overlay.dts @@ -29,6 +29,28 @@ qcom,mdss-pref-prim-intf = "dsi"; }; +&mdss_dsi { + /delete-property/ vdda-supply; + /delete-property/ vddio-supply; + vdda-supply = <&L6A>; /* 0.8v */ + vddio-supply = <&L13A>; /* 1.8v */ + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda"; + qcom,supply-min-voltage = <800000>; + qcom,supply-max-voltage = <800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; + }; +}; + &mdss_dsi0 { qcom,dsi-pref-prim-pan = <&dsi_auo_416p_amoled_cmd>; /delete-property/ vdd-supply; @@ -36,13 +58,25 @@ pinctrl-0 = <&mdss_te_active>; pinctrl-1 = <&mdss_te_suspend>; vddio-supply = <&L11A>; + qcom,platform-te-gpio = <&tlmm 24 0>; + qcom,platform-reset-gpio = <&tlmm 60 0>; qcom,platform-enable-gpio = <&pm660_gpios 12 0>; + +}; + +&mdss_dsi0_pll { + /delete-property/ vddio-supply; + vddio-supply = <&L13A>; }; &mdss_dsi1 { status = "disabled"; }; +&mdss_dsi1_pll { + status = "disabled"; +}; + &i2c_4 { status = "ok"; -- GitLab From d13c5f0e57a3d23430febc7d3bd1eb84a6a8e9ed Mon Sep 17 00:00:00 2001 From: Naohiro Aota Date: Sat, 28 Mar 2020 00:28:08 -0700 Subject: [PATCH 1033/1055] mm/swapfile.c: move inode_lock out of claim_swapfile claim_swapfile() currently keeps the inode locked when it is successful, or the file is already swapfile (with -ebusy). and, on the other error cases, it does not lock the inode. this inconsistency of the lock state and return value is quite confusing and actually causing a bad unlock balance as below in the "bad_swap" section of __do_sys_swapon(). this commit fixes this issue by moving the inode_lock() and is_swapfile check out of claim_swapfile(). the inode is unlocked in "bad_swap_unlock_inode" section, so that the inode is ensured to be unlocked at "bad_swap". thus, error handling codes after the locking now jumps to "bad_swap_unlock_inode" instead of "bad_swap". ===================================== warning: bad unlock balance detected! 5.5.0-rc7+ #176 not tainted ------------------------------------- swapon/4294 is trying to release lock (&sb->s_type->i_mutex_key) at: [] __do_sys_swapon+0x94b/0x3550 but there are no more locks to release! other info that might help us debug this: no locks held by swapon/4294. stack backtrace: cpu: 5 pid: 4294 comm: swapon not tainted 5.5.0-rc7-btrfs-zns+ #176 hardware name: asus all series/h87-pro, bios 2102 07/29/2014 call trace: dump_stack+0xa1/0xea ? __do_sys_swapon+0x94b/0x3550 print_unlock_imbalance_bug.cold+0x114/0x123 ? __do_sys_swapon+0x94b/0x3550 lock_release+0x562/0xed0 ? kvfree+0x31/0x40 ? lock_downgrade+0x770/0x770 ? kvfree+0x31/0x40 ? rcu_read_lock_sched_held+0xa1/0xd0 ? rcu_read_lock_bh_held+0xb0/0xb0 up_write+0x2d/0x490 ? kfree+0x293/0x2f0 __do_sys_swapon+0x94b/0x3550 ? putname+0xb0/0xf0 ? kmem_cache_free+0x2e7/0x370 ? do_sys_open+0x184/0x3e0 ? generic_max_swapfile_size+0x40/0x40 ? do_syscall_64+0x27/0x4b0 ? entry_syscall_64_after_hwframe+0x49/0xbe ? lockdep_hardirqs_on+0x38c/0x590 __x64_sys_swapon+0x54/0x80 do_syscall_64+0xa4/0x4b0 entry_syscall_64_after_hwframe+0x49/0xbe rip: 0033:0x7f15da0a0dc7 Change-Id: Ife481bf554c5aeaa97812cad0750319cf8a87449 link: http://lkml.kernel.org/r/20200206090132.154869-1-naohiro.aota@wdc.com fixes: 1638045c3677 ("mm: set s_swapfile on blockdev swap devices") signed-off-by: naohiro aota reviewed-by: andrew morton reviewed-by: darrick j. wong tested-by: qais youef cc: christoph hellwig cc: Git-commit: e771685bad3d8555d7931876463b542b36ff0c83 Git-repo: https://android.googlesource.com/kernel/common Signed-off-by: Srinivasarao P --- mm/swapfile.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/mm/swapfile.c b/mm/swapfile.c index aaf933538ae4..2ba909118887 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -2926,10 +2926,6 @@ static int claim_swapfile(struct swap_info_struct *p, struct inode *inode) p->bdev = inode->i_sb->s_bdev; } - inode_lock(inode); - if (IS_SWAPFILE(inode)) - return -EBUSY; - return 0; } @@ -3183,36 +3179,40 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) mapping = swap_file->f_mapping; inode = mapping->host; - /* If S_ISREG(inode->i_mode) will do inode_lock(inode); */ error = claim_swapfile(p, inode); if (unlikely(error)) goto bad_swap; + inode_lock(inode); + if (IS_SWAPFILE(inode)) { + error = -EBUSY; + goto bad_swap_unlock_inode; + } /* * Read the swap header. */ if (!mapping->a_ops->readpage) { error = -EINVAL; - goto bad_swap; + goto bad_swap_unlock_inode; } page = read_mapping_page(mapping, 0, swap_file); if (IS_ERR(page)) { error = PTR_ERR(page); - goto bad_swap; + goto bad_swap_unlock_inode; } swap_header = kmap(page); maxpages = read_swap_header(p, swap_header, inode); if (unlikely(!maxpages)) { error = -EINVAL; - goto bad_swap; + goto bad_swap_unlock_inode; } /* OK, set up the swap map and apply the bad block list */ swap_map = vzalloc(maxpages); if (!swap_map) { error = -ENOMEM; - goto bad_swap; + goto bad_swap_unlock_inode; } if (bdi_cap_stable_pages_required(inode_to_bdi(inode))) @@ -3238,7 +3238,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) GFP_KERNEL); if (!cluster_info) { error = -ENOMEM; - goto bad_swap; + goto bad_swap_unlock_inode; } for (ci = 0; ci < nr_cluster; ci++) @@ -3247,7 +3247,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) p->percpu_cluster = alloc_percpu(struct percpu_cluster); if (!p->percpu_cluster) { error = -ENOMEM; - goto bad_swap; + goto bad_swap_unlock_inode; } for_each_possible_cpu(cpu) { struct percpu_cluster *cluster; @@ -3259,13 +3259,13 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = swap_cgroup_swapon(p->type, maxpages); if (error) - goto bad_swap; + goto bad_swap_unlock_inode; nr_extents = setup_swap_map_and_extents(p, swap_header, swap_map, cluster_info, maxpages, &span); if (unlikely(nr_extents < 0)) { error = nr_extents; - goto bad_swap; + goto bad_swap_unlock_inode; } /* frontswap enabled? set up bit-per-page map for frontswap */ if (IS_ENABLED(CONFIG_FRONTSWAP)) @@ -3304,7 +3304,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = init_swap_address_space(p->type, maxpages); if (error) - goto bad_swap; + goto bad_swap_unlock_inode; /* * Flush any pending IO and dirty mappings before we start using this @@ -3314,7 +3314,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = inode_drain_writes(inode); if (error) { inode->i_flags &= ~S_SWAPFILE; - goto bad_swap; + goto bad_swap_unlock_inode; } mutex_lock(&swapon_mutex); @@ -3341,6 +3341,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) error = 0; goto out; +bad_swap_unlock_inode: + inode_unlock(inode); bad_swap: free_percpu(p->percpu_cluster); p->percpu_cluster = NULL; @@ -3348,6 +3350,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) set_blocksize(p->bdev, p->old_block_size); blkdev_put(p->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); } + inode = NULL; destroy_swap_extents(p); swap_cgroup_swapoff(p->type); spin_lock(&swap_lock); @@ -3357,13 +3360,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) vfree(swap_map); kvfree(cluster_info); kvfree(frontswap_map); - if (swap_file) { - if (inode) { - inode_unlock(inode); - inode = NULL; - } + if (swap_file) filp_close(swap_file, NULL); - } out: if (page && !IS_ERR(page)) { kunmap(page); -- GitLab From 69843cd0a6a9b15d94411de144b530ae03bf9492 Mon Sep 17 00:00:00 2001 From: Venkata Prahlad Valluru Date: Wed, 10 Jun 2020 12:45:55 +0530 Subject: [PATCH 1034/1055] clk: qcom: mdss: update dsi 12nm clock driver Add 12nm clock to mdss clocks. Fix regmap parameters. Move clock commit to set_rate. Set divider values to registers instead of setting them during prepare call. Change-Id: I4eec349875e392dd707d0ac93f906428ca4b97e3 Signed-off-by: Venkata Prahlad Valluru --- .../clk/qcom/mdss/mdss-dsi-pll-12nm-util.c | 118 +++++++++++++----- drivers/clk/qcom/mdss/mdss-dsi-pll-12nm.c | 43 ++++--- drivers/clk/qcom/mdss/mdss-pll.c | 2 + drivers/clk/qcom/mdss/mdss-pll.h | 6 +- 4 files changed, 115 insertions(+), 54 deletions(-) diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm-util.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm-util.c index 944b1dbad781..f67d5a0e7765 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm-util.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm-util.c @@ -24,17 +24,31 @@ #define DSI_PLL_POLL_MAX_READS 15 #define DSI_PLL_POLL_TIMEOUT_US 1000 +static void __mdss_dsi_get_pll_vco_cntrl(u64 target_freq, u32 post_div_mux, + u32 *vco_cntrl, u32 *cpbias_cntrl); + int pixel_div_set_div(void *context, unsigned int reg, unsigned int div) { struct mdss_pll_resources *pll = context; + void __iomem *pll_base = pll->pll_base; + int rc; + char data = 0; struct dsi_pll_db *pdb; pdb = (struct dsi_pll_db *)pll->priv; + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } /* Programming during vco_prepare. Keep this value */ - pdb->param.pixel_divhf = (div - 1); + data = ((div - 1) & 0x7f); + MDSS_PLL_REG_W(pll_base, DSIPHY_SSC9, data); + pdb->param.pixel_divhf = data; + mdss_pll_resource_enable(pll, false); pr_debug("ndx=%d div=%d divhf=%d\n", pll->index, div, pdb->param.pixel_divhf); @@ -46,6 +60,7 @@ int pixel_div_get_div(void *context, unsigned int reg, { int rc; struct mdss_pll_resources *pll = context; + u32 val = 0; if (is_gdsc_disabled(pll)) return 0; @@ -56,8 +71,9 @@ int pixel_div_get_div(void *context, unsigned int reg, return rc; } - *div = (MDSS_PLL_REG_R(pll->pll_base, DSIPHY_SSC9) & 0x7F); - pr_debug("pixel_div = %d\n", (*div+1)); + val = (MDSS_PLL_REG_R(pll->pll_base, DSIPHY_SSC9) & 0x7F); + *div = val + 1; + pr_debug("pixel_div = %d\n", (*div)); mdss_pll_resource_enable(pll, false); @@ -68,13 +84,30 @@ int set_post_div_mux_sel(void *context, unsigned int reg, unsigned int sel) { struct mdss_pll_resources *pll = context; + void __iomem *pll_base = pll->pll_base; struct dsi_pll_db *pdb; + u64 target_freq = 0; + u32 vco_cntrl = 0, cpbias_cntrl = 0; + char data = 0; pdb = (struct dsi_pll_db *)pll->priv; /* Programming during vco_prepare. Keep this value */ pdb->param.post_div_mux = sel; + target_freq = div_u64(pll->vco_current_rate, + BIT(pdb->param.post_div_mux)); + __mdss_dsi_get_pll_vco_cntrl(target_freq, pdb->param.post_div_mux, + &vco_cntrl, &cpbias_cntrl); + + data = ((vco_cntrl & 0x3f) | BIT(6)); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_CTRL, data); + pr_debug("%s: vco_cntrl 0x%x\n", __func__, vco_cntrl); + + data = ((cpbias_cntrl & 0x1) << 6) | BIT(4); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL, data); + pr_debug("%s: cpbias_cntrl 0x%x\n", __func__, cpbias_cntrl); + pr_debug("ndx=%d post_div_mux_sel=%d p_div=%d\n", pll->index, sel, (u32) BIT(sel)); @@ -99,6 +132,7 @@ int get_post_div_mux_sel(void *context, unsigned int reg, vco_cntrl = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_PLL_VCO_CTRL); vco_cntrl &= 0x30; + pr_debug("%s: vco_cntrl 0x%x\n", __func__, vco_cntrl); cpbias_cntrl = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL); @@ -121,6 +155,7 @@ int get_post_div_mux_sel(void *context, unsigned int reg, } mdss_pll_resource_enable(pll, false); + pr_debug("%s: sel = %d\n", __func__, *sel); return 0; } @@ -129,16 +164,24 @@ int set_gp_mux_sel(void *context, unsigned int reg, unsigned int sel) { struct mdss_pll_resources *pll = context; - struct dsi_pll_db *pdb; + void __iomem *pll_base = pll->pll_base; + char data = 0; + int rc; - pdb = (struct dsi_pll_db *)pll->priv; + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } /* Programming during vco_prepare. Keep this value */ - pdb->param.gp_div_mux = sel; + data = ((sel & 0x7) << 5) | 0x5; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CTRL, data); pr_debug("ndx=%d gp_div_mux_sel=%d gp_cntrl=%d\n", pll->index, sel, (u32) BIT(sel)); + mdss_pll_resource_enable(pll, false); return 0; } @@ -184,7 +227,9 @@ static bool pll_is_pll_locked_12nm(struct mdss_pll_resources *pll, pr_err("DSI PLL ndx=%d status=%x failed to Lock\n", pll->index, status); pll_locked = false; + pr_debug("%s: not locked\n", __func__); } else { + pr_debug("%s: locked\n", __func__); pll_locked = true; } @@ -551,13 +596,13 @@ static void mdss_dsi_pll_12nm_calc_reg(struct mdss_pll_resources *pll, { struct dsi_pll_param *param = &pdb->param; u64 target_freq = 0; + u32 post_div_mux = 0; + get_post_div_mux_sel(pll, 0, &post_div_mux); target_freq = div_u64(pll->vco_current_rate, - BIT(pdb->param.post_div_mux)); + BIT(post_div_mux)); param->hsfreqrange = __mdss_dsi_get_hsfreqrange(target_freq); - __mdss_dsi_get_pll_vco_cntrl(target_freq, param->post_div_mux, - ¶m->vco_cntrl, ¶m->cpbias_cntrl); param->osc_freq_target = __mdss_dsi_get_osc_freq_target(target_freq); param->m_div = (u32) __mdss_dsi_pll_get_m_div(pll->vco_current_rate); param->fsm_ovr_ctrl = __mdss_dsi_get_fsm_ovr_ctrl(target_freq); @@ -716,9 +761,6 @@ static void pll_db_commit_12nm(struct mdss_pll_resources *pll, data = ((param->hsfreqrange & 0x7f) | BIT(7)); MDSS_PLL_REG_W(pll_base, DSIPHY_HS_FREQ_RAN_SEL, data); - data = ((param->vco_cntrl & 0x3f) | BIT(6)); - MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_CTRL, data); - data = (param->osc_freq_target & 0x7f); MDSS_PLL_REG_W(pll_base, DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_0, data); @@ -742,15 +784,6 @@ static void pll_db_commit_12nm(struct mdss_pll_resources *pll, data = ((param->gmp_cntrl & 0x3) << 4); MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_GMP_CTRL_DIG_TST, data); - data = ((param->cpbias_cntrl & 0x1) << 6) | BIT(4); - MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL, data); - - data = ((param->gp_div_mux & 0x7) << 5) | 0x5; - MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CTRL, data); - - data = (param->pixel_divhf & 0x7f); - MDSS_PLL_REG_W(pll_base, DSIPHY_SSC9, data); - MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_ANA_PROG_CTRL, 0x03); MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_ANA_TST_LOCK_ST_OVR_CTRL, 0x50); MDSS_PLL_REG_W(pll_base, @@ -788,6 +821,14 @@ int pll_vco_set_rate_12nm(struct clk_hw *hw, unsigned long rate, pll->vco_current_rate = rate; pll->vco_ref_clk_rate = vco->ref_clk_rate; + + mdss_dsi_pll_12nm_calc_reg(pll, pdb); + if (pll->ssc_en) + mdss_dsi_pll_12nm_calc_ssc(pll, pdb); + + /* commit DSI vco */ + pll_db_commit_12nm(pll, pdb); + error: return rc; } @@ -800,9 +841,13 @@ static unsigned long pll_vco_get_rate_12nm(struct clk_hw *hw) u64 ref_clk = vco->ref_clk_rate; int rc; struct mdss_pll_resources *pll = vco->priv; + u32 post_div_mux; + u32 cpbias_cntrl = 0; - if (is_gdsc_disabled(pll)) + if (is_gdsc_disabled(pll)) { + pr_err("%s:gdsc disabled\n", __func__); return 0; + } rc = mdss_pll_resource_enable(pll, true); if (rc) { @@ -820,6 +865,16 @@ static unsigned long pll_vco_get_rate_12nm(struct clk_hw *hw) m_div_11_6 &= 0x3f; pr_debug("m_div_11_6 = 0x%x\n", m_div_11_6); + post_div_mux = MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_VCO_CTRL); + + pr_debug("post_div_mux = 0x%x\n", post_div_mux); + + cpbias_cntrl = MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL); + cpbias_cntrl = ((cpbias_cntrl >> 6) & 0x1); + pr_debug("cpbias_cntrl = 0x%x\n", cpbias_cntrl); + m_div = ((m_div_11_6 << 6) | (m_div_5_0)); vco_rate = div_u64((ref_clk * m_div), 4); @@ -854,12 +909,22 @@ unsigned long vco_12nm_recalc_rate(struct clk_hw *hw, struct mdss_pll_resources *pll = vco->priv; unsigned long rate = 0; int rc; + struct dsi_pll_db *pdb; + + pdb = (struct dsi_pll_db *)pll->priv; if (!pll && is_gdsc_disabled(pll)) { pr_err("gdsc disabled\n"); return 0; } + if (pll->vco_current_rate != 0) { + rate = pll_vco_get_rate_12nm(hw); + pr_debug("%s:returning vco rate = %lld\n", __func__, + pll->vco_current_rate); + return rate; + } + rc = mdss_pll_resource_enable(pll, true); if (rc) { pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); @@ -870,6 +935,7 @@ unsigned long vco_12nm_recalc_rate(struct clk_hw *hw, pll->handoff_resources = true; pll->pll_on = true; rate = pll_vco_get_rate_12nm(hw); + pr_debug("%s: pll locked. rate %lu\n", __func__, rate); } else { mdss_pll_resource_enable(pll, false); } @@ -930,15 +996,7 @@ int pll_vco_prepare_12nm(struct clk_hw *hw) goto end; } - mdss_dsi_pll_12nm_calc_reg(pll, pdb); - if (pll->ssc_en) - mdss_dsi_pll_12nm_calc_ssc(pll, pdb); - - /* commit DSI vco */ - pll_db_commit_12nm(pll, pdb); - rc = dsi_pll_enable(hw); - error: if (rc) { mdss_pll_resource_enable(pll, false); diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm.c index 21561941dcd5..9f8767455338 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-12nm.c @@ -37,6 +37,7 @@ static const struct clk_ops clk_ops_vco_12nm = { .round_rate = pll_vco_round_rate_12nm, .prepare = pll_vco_prepare_12nm, .unprepare = pll_vco_unprepare_12nm, + .enable = pll_vco_enable_12nm, }; static struct regmap_bus pclk_div_regmap_bus = { @@ -216,8 +217,8 @@ static struct clk_fixed_factor dsi0pll_post_div32 = { static struct clk_regmap_mux dsi0pll_post_div_mux = { .reg = DSIPHY_PLL_VCO_CTRL, - .shift = 4, - .width = 2, + .shift = 0, + .width = 3, .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi0pll_post_div_mux", @@ -308,8 +309,8 @@ static struct clk_fixed_factor dsi1pll_post_div32 = { static struct clk_regmap_mux dsi1pll_post_div_mux = { .reg = DSIPHY_PLL_VCO_CTRL, - .shift = 4, - .width = 2, + .shift = 0, + .width = 3, .clkr = { .hw.init = &(struct clk_init_data){ .name = "dsi1pll_post_div_mux", @@ -400,7 +401,7 @@ static struct clk_fixed_factor dsi0pll_gp_div32 = { static struct clk_regmap_mux dsi0pll_gp_div_mux = { .reg = DSIPHY_PLL_CTRL, - .shift = 5, + .shift = 0, .width = 3, .clkr = { .hw.init = &(struct clk_init_data){ @@ -492,7 +493,7 @@ static struct clk_fixed_factor dsi1pll_gp_div32 = { static struct clk_regmap_mux dsi1pll_gp_div_mux = { .reg = DSIPHY_PLL_CTRL, - .shift = 5, + .shift = 0, .width = 3, .clkr = { .hw.init = &(struct clk_init_data){ @@ -516,11 +517,12 @@ static struct clk_regmap_div dsi0pll_pclk_src = { .width = 6, .clkr = { .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_pclk_src", + .name = "dsi0_phy_pll_out_dsiclk", .parent_names = (const char *[]){ "dsi0pll_gp_div_mux"}, .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), .ops = &clk_regmap_div_ops, }, }, @@ -532,11 +534,12 @@ static struct clk_regmap_div dsi1pll_pclk_src = { .width = 6, .clkr = { .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_pclk_src", + .name = "dsi1_phy_pll_out_dsiclk", .parent_names = (const char *[]){ "dsi1pll_gp_div_mux"}, .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), .ops = &clk_regmap_div_ops, }, }, @@ -546,10 +549,11 @@ static struct clk_fixed_factor dsi0pll_byte_clk_src = { .div = 4, .mult = 1, .hw.init = &(struct clk_init_data){ - .name = "dsi0pll_byte_clk_src", + .name = "dsi0_phy_pll_out_byteclk", .parent_names = (const char *[]){"dsi0pll_post_div_mux"}, .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), .ops = &clk_fixed_factor_ops, }, }; @@ -558,15 +562,15 @@ static struct clk_fixed_factor dsi1pll_byte_clk_src = { .div = 4, .mult = 1, .hw.init = &(struct clk_init_data){ - .name = "dsi1pll_byte_clk_src", + .name = "dsi1_phy_pll_out_byteclk", .parent_names = (const char *[]){"dsi1pll_post_div_mux"}, .num_parents = 1, - .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT), + .flags = (CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT | + CLK_SET_RATE_NO_REPARENT), .ops = &clk_fixed_factor_ops, }, }; - static struct clk_hw *mdss_dsi_pllcc_12nm[] = { [VCO_CLK_0] = &dsi0pll_vco_clk.hw, [POST_DIV1_0_CLK] = &dsi0pll_post_div1.hw, @@ -608,14 +612,14 @@ int dsi_pll_clock_register_12nm(struct platform_device *pdev, struct mdss_pll_resources *pll_res) { int rc = 0, ndx, i; - struct clk *clk; + struct clk *clk = NULL; struct clk_onecell_data *clk_data; int num_clks = ARRAY_SIZE(mdss_dsi_pllcc_12nm); struct regmap *rmap; struct dsi_pll_db *pdb; if (!pdev || !pdev->dev.of_node || - !pll_res || !pll_res->pll_base || !pll_res->phy_base) { + !pll_res || !pll_res->pll_base) { pr_err("Invalid params\n"); return -EINVAL; } @@ -649,7 +653,7 @@ int dsi_pll_clock_register_12nm(struct platform_device *pdev, clk_data->clk_num = num_clks; /* Establish client data */ - if (ndx == 0) { + if (pll_res->index == 0) { rmap = devm_regmap_init(&pdev->dev, &post_div_mux_regmap_bus, pll_res, &dsi_pll_12nm_config); dsi0pll_post_div_mux.clkr.regmap = rmap; @@ -712,7 +716,8 @@ int dsi_pll_clock_register_12nm(struct platform_device *pdev, of_clk_src_onecell_get, clk_data); } if (!rc) { - pr_info("Registered DSI PLL ndx=%d, clocks successfully", ndx); + pr_info("Registered DSI PLL ndx=%d, clocks successfully", + pll_res->index); return rc; } diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c index 8a948250b200..f99070ec9c3d 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.c +++ b/drivers/clk/qcom/mdss/mdss-pll.c @@ -136,6 +136,8 @@ static int mdss_pll_resource_parse(struct platform_device *pdev, pll_res->pll_interface_type = MDSS_DSI_PLL_7NM; else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_7nm_v2")) pll_res->pll_interface_type = MDSS_DSI_PLL_7NM_V2; + else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_12nm")) + pll_res->pll_interface_type = MDSS_DSI_PLL_12NM; else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_28lpm")) pll_res->pll_interface_type = MDSS_DSI_PLL_28LPM; else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_14nm")) diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h index d7e1e2c53851..4e3af2f03b8b 100644 --- a/drivers/clk/qcom/mdss/mdss-pll.h +++ b/drivers/clk/qcom/mdss/mdss-pll.h @@ -219,12 +219,8 @@ static inline bool is_gdsc_disabled(struct mdss_pll_resources *pll_res) WARN(1, "gdsc_base register is not defined\n"); return true; } - if (pll_res->target_id == MDSS_PLL_TARGET_SDM660) - ret = ((readl_relaxed(pll_res->gdsc_base + 0x4) & BIT(31)) && + ret = ((readl_relaxed(pll_res->gdsc_base + 0x4) & BIT(31)) && (!(readl_relaxed(pll_res->gdsc_base) & BIT(0)))) ? false : true; - else - ret = readl_relaxed(pll_res->gdsc_base) & BIT(31) ? - false : true; return ret; } -- GitLab From 84248bd660141f7f06003f0df93e75518e12c3a0 Mon Sep 17 00:00:00 2001 From: Arun Prakash Date: Sun, 17 May 2020 13:12:21 +0530 Subject: [PATCH 1035/1055] hwspinlock: Add support to parse spin lock id The current implementation will use hard coded spin lock id which will cause conflicts when gvm want to access hardware spink lock while communicating with remote host over dedicated smem partition area. Adding support to parse spin lock id from dt entry. This will help to configure unique spin lock id for gvm. Change-Id: I8001c6339a2d823109177dedbfceef9a5bdc2d51 Signed-off-by: Arun Prakash --- drivers/hwspinlock/qcom_hwspinlock.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/hwspinlock/qcom_hwspinlock.c b/drivers/hwspinlock/qcom_hwspinlock.c index fa6880b8060a..b0511d7a8017 100644 --- a/drivers/hwspinlock/qcom_hwspinlock.c +++ b/drivers/hwspinlock/qcom_hwspinlock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013,2020, The Linux Foundation. All rights reserved. * Copyright (c) 2015, Sony Mobile Communications AB * * This software is licensed under the terms of the GNU General Public @@ -28,13 +28,19 @@ #define QCOM_MUTEX_APPS_PROC_ID 1 #define QCOM_MUTEX_NUM_LOCKS 32 +/** + * setting default mutex id as QCOM_MUTEX_APPS_PROC_ID + * and will override this value if dt entry is found + */ +static u32 qcom_mutex_lock_id = QCOM_MUTEX_APPS_PROC_ID; + static int qcom_hwspinlock_trylock(struct hwspinlock *lock) { struct regmap_field *field = lock->priv; u32 lock_owner; int ret; - ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID); + ret = regmap_field_write(field, qcom_mutex_lock_id); if (ret) return ret; @@ -42,7 +48,7 @@ static int qcom_hwspinlock_trylock(struct hwspinlock *lock) if (ret) return ret; - return lock_owner == QCOM_MUTEX_APPS_PROC_ID; + return lock_owner == qcom_mutex_lock_id; } static void qcom_hwspinlock_unlock(struct hwspinlock *lock) @@ -57,7 +63,7 @@ static void qcom_hwspinlock_unlock(struct hwspinlock *lock) return; } - if (lock_owner != QCOM_MUTEX_APPS_PROC_ID) { + if (lock_owner != qcom_mutex_lock_id) { pr_err("%s: spinlock not owned by us (actual owner is %d)\n", __func__, lock_owner); } @@ -88,6 +94,7 @@ static int qcom_hwspinlock_probe(struct platform_device *pdev) size_t array_size; u32 stride; u32 base; + u32 mutex_id; int ret; int i; @@ -114,6 +121,10 @@ static int qcom_hwspinlock_probe(struct platform_device *pdev) return -EINVAL; } + ret = of_property_read_u32(pdev->dev.of_node, "mutex-id", &mutex_id); + if (!ret) + qcom_mutex_lock_id = mutex_id; + array_size = QCOM_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock); bank = devm_kzalloc(&pdev->dev, sizeof(*bank) + array_size, GFP_KERNEL); if (!bank) -- GitLab From 78f5f831816a7b36114792a5ecbaed1d6f45705b Mon Sep 17 00:00:00 2001 From: Arun Prakash Date: Sun, 17 May 2020 13:24:36 +0530 Subject: [PATCH 1036/1055] mailbox: Add new mailbox for gvm Add new mailbox for gvm which will be used to siganl primary host when gvm want to communicate with remote sub system. This mailbox will use virtual IRQ line which will trigger interrupt to primary host and primary host will then forward this interrupt to corresponding remote sub system. Change-Id: Ib9e10e26f0e636e9a3a4cbaf9676362f5574d681 Signed-off-by: Arun Prakash --- drivers/mailbox/Kconfig | 10 ++ drivers/mailbox/Makefile | 2 + drivers/mailbox/qcom-gvm-ipc-mailbox.c | 126 +++++++++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 drivers/mailbox/qcom-gvm-ipc-mailbox.c diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index cb2ecf417ffe..c9ef797d423b 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -132,6 +132,16 @@ config QCOM_APCS_IPC providing an interface for invoking the inter-process communication signals from the application processor to other masters. +config QCOM_GVM_IPC + tristate "Qualcomm Technologies, Inc. GVM IPC driver" + depends on ARCH_QCOM + help + Say y here to enable support for the GVM IPC mailbox driver, + This driver will providing an interface for invoking the communication + between GVM and primary host through virtual IRQ line. It signals from + the GVM to primary host and primary host will send different signal to + remote sub system. + config TEGRA_HSP_MBOX bool "Tegra HSP (Hardware Synchronization Primitives) Driver" depends on ARCH_TEGRA_186_SOC diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index 7650057c4cfb..2f4f8d614640 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -35,6 +35,8 @@ obj-$(CONFIG_BCM_FLEXRM_MBOX) += bcm-flexrm-mailbox.o obj-$(CONFIG_QCOM_APCS_IPC) += qcom-apcs-ipc-mailbox.o +obj-$(CONFIG_QCOM_GVM_IPC) += qcom-gvm-ipc-mailbox.o + obj-$(CONFIG_TEGRA_HSP_MBOX) += tegra-hsp.o obj-$(CONFIG_QTI_RPMH_MBOX) += qcom-rpmh-mailbox.o diff --git a/drivers/mailbox/qcom-gvm-ipc-mailbox.c b/drivers/mailbox/qcom-gvm-ipc-mailbox.c new file mode 100644 index 000000000000..ee080a292b49 --- /dev/null +++ b/drivers/mailbox/qcom-gvm-ipc-mailbox.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2020, 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 + +#define QCOM_GVM_CHNL 32 + +struct qcom_gvm_ipc { + struct mbox_controller mbox; + struct mbox_chan mbox_chans[QCOM_GVM_CHNL]; + + void __iomem *reg; + unsigned long offset; +}; + +static int qcom_gvm_ipc_send_data(struct mbox_chan *chan, void *data) +{ + struct qcom_gvm_ipc *gvm_ipc = container_of(chan->mbox, + struct qcom_gvm_ipc, mbox); + + __raw_writel(1, gvm_ipc->reg); + + return 0; +} + +static const struct mbox_chan_ops qcom_gvm_ipc_ops = { + .send_data = qcom_gvm_ipc_send_data, +}; + +static int qcom_gvm_ipc_probe(struct platform_device *pdev) +{ + struct qcom_gvm_ipc *gvm_ipc; + struct resource *res; + void __iomem *base; + unsigned long i; + int ret; + + gvm_ipc = devm_kzalloc(&pdev->dev, sizeof(*gvm_ipc), GFP_KERNEL); + if (!gvm_ipc) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (IS_ERR(base)) + return PTR_ERR(base); + + gvm_ipc->reg = base; + /* Initialize channel identifiers */ + for (i = 0; i < ARRAY_SIZE(gvm_ipc->mbox_chans); i++) + gvm_ipc->mbox_chans[i].con_priv = (void *)i; + + gvm_ipc->mbox.dev = &pdev->dev; + gvm_ipc->mbox.ops = &qcom_gvm_ipc_ops; + gvm_ipc->mbox.chans = gvm_ipc->mbox_chans; + gvm_ipc->mbox.num_chans = ARRAY_SIZE(gvm_ipc->mbox_chans); + + ret = mbox_controller_register(&gvm_ipc->mbox); + if (ret) { + dev_err(&pdev->dev, "failed to register GVM IPC controller\n"); + return ret; + } + + platform_set_drvdata(pdev, gvm_ipc); + + return 0; +} + +static int qcom_gvm_ipc_remove(struct platform_device *pdev) +{ + struct qcom_gvm_ipc *gvm_ipc = platform_get_drvdata(pdev); + + mbox_controller_unregister(&gvm_ipc->mbox); + + return 0; +} + +/* .data is the offset of the ipc register within the global block */ +static const struct of_device_id qcom_gvm_ipc_of_match[] = { + { .compatible = "qcom,sm8150-apcs-hmss-global" }, + {} +}; +MODULE_DEVICE_TABLE(of, qcom_gvm_ipc_of_match); + +static struct platform_driver qcom_gvm_ipc_driver = { + .probe = qcom_gvm_ipc_probe, + .remove = qcom_gvm_ipc_remove, + .driver = { + .name = "qcom_gvm_ipc", + .of_match_table = qcom_gvm_ipc_of_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init qcom_gvm_ipc_init(void) +{ + return platform_driver_register(&qcom_gvm_ipc_driver); +} +postcore_initcall(qcom_gvm_ipc_init); + +static void __exit qcom_gvm_ipc_exit(void) +{ + platform_driver_unregister(&qcom_gvm_ipc_driver); +} +module_exit(qcom_gvm_ipc_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies, Inc. GVM IPC driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From adfc11c70f7a4342a63ff85f0f576d05d1e5ad06 Mon Sep 17 00:00:00 2001 From: Venkata Manasa Kakarla Date: Tue, 23 Jun 2020 14:19:00 +0530 Subject: [PATCH 1037/1055] serial: msm_geni_serial: Initialize the variables before access Initialize the variables to resolve KW (clockwork) issues. Change-Id: I2e4b1e4511474161372523e4d3b86d20bd5d9e59 Signed-off-by: Venkata Manasa Kakarla --- drivers/tty/serial/msm_geni_serial.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index cd4ce95f3021..b0d04569847c 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -1613,7 +1613,7 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx) struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); unsigned int rx_bytes = 0; struct tty_port *tport; - int ret; + int ret = 0; unsigned int geni_status; if (msm_port->uart_ssr.is_ssr_down) { @@ -1726,6 +1726,10 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) SE_GENI_M_IRQ_CLEAR); geni_write_reg_nolog(s_irq_status, uport->membase, SE_GENI_S_IRQ_CLEAR); + dma_tx_status = geni_read_reg_nolog(uport->membase, + SE_DMA_TX_IRQ_STAT); + dma_rx_status = geni_read_reg_nolog(uport->membase, + SE_DMA_RX_IRQ_STAT); if (dma_tx_status) geni_write_reg_nolog(dma_tx_status, uport->membase, SE_DMA_TX_IRQ_CLR); @@ -3081,8 +3085,7 @@ static int msm_geni_serial_probe(struct platform_device *pdev) return 0; exit_geni_serial_probe: - IPC_LOG_MSG(dev_port->ipc_log_misc, "%s: fail port:%s ret:%d\n", - __func__, uport->name, ret); + IPC_LOG_MSG(dev_port->ipc_log_misc, "%s: ret:%d\n", __func__, ret); return ret; } -- GitLab From 804eca1167c8d35a0144afb4a28465fd7ef35abf Mon Sep 17 00:00:00 2001 From: Nitesh Gupta Date: Tue, 18 Feb 2020 15:06:12 +0530 Subject: [PATCH 1038/1055] msm: mhi_dev: Add KPI marker and log for mhi init Add logs and Boot KPI Markers in MHI driver for MHI Initialization. This is required for KPI consistency and KPI calculation and getting KPI data. Change-Id: Ie6ab9b69f4ab3fb548cc9a2f0bf74ba935a88e0c Signed-off-by: Nitesh Gupta --- drivers/platform/msm/mhi_dev/mhi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 078b1785df2d..fc98fec90068 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "mhi.h" #include "mhi_hwio.h" @@ -1270,6 +1271,9 @@ static void mhi_hwc_cb(void *priv, enum ipa_mhi_event_type event, pr_err("Error configuring interrupts, rc = %d\n", rc); return; } + + mhi_log(MHI_MSG_CRITICAL, "Device in M0 State\n"); + place_marker("MHI - Device in M0 State\n"); break; case IPA_MHI_EVENT_DATA_AVAILABLE: rc = mhi_dev_notify_sm_event(MHI_DEV_EVENT_HW_ACC_WAKEUP); -- GitLab From 0cc3ccb5f7f5ceba8a293e5e349957d158e41356 Mon Sep 17 00:00:00 2001 From: Nitesh Gupta Date: Tue, 18 Feb 2020 15:23:39 +0530 Subject: [PATCH 1039/1055] msm: ep_pcie: Add KPI marker and log for PCIe link init Add logs and Boot KPI Markers in PCIe EP driver for link Initialization. This is required for KPI consistency and KPI calculation and getting KPI data. Change-Id: I1b2696ba3fdd9e6dda2cb23bfbab941b8fcc8f32 Signed-off-by: Nitesh Gupta --- drivers/platform/msm/ep_pcie/ep_pcie_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index d5f42de40343..d3c79d7a2912 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "ep_pcie_com.h" #include @@ -1893,6 +1894,9 @@ int ep_pcie_core_enable_endpoint(enum ep_pcie_options opt) EP_PCIE_INFO(dev, "PCIe V%d: link initialized for LE PCIe endpoint\n", dev->rev); + pr_crit("PCIe - link initialized for LE PCIe endpoint\n"); + place_marker( + "PCIe - link initialized for LE PCIe endpoint\n"); } checkbme: -- GitLab From eaa69fb091ec2c8bf6a8f348fa8e9f8920d830e1 Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Wed, 8 Jul 2020 11:03:26 +0530 Subject: [PATCH 1040/1055] rpmsg: qcom_glink_bgcom: Correct the copyright licence Correct the copyright licence for the glink-bgcom transport driver. Change-Id: I40537f5e1c3ca5e7385bab03dd65fa6549c54bc6 Signed-off-by: Prudhvi Yarlagadda --- drivers/rpmsg/qcom_glink_bgcom.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/rpmsg/qcom_glink_bgcom.c b/drivers/rpmsg/qcom_glink_bgcom.c index 74bf2e54dbba..31f9f0cdb47c 100644 --- a/drivers/rpmsg/qcom_glink_bgcom.c +++ b/drivers/rpmsg/qcom_glink_bgcom.c @@ -1,4 +1,6 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, Linaro Ltd * * 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 -- GitLab From 98bf61e5dcf7d174eb5bb384d0838ff20f0c5161 Mon Sep 17 00:00:00 2001 From: Pankaj Gupta Date: Wed, 8 Jul 2020 12:17:13 +0530 Subject: [PATCH 1041/1055] msm: kgsl: Put a keep alive vote before updating CP_RB_WPTR There could be a situation where GPU comes out of ifpc after a fenced write transaction but before reading AHB_FENCE_STATUS from KMD, it goes back to ifpc due to inactivity. Put a keep alive vote before doing fenced write for CP_RB_WPTR to avoid such unlikely scenario. Change-Id: Ibe0391b39cedf64e2dfa78ab0bbcda0fc8746c88 Signed-off-by: Pankaj Gupta --- drivers/gpu/msm/adreno_a6xx_preempt.c | 20 ++++++++++++++++++++ drivers/gpu/msm/adreno_ringbuffer.c | 17 ++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index d39420b0c9ed..760cef5891af 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -36,6 +36,7 @@ static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) struct adreno_ringbuffer *rb = adreno_dev->cur_rb; unsigned long flags; int ret = 0; + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); spin_lock_irqsave(&rb->preempt_lock, flags); @@ -45,11 +46,30 @@ static void _update_wptr(struct adreno_device *adreno_dev, bool reset_timer) * dispatcher context. Do it now. */ if (rb->skip_inline_wptr) { + /* + * There could be a situation where GPU comes out of + * ifpc after a fenced write transaction but before + * reading AHB_FENCE_STATUS from KMD, it goes back to + * ifpc due to inactivity (kernel scheduler plays a + * role here). Thus, the GPU could technically be + * re-collapsed between subsequent register writes + * leading to a prolonged preemption sequence. The + * keepalive bit prevents any further power collapse + * while it is set. + */ + if (gmu_core_isenabled(device)) + gmu_core_regrmw(device, A6XX_GMU_AO_SPARE_CNTL, + 0x0, 0x2); ret = adreno_gmu_fenced_write(adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->wptr, FENCE_STATUS_WRITEDROPPED0_MASK); + /* Clear the keep alive */ + if (gmu_core_isenabled(device)) + gmu_core_regrmw(device, A6XX_GMU_AO_SPARE_CNTL, + 0x2, 0x0); + reset_timer = true; rb->skip_inline_wptr = false; } diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c index 12ebc174bf16..2ee57e9a5ce6 100644 --- a/drivers/gpu/msm/adreno_ringbuffer.c +++ b/drivers/gpu/msm/adreno_ringbuffer.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-2020, 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 @@ -89,6 +89,7 @@ static void adreno_get_submit_time(struct adreno_device *adreno_dev, static void adreno_ringbuffer_wptr(struct adreno_device *adreno_dev, struct adreno_ringbuffer *rb) { + struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); unsigned long flags; int ret = 0; @@ -102,6 +103,17 @@ static void adreno_ringbuffer_wptr(struct adreno_device *adreno_dev, */ kgsl_pwrscale_busy(KGSL_DEVICE(adreno_dev)); + /* + * There could be a situation where GPU comes out of + * ifpc after a fenced write transaction but before + * reading AHB_FENCE_STATUS from KMD, it goes back to + * ifpc due to inactivity (kernel scheduler plays a + * role here). Put a keep alive vote to avoid such + * unlikely scenario. + */ + if (gpudev->gpu_keepalive) + gpudev->gpu_keepalive(adreno_dev, true); + /* * Ensure the write posted after a possible * GMU wakeup (write could have dropped during wakeup) @@ -110,6 +122,9 @@ static void adreno_ringbuffer_wptr(struct adreno_device *adreno_dev, ADRENO_REG_CP_RB_WPTR, rb->_wptr, FENCE_STATUS_WRITEDROPPED0_MASK); rb->skip_inline_wptr = false; + if (gpudev->gpu_keepalive) + gpudev->gpu_keepalive(adreno_dev, false); + } } else { /* -- GitLab From 1d5863d4db3bbfb7cf24a4955a7282078f71d410 Mon Sep 17 00:00:00 2001 From: Sneh Shah Date: Wed, 1 Jul 2020 13:05:27 +0530 Subject: [PATCH 1042/1055] net: stmmac: Set DOMAIN_ATTR_GEOMETRY for smmu fastmap Use geometry mapping to optimize fastmap memory usage. Change-Id: I0affebabeefb9b4684a27f61dc63138c0d19d864 Signed-off-by: Sneh Shah --- .../stmicro/stmmac/dwmac-qcom-ethqos.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index aa9764ba2cb8..b59958f5aec1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -1344,6 +1344,7 @@ static int stmmac_emb_smmu_cb_probe(struct platform_device *pdev) int atomic_ctx = 1; int fast = 1; int bypass = 1; + struct iommu_domain_geometry geometry = {0}; ETHQOSDBG("EMAC EMB SMMU CB probe: smmu pdev=%p\n", pdev); @@ -1358,6 +1359,10 @@ static int stmmac_emb_smmu_cb_probe(struct platform_device *pdev) stmmac_emb_smmu_ctx.va_end = stmmac_emb_smmu_ctx.va_start + stmmac_emb_smmu_ctx.va_size; + geometry.aperture_start = stmmac_emb_smmu_ctx.va_start; + geometry.aperture_end = + stmmac_emb_smmu_ctx.va_start + stmmac_emb_smmu_ctx.va_size; + stmmac_emb_smmu_ctx.smmu_pdev = pdev; if (dma_set_mask(dev, DMA_BIT_MASK(32)) || @@ -1402,6 +1407,19 @@ static int stmmac_emb_smmu_cb_probe(struct platform_device *pdev) goto err_smmu_probe; } ETHQOSDBG("SMMU fast map set\n"); + if (of_property_read_bool(dev->of_node, + "qcom,smmu-geometry")) { + if (iommu_domain_set_attr + (stmmac_emb_smmu_ctx.mapping->domain, + DOMAIN_ATTR_GEOMETRY, + &geometry)) { + ETHQOSERR("Couldn't set DOMAIN_ATTR_GEOMETRY"); + result = -EIO; + goto err_smmu_probe; + } + ETHQOSDBG("SMMU DOMAIN_ATTR_GEOMETRY set\n"); + } + } result = arm_iommu_attach_device(&stmmac_emb_smmu_ctx.smmu_pdev->dev, -- GitLab From 99db0b7d5cc6f3ea20a82efa9e2db8cf5cb38af7 Mon Sep 17 00:00:00 2001 From: Sean Tranchetti Date: Tue, 30 Jun 2020 11:50:17 -0600 Subject: [PATCH 1043/1055] genetlink: remove genl_bind A potential deadlock can occur during registering or unregistering a new generic netlink family between the main nl_table_lock and the cb_lock where each thread wants the lock held by the other, as demonstrated below. 1) Thread 1 is performing a netlink_bind() operation on a socket. As part of this call, it will call netlink_lock_table(), incrementing the nl_table_users count to 1. 2) Thread 2 is registering (or unregistering) a genl_family via the genl_(un)register_family() API. The cb_lock semaphore will be taken for writing. 3) Thread 1 will call genl_bind() as part of the bind operation to handle subscribing to GENL multicast groups at the request of the user. It will attempt to take the cb_lock semaphore for reading, but it will fail and be scheduled away, waiting for Thread 2 to finish the write. 4) Thread 2 will call netlink_table_grab() during the (un)registration call. However, as Thread 1 has incremented nl_table_users, it will not be able to proceed, and both threads will be stuck waiting for the other. genl_bind() is a noop, unless a genl_family implements the mcast_bind() function to handle setting up family-specific multicast operations. Since no one in-tree uses this functionality as Cong pointed out, simply removing the genl_bind() function will remove the possibility for deadlock, as there is no attempt by Thread 1 above to take the cb_lock semaphore. Change-Id: Ic7fbc60896384d8fe2d46b56419f14493e5782b6 Fixes: c380d9a7afff ("genetlink: pass multicast bind/unbind to families") Suggested-by: Cong Wang Acked-by: Johannes Berg Reported-by: kernel test robot Git-repo: git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git Git-commit: 1e82a62fec613844da9e558f3493540a5b7a7b67 Signed-off-by: Sean Tranchetti Signed-off-by: David S. Miller --- include/net/genetlink.h | 8 ------- net/netlink/genetlink.c | 49 ----------------------------------------- 2 files changed, 57 deletions(-) diff --git a/include/net/genetlink.h b/include/net/genetlink.h index 5ac169a735f4..c25b2e75732b 100644 --- a/include/net/genetlink.h +++ b/include/net/genetlink.h @@ -34,12 +34,6 @@ struct genl_info; * do additional, common, filtering and return an error * @post_doit: called after an operation's doit callback, it may * undo operations done by pre_doit, for example release locks - * @mcast_bind: a socket bound to the given multicast group (which - * is given as the offset into the groups array) - * @mcast_unbind: a socket was unbound from the given multicast group. - * Note that unbind() will not be called symmetrically if the - * generic netlink family is removed while there are still open - * sockets. * @attrbuf: buffer to store parsed attributes (private) * @mcgrps: multicast groups used by this family * @n_mcgrps: number of multicast groups @@ -62,8 +56,6 @@ struct genl_family { void (*post_doit)(const struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info); - int (*mcast_bind)(struct net *net, int group); - void (*mcast_unbind)(struct net *net, int group); struct nlattr ** attrbuf; /* private */ const struct genl_ops * ops; const struct genl_multicast_group *mcgrps; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index dd3d13799cb6..7bc631bfb101 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -959,60 +959,11 @@ static struct genl_family genl_ctrl __ro_after_init = { .netnsok = true, }; -static int genl_bind(struct net *net, int group) -{ - struct genl_family *f; - int err = 0; - unsigned int id; - - down_read(&cb_lock); - - idr_for_each_entry(&genl_fam_idr, f, id) { - if (group >= f->mcgrp_offset && - group < f->mcgrp_offset + f->n_mcgrps) { - int fam_grp = group - f->mcgrp_offset; - - if (!f->netnsok && net != &init_net) - err = -ENOENT; - else if (f->mcast_bind) - err = f->mcast_bind(net, fam_grp); - else - err = 0; - break; - } - } - up_read(&cb_lock); - - return err; -} - -static void genl_unbind(struct net *net, int group) -{ - struct genl_family *f; - unsigned int id; - - down_read(&cb_lock); - - idr_for_each_entry(&genl_fam_idr, f, id) { - if (group >= f->mcgrp_offset && - group < f->mcgrp_offset + f->n_mcgrps) { - int fam_grp = group - f->mcgrp_offset; - - if (f->mcast_unbind) - f->mcast_unbind(net, fam_grp); - break; - } - } - up_read(&cb_lock); -} - static int __net_init genl_pernet_init(struct net *net) { struct netlink_kernel_cfg cfg = { .input = genl_rcv, .flags = NL_CFG_F_NONROOT_RECV, - .bind = genl_bind, - .unbind = genl_unbind, }; /* we'll bump the group number right afterwards */ -- GitLab From a948d7af15d44b3a6457b06ce4878b736be669d4 Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Wed, 1 Jul 2020 17:03:58 -0700 Subject: [PATCH 1044/1055] msm: ipahal: Add uCP exception case for status pkt Add a new enum for uCP exception pkt status. Handle the case where this pkt status exception is received. Change-Id: Ib69e307548efed3482d4636db9161f423c051570 Signed-off-by: Michael Adisumarta --- drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c | 5 +++++ drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c index c2f8e1a2d626..e16003813a9c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c @@ -49,6 +49,8 @@ static const char *ipahal_pkt_status_exception_to_str __stringify(IPAHAL_PKT_STATUS_EXCEPTION_SW_FILT), __stringify(IPAHAL_PKT_STATUS_EXCEPTION_NAT), __stringify(IPAHAL_PKT_STATUS_EXCEPTION_IPV6CT), + __stringify(IPAHAL_PKT_STATUS_EXCEPTION_UCP), + __stringify(IPAHAL_PKT_STATUS_EXCEPTION_CSUM), }; static u16 ipahal_imm_cmd_get_opcode(enum ipahal_imm_cmd_name cmd); @@ -978,6 +980,9 @@ static void ipa_pkt_status_parse( else exception_type = IPAHAL_PKT_STATUS_EXCEPTION_NAT; break; + case 128: + exception_type = IPAHAL_PKT_STATUS_EXCEPTION_UCP; + break; case 229: exception_type = IPAHAL_PKT_STATUS_EXCEPTION_CSUM; break; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h index 164d75d1edb4..3576aea239ec 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2020, 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 @@ -444,6 +444,7 @@ enum ipahal_pkt_status_exception { */ IPAHAL_PKT_STATUS_EXCEPTION_NAT, IPAHAL_PKT_STATUS_EXCEPTION_IPV6CT, + IPAHAL_PKT_STATUS_EXCEPTION_UCP, IPAHAL_PKT_STATUS_EXCEPTION_CSUM, IPAHAL_PKT_STATUS_EXCEPTION_MAX, }; -- GitLab From 9d12c9354ac722cd056986731ebb381337b87b82 Mon Sep 17 00:00:00 2001 From: Yao Jiang Date: Thu, 9 Jul 2020 13:52:46 +0800 Subject: [PATCH 1045/1055] ARM: dts: msm: change HAB VMID to 3 for single LV GVM LV GVM vmid is fixed on 3 for Gen3, so it needs to be changed from 2 to 3 for single LV GVM. Otherwise, it will cause HAB initialization failure if using sa8155-vm-lv.dtb. Change-Id: I08ec12eaa82639f70a793c8216205a9d64154d66 Signed-off-by: Yao Jiang --- arch/arm64/boot/dts/qcom/sa8155-vm-lv.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dtsi b/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dtsi index 80e6b7f1f3e9..ae9b50481609 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-vm-lv.dtsi @@ -21,6 +21,10 @@ }; }; +&hab { + vmid = <3>; +}; + &slpi_tlmm { status = "ok"; }; -- GitLab From 779861c7801127635e762f7a438eba3f53fc3ac2 Mon Sep 17 00:00:00 2001 From: Shreyas K K Date: Fri, 19 Jun 2020 10:57:43 +0530 Subject: [PATCH 1046/1055] drivers: soc: sdx_ext_ipc: Add wakeup support from system suspend Remote SoC needs to be waken up before initiating any transport layer interface (like USB, PCIe). Add two GPIOs (to the AP and modem) to handle to and fro of the wakeable interrupts. Wakeup notifications are initiated by the transport layer. Register notifiers in this driver to act on the request to wakeup. Change-Id: I4ee3b2e15bcb7af63d71bac2fb54488808eb0b45 Signed-off-by: Shreyas K K --- .../bindings/arm/msm/sdx-ext-ipc.txt | 7 ++ drivers/soc/qcom/sdx_ext_ipc.c | 117 +++++++++++++++++- 2 files changed, 123 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt b/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt index d8c6478c469a..76b230ed8b41 100644 --- a/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt +++ b/Documentation/devicetree/bindings/arm/msm/sdx-ext-ipc.txt @@ -18,10 +18,17 @@ Optional named gpio properties: - qcom,default-policy-nop: Set default policy from PANIC to NOP. +- qcom,wakeup-gpio-out: gpio to wakeup remote AP or modem. + +- qcom,wakeup-gpio-in: input gpio to receive wakeup signal from remote AP or + modem. + Example: sdx_ext_ipc: qcom,sdx_ext_ipc { compatible = "qcom,sdx-ext-ipc"; qcom,status-in-gpio = <&tlmm 64 0x00>; qcom,status-out-gpio = <&tlmm 63 0x00>; qcom,status-out2-gpio = <&tlmm 66 0x00>; + qcom,wakeup-gpio-in = <&tlmm 67 0x00>; + qcom,wakeup-gpio-out = <&tlmm 68 0x00>; }; diff --git a/drivers/soc/qcom/sdx_ext_ipc.c b/drivers/soc/qcom/sdx_ext_ipc.c index 2c4e9f764e08..9e4ee937b03f 100644 --- a/drivers/soc/qcom/sdx_ext_ipc.c +++ b/drivers/soc/qcom/sdx_ext_ipc.c @@ -17,7 +17,7 @@ #include #include #include - +#include enum subsys_policies { SUBSYS_PANIC = 0, @@ -33,6 +33,8 @@ enum gpios { STATUS_IN = 0, STATUS_OUT, STATUS_OUT2, + WAKEUP_OUT, + WAKEUP_IN, NUM_GPIOS, }; @@ -40,16 +42,20 @@ static const char * const gpio_map[] = { [STATUS_IN] = "qcom,status-in-gpio", [STATUS_OUT] = "qcom,status-out-gpio", [STATUS_OUT2] = "qcom,status-out2-gpio", + [WAKEUP_OUT] = "qcom,wakeup-gpio-out", + [WAKEUP_IN] = "qcom,wakeup-gpio-in", }; struct gpio_cntrl { unsigned int gpios[NUM_GPIOS]; int status_irq; + int wakeup_irq; int policy; struct device *dev; struct mutex policy_lock; struct mutex e911_lock; struct notifier_block panic_blk; + struct notifier_block sideband_nb; }; static ssize_t policy_show(struct device *dev, struct device_attribute *attr, @@ -128,6 +134,26 @@ static ssize_t e911_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(e911); +static int sideband_notify(struct notifier_block *nb, + unsigned long action, void *dev) +{ + struct gpio_cntrl *mdm = container_of(nb, + struct gpio_cntrl, sideband_nb); + + switch (action) { + + case EVT_WAKE_UP: + gpio_set_value(mdm->gpios[WAKEUP_OUT], 1); + usleep_range(10000, 20000); + gpio_set_value(mdm->gpios[WAKEUP_OUT], 0); + break; + default: + dev_info(mdm->dev, "Invalid action passed %d\n", + action); + } + return NOTIFY_OK; +} + static irqreturn_t ap_status_change(int irq, void *dev_id) { struct gpio_cntrl *mdm = dev_id; @@ -150,6 +176,12 @@ static irqreturn_t ap_status_change(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t sdx_ext_ipc_wakeup_irq(int irq, void *dev_id) +{ + pr_info("%s: Received\n", __func__); + return IRQ_HANDLED; +} + static void remove_ipc(struct gpio_cntrl *mdm) { int i; @@ -210,6 +242,35 @@ static int setup_ipc(struct gpio_cntrl *mdm) } else dev_info(mdm->dev, "STATUS_OUT2 not used\n"); + if (mdm->gpios[WAKEUP_OUT] >= 0) { + ret = gpio_request(mdm->gpios[WAKEUP_OUT], "WAKEUP_OUT"); + + if (ret) { + dev_err(mdm->dev, "Failed to configure WAKEUP_OUT gpio\n"); + return ret; + } + gpio_direction_output(mdm->gpios[WAKEUP_OUT], 0); + } else + dev_info(mdm->dev, "WAKEUP_OUT not used\n"); + + if (mdm->gpios[WAKEUP_IN] >= 0) { + ret = gpio_request(mdm->gpios[WAKEUP_IN], "WAKEUP_IN"); + + if (ret) { + dev_warn(mdm->dev, "Failed to configure WAKEUP_IN gpio\n"); + return ret; + } + gpio_direction_input(mdm->gpios[WAKEUP_IN]); + + irq = gpio_to_irq(mdm->gpios[WAKEUP_IN]); + if (irq < 0) { + dev_err(mdm->dev, "bad AP2MDM_STATUS IRQ resource\n"); + return irq; + } + mdm->wakeup_irq = irq; + } else + dev_info(mdm->dev, "WAKEUP_IN not used\n"); + return 0; } @@ -283,6 +344,32 @@ static int sdx_ext_ipc_probe(struct platform_device *pdev) } irq_set_irq_wake(mdm->status_irq, 1); } + + if (mdm->gpios[WAKEUP_IN] >= 0) { + ret = devm_request_threaded_irq(mdm->dev, mdm->wakeup_irq, + NULL, sdx_ext_ipc_wakeup_irq, + IRQF_TRIGGER_FALLING, "sdx_ext_ipc_wakeup", + mdm); + if (ret < 0) { + dev_err(mdm->dev, + "%s: WAKEUP_IN IRQ#%d request failed,\n", + __func__, mdm->status_irq); + goto irq_fail; + } + disable_irq(mdm->wakeup_irq); + } + + if (mdm->gpios[WAKEUP_OUT] >= 0) { + mdm->sideband_nb.notifier_call = sideband_notify; + ret = sb_register_evt_listener(&mdm->sideband_nb); + if (ret) { + dev_err(mdm->dev, + "%s: sb_register_evt_listener failed!\n", + __func__); + goto irq_fail; + } + } + return 0; irq_fail: @@ -313,6 +400,31 @@ static int sdx_ext_ipc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int sdx_ext_ipc_suspend(struct device *dev) +{ + struct gpio_cntrl *mdm = dev_get_drvdata(dev); + + if (mdm->gpios[WAKEUP_IN] >= 0) + enable_irq_wake(mdm->wakeup_irq); + return 0; +} + +static int sdx_ext_ipc_resume(struct device *dev) +{ + struct gpio_cntrl *mdm = dev_get_drvdata(dev); + + if (mdm->gpios[WAKEUP_IN] >= 0) + disable_irq_wake(mdm->wakeup_irq); + return 0; +} + +static const struct dev_pm_ops sdx_ext_ipc_pm_ops = { + .suspend = sdx_ext_ipc_suspend, + .resume = sdx_ext_ipc_resume, +}; +#endif + static const struct of_device_id sdx_ext_ipc_of_match[] = { { .compatible = "qcom,sdx-ext-ipc"}, { .compatible = "qcom,sa515m-ccard"}, @@ -326,6 +438,9 @@ static struct platform_driver sdx_ext_ipc_driver = { .name = "sdx-ext-ipc", .owner = THIS_MODULE, .of_match_table = sdx_ext_ipc_of_match, +#ifdef CONFIG_PM + .pm = &sdx_ext_ipc_pm_ops, +#endif }, }; -- GitLab From 71157fb47374815a8f75152debb8d2c55caf2f6e Mon Sep 17 00:00:00 2001 From: Shreyas K K Date: Fri, 19 Jun 2020 11:00:12 +0530 Subject: [PATCH 1047/1055] ARM64: dts: msm: Add wakeup support for sdx-ext-ipc devices Remote SoC needs to be waken up before initiating any transport layer interface (like USB, PCIe). Add two GPIOs (to the AP and modem) to handle to and fro of the wakeable interrupts. Change-Id: Id9d667e4beeb6d10662575120594cce42e7179d6 Signed-off-by: Shreyas K K --- arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi | 22 +++++++++++++++++++ .../boot/dts/qcom/sdxprairie-pinctrl.dtsi | 13 +++++++++++ arch/arm64/boot/dts/qcom/sdxprairie.dtsi | 4 ++++ 3 files changed, 39 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi b/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi index 304357a3195e..8b352bad0fcd 100644 --- a/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi +++ b/arch/arm64/boot/dts/qcom/sa2150p-ccard.dtsi @@ -24,6 +24,19 @@ output-high; }; }; + + wakeup_gpio_default: wakeup_gpio_default { + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + drive-strength = <2>; + bias-pull-down; + }; + }; }; &pcie0_perst_default { @@ -167,6 +180,15 @@ }; }; }; + + sdx_ext_ipc: qcom,sdx_ext_ipc { + compatible = "qcom,sdx-ext-ipc"; + qcom,wakeup-gpio-in = <&tlmm 14 0x00>; + qcom,wakeup-gpio-out = <&tlmm 79 0x00>; + pinctrl-names = "default"; + pinctrl-0 = <&wakeup_gpio_default>; + }; + }; &thermal_zones { diff --git a/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi index edba1fd6cdbb..aaf72774fa18 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie-pinctrl.dtsi @@ -1685,5 +1685,18 @@ bias-pull-down; }; }; + + wakeup_gpio_default: wakeup_gpio_default { + mux { + pins = "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio22"; + drive-strength = <2>; + bias-pull-down; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi index 7c1d5d4addd1..0cd7e85fa8c1 100644 --- a/arch/arm64/boot/dts/qcom/sdxprairie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdxprairie.dtsi @@ -1596,6 +1596,10 @@ qcom,status-in-gpio = <&tlmm 64 0x00>; qcom,status-out-gpio = <&tlmm 63 0x00>; qcom,status-out2-gpio = <&tlmm 66 0x00>; + qcom,wakeup-gpio-in = <&tlmm 87 0x00>; + qcom,wakeup-gpio-out = <&tlmm 22 0x00>; + pinctrl-names = "default"; + pinctrl-0 = <&wakeup_gpio_default>; status = "disabled"; }; }; -- GitLab From b7bddef6d270d0f9efdd55e3999ecd29c97ccd97 Mon Sep 17 00:00:00 2001 From: Mahesh Voorugonda Date: Tue, 23 Jun 2020 11:20:40 +0530 Subject: [PATCH 1048/1055] ARM: dts: qcom: add video device tree support for sdm429w Add video device tree node sdm429-vidc for sdm429w. Change-Id: Iff6764373bebfb38a43553d371c61fd8446f1a50 Signed-off-by: Mahesh Voorugonda --- arch/arm64/boot/dts/qcom/sdm429-vidc.dtsi | 168 ++++++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm429.dtsi | 1 + 2 files changed, 169 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdm429-vidc.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm429-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm429-vidc.dtsi new file mode 100644 index 000000000000..0fceee84ac5d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm429-vidc.dtsi @@ -0,0 +1,168 @@ +/* Copyright (c) 2015-2020, 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. + */ + +&soc { + qcom,vidc@1d00000 { + compatible = "qcom,msm-vidc"; + reg = <0x01d00000 0xff000>; + interrupts = <0 44 0>; + qcom,hfi-version = "3xx"; + venus-supply = <&venus_gdsc>; + venus-core0-supply = <&venus_core0_gdsc>; + clocks = <&gcc GCC_VENUS0_VCODEC0_CLK>, + <&gcc GCC_VENUS0_CORE0_VCODEC0_CLK>, + <&gcc GCC_VENUS0_AHB_CLK>, + <&gcc GCC_VENUS0_AXI_CLK>; + clock-names = "core_clk", "core0_clk", "iface_clk", "bus_clk"; + qcom,clock-configs = <0x1 0x0 0x0 0x0>; + qcom,sw-power-collapse; + qcom,slave-side-cp; + qcom,dcvs-tbl = + <108000 108000 244800 0x00000004>, /* Encoder */ + <108000 108000 244800 0x0f00000c>; /* Decoder */ + qcom,dcvs-limit = + <8160 30>, /* Encoder */ + <8160 30>; /* Decoder */ + qcom,hfi = "venus"; + qcom,reg-presets = <0xe0020 0x05555556>, + <0xe0024 0x05555556>, + <0x80124 0x00000003>; + qcom,qdss-presets = <0x826000 0x1000>, + <0x827000 0x1000>, + <0x822000 0x1000>, + <0x803000 0x1000>, + <0x9180000 0x1000>, + <0x9181000 0x1000>; + qcom,max-hw-load = <352800>; /* 1080p@30 + 720p@30 */ + qcom,firmware-name = "venus"; + qcom,allowed-clock-rates = <360000000 320000000 + 308570000 240000000 166150000>; + qcom,clock-freq-tbl { + qcom,profile-enc { + qcom,codec-mask = <0x55555555>; + qcom,cycles-per-mb = <2316>; + qcom,low-power-mode-factor = <32768>; + }; + qcom,profile-dec { + qcom,codec-mask = <0xf3ffffff>; + qcom,cycles-per-mb = <788>; + }; + qcom,profile-hevcdec { + qcom,codec-mask = <0x0c000000>; + qcom,cycles-per-mb = <1015>; + }; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = <&apps_iommu 0x800 0x00>, + <&apps_iommu 0x807 0x00>, + <&apps_iommu 0x808 0x27>, + <&apps_iommu 0x811 0x20>; + buffer-types = <0xfff>; + virtual-addr-pool = <0x5dc00000 0x7f000000 + 0xdcc00000 0x1000000>; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&apps_iommu 0x900 0x00>, + <&apps_iommu 0x90a 0x04>, + <&apps_iommu 0x909 0x22>; + buffer-types = <0x241>; + virtual-addr-pool = <0x4b000000 0x12c00000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&apps_iommu 0x90c 0x20>; + buffer-types = <0x106>; + virtual-addr-pool = <0x25800000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&apps_iommu 0x940 0x00>, + <&apps_iommu 0x907 0x08>, + <&apps_iommu 0x908 0x20>, + <&apps_iommu 0x90d 0x20>; + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + + /* Buses */ + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "venus-ddr-gov"; + qcom,bus-range-kbps = <1000 917000>; + }; + + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1 1>; + }; + }; + + venus-ddr-gov { + compatible = "qcom,msm-vidc,governor,table"; + name = "venus-ddr-gov"; + status = "ok"; + qcom,bus-freq-table { + qcom,profile-enc { + qcom,codec-mask = <0x55555555>; + qcom,load-busfreq-tbl = + <244800 841000>, /* 1080p30E */ + <216000 740000>, /* 720p60E */ + <194400 680000>, /* FWVGA120E */ + <144000 496000>, /* VGA120E */ + <108000 370000>, /* 720p30E */ + <97200 340000>, /* FWVGA60E */ + <48600 170000>, /* FWVGA30E */ + <72000 248000>, /* VGA60E */ + <36000 124000>, /* VGA30E */ + <18000 70000>, /* QVGA60E */ + <9000 35000>, /* QVGA30E */ + <0 0>; + }; + qcom,profile-dec { + qcom,codec-mask = <0xffffffff>; + qcom,load-busfreq-tbl = + <244800 605000>, /* 1080p30D */ + <216000 540000>, /* 720p60D */ + <194400 484000>, /* FWVGA120D */ + <144000 360000>, /* VGA120D */ + <108000 270000>, /* 720p30D */ + <97200 242000>, /* FWVGA60D */ + <48600 121000>, /* FWVGA30D */ + <72000 180000>, /* VGA60D */ + <36000 90000>, /* VGA30D */ + <18000 45000>, /* HVGA30D */ + <0 0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index f033cf299b0c..899b9f6e41cf 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -187,6 +187,7 @@ #include "sdm429-ion.dtsi" #include "msm-arm-smmu-sdm429.dtsi" #include "sdm429w-gpu.dtsi" +#include "sdm429-vidc.dtsi" &soc { #address-cells = <1>; #size-cells = <1>; -- GitLab From bf9213a9a2bc6aec7a0940ee9025b31e01ec1124 Mon Sep 17 00:00:00 2001 From: Jim Wang Date: Wed, 8 Jul 2020 19:16:41 -0400 Subject: [PATCH 1049/1055] ARM: dts: msm: change display-label to display-type for DSI0 Fix a typo that mistaking "display-type" as "display-label". Change-Id: I8f65c110c6855e567b60c94439abfa5b00e3e7e7 Signed-off-by: Jim Wang --- arch/arm64/boot/dts/qcom/sa6155-display.dtsi | 2 +- arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi | 2 +- arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sa6155-display.dtsi b/arch/arm64/boot/dts/qcom/sa6155-display.dtsi index 4556b60ff124..137d946a946d 100644 --- a/arch/arm64/boot/dts/qcom/sa6155-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sa6155-display.dtsi @@ -162,7 +162,7 @@ dsi_anx_7625_1: qcom,dsi-display@17 { label = "dsi_anx_7625_1"; qcom,dsi-display-active; - qcom,display-label = "primary"; + qcom,display-type = "primary"; qcom,dsi-ctrl-num = <0>; qcom,dsi-phy-num = <0>; diff --git a/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi b/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi index 9d3d1093e964..925a9c239c57 100644 --- a/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8155-adp-star-display.dtsi @@ -201,7 +201,7 @@ dsi_anx_7625_1: qcom,dsi-display@17 { label = "dsi_anx_7625_1"; qcom,dsi-display-active; - qcom,display-label = "primary"; + qcom,display-type = "primary"; qcom,dsi-ctrl-num = <0>; qcom,dsi-phy-num = <0>; diff --git a/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi b/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi index aa218ee813f0..36ffa616fecd 100644 --- a/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8195p-adp-star-display.dtsi @@ -243,7 +243,7 @@ dsi_anx_7625_1: qcom,dsi-display@17 { label = "dsi_anx_7625_1"; qcom,dsi-display-active; - qcom,display-label = "primary"; + qcom,display-type = "primary"; qcom,dsi-ctrl-num = <0>; qcom,dsi-phy-num = <0>; -- GitLab From ab2bc62ea26b280ea75ac5fcbcc10bb474f8c942 Mon Sep 17 00:00:00 2001 From: Arun Prakash Date: Sun, 1 Mar 2020 23:45:05 +0530 Subject: [PATCH 1050/1055] arm64: config: Enable Glink for GVM Enable Glink for GVM to support direct communication between GVM and CDSP. Change-Id: If9bfbdc89f3724d3657583a9483c64e36d27424f Signed-off-by: Arun Prakash --- arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig | 4 ++++ arch/arm64/configs/vendor/qti-quin-gvm_defconfig | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig b/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig index 9b8c8fa371d9..eae30c1b4fb0 100644 --- a/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig +++ b/arch/arm64/configs/vendor/qti-quin-gvm-perf_defconfig @@ -435,13 +435,16 @@ CONFIG_IPA_UT=y CONFIG_QCOM_CLK_VIRT=y CONFIG_VIRTIO_CLK=y CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y +CONFIG_QCOM_GVM_IPC=y CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_RPMSG_VIRTIO=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_QMI_HELPERS=y @@ -455,6 +458,7 @@ CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_GLINK=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_MSM_HAB=y CONFIG_QCOM_HGSL_TCSR_SIGNAL=y diff --git a/arch/arm64/configs/vendor/qti-quin-gvm_defconfig b/arch/arm64/configs/vendor/qti-quin-gvm_defconfig index b2efa820a67f..1559e097deeb 100644 --- a/arch/arm64/configs/vendor/qti-quin-gvm_defconfig +++ b/arch/arm64/configs/vendor/qti-quin-gvm_defconfig @@ -446,13 +446,16 @@ CONFIG_IPA_UT=y CONFIG_QCOM_CLK_VIRT=y CONFIG_VIRTIO_CLK=y CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y +CONFIG_QCOM_GVM_IPC=y CONFIG_IOMMU_IO_PGTABLE_FAST=y CONFIG_ARM_SMMU=y CONFIG_QCOM_LAZY_MAPPING=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_RPMSG_VIRTIO=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_QMI_HELPERS=y @@ -466,6 +469,7 @@ CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_GLINK=y CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_MSM_HAB=y CONFIG_QCOM_HGSL_TCSR_SIGNAL=y -- GitLab From f842981d0b8db869bdede2009ee3c4a4d361fcfe Mon Sep 17 00:00:00 2001 From: Arun Prakash Date: Sun, 17 May 2020 21:05:13 +0530 Subject: [PATCH 1051/1055] rpmsg: glink: Changing interrupt trigger option Adding IRQF_TRIGGER_RISING option for glink IN interrupt. This option is required to receive interrupt from primary host through virtual irq line. Change-Id: Ib854e9fe9409690461b7a74b709c294f89cb3888 Signed-off-by: Arun Prakash --- drivers/rpmsg/qcom_glink_native.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index 069b06584969..2b051b54ae4b 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -1974,6 +1974,8 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, bool intentless) { struct qcom_glink *glink; + unsigned long irqflags; + bool vm_support; u32 *arr; int size; int irq; @@ -2032,9 +2034,17 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, dev_err(dev, "failed to register early notif %d\n", ret); irq = of_irq_get(dev->of_node, 0); + + /* Use different irq flag option in case of gvm */ + vm_support = of_property_read_bool(dev->of_node, "vm-support"); + if (vm_support) + irqflags = IRQF_TRIGGER_RISING; + else + irqflags = IRQF_NO_SUSPEND | IRQF_SHARED; + ret = devm_request_irq(dev, irq, qcom_glink_native_intr, - IRQF_NO_SUSPEND | IRQF_SHARED, + irqflags, "glink-native", glink); if (ret) { dev_err(dev, "failed to request IRQ\n"); -- GitLab From 721430947cc1776ca90321ffdac8e142a48bf268 Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Thu, 25 Jun 2020 23:51:36 +0530 Subject: [PATCH 1052/1055] documentation: bindings: spi_qsd: Add shared ee dtsi flag Add shared EE property of spi node to support the shared EE usecases. Change-Id: Ie5b744184ea5aede481a3fad807589484207ab69 Signed-off-by: Prudhvi Yarlagadda --- Documentation/devicetree/bindings/spi/spi_qsd.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt index 1edf0820398a..7c0b2a4df208 100644 --- a/Documentation/devicetree/bindings/spi/spi_qsd.txt +++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt @@ -36,7 +36,13 @@ Optional properties: - qcom,rt-priority : whether spi message queue is set to run as a realtime task. With this spi transaction message pump with high (realtime) priority to reduce the transfer latency on the bus by minimising the delay between a transfer request - - qcom,shared : whether this qup is shared with other ee's + - qcom,shared : whether this qup is shared with other ee's and client driver is not + in control of the spi driver get_sync/put_sync_suspend. Spi driver will + take care of resources management like clock, gpios and bam for EE switching. + - qcom,shared_ee : whether this qup is used by other ee's and client driver is in + control of the spi driver get_sync/put_sync_suspend. Resources management + of clock, gpios and bam for EE switching will be taken care when client calls spi + get_sync/put_sync_suspend APIs. Optional properties which are required for support of BAM-mode: - qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW -- GitLab From cd90c0a7308c3cc32c674562e2e3963a52b875bf Mon Sep 17 00:00:00 2001 From: Prudhvi Yarlagadda Date: Tue, 9 Jun 2020 12:26:10 +0530 Subject: [PATCH 1053/1055] spi: spi_qsd: Add Shared EE property check for spi Add Shared EE property check for spi to support dual EE use case. Have the prepare_message/unprepare_message API support for spi for Dual EE use case so that client can have control for spi driver get_sync, put_sync by calling the APIs pm_runtime_get_sync and pm_runtime_put_sync_suspend and use them when switching to other EEs. This will allow client driver to remove the delay/wait time while switching between the secure and non-secure EEs. Change-Id: I465bc4b9036b3b9701a876825412b55b4d4134c7 Signed-off-by: Prudhvi Yarlagadda --- drivers/spi/spi_qsd.c | 99 ++++++++++++++++++++++++++++++------ include/linux/spi/qcom-spi.h | 8 ++- 2 files changed, 89 insertions(+), 18 deletions(-) diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c index e7d7efacfda7..1cca65f186eb 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-2018, 2020 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 @@ -1703,28 +1703,82 @@ static int msm_spi_transfer_one(struct spi_master *master, return status_error; } -static int msm_spi_prepare_transfer_hardware(struct spi_master *master) +static int msm_spi_pm_get_sync(struct device *dev) { - struct msm_spi *dd = spi_master_get_devdata(master); - int resume_state = 0; - - resume_state = pm_runtime_get_sync(dd->dev); - if (resume_state < 0) - goto spi_finalize; + int ret; /* * Counter-part of system-suspend when runtime-pm is not enabled. * This way, resume can be left empty and device will be put in * active mode only if client requests anything on the bus */ - if (!pm_runtime_enabled(dd->dev)) - resume_state = msm_spi_pm_resume_runtime(dd->dev); + if (!pm_runtime_enabled(dev)) { + dev_info(dev, "%s: pm_runtime not enabled\n", __func__); + ret = msm_spi_pm_resume_runtime(dev); + } else { + ret = pm_runtime_get_sync(dev); + } + + return ret; +} + +static int msm_spi_pm_put_sync(struct device *dev) +{ + int ret = 0; + + if (!pm_runtime_enabled(dev)) { + dev_info(dev, "%s: pm_runtime not enabled\n", __func__); + ret = msm_spi_pm_suspend_runtime(dev); + } else { + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + } + + return ret; +} + +static int msm_spi_prepare_message(struct spi_master *master, + struct spi_message *spi_msg) +{ + struct msm_spi *dd = spi_master_get_devdata(master); + int resume_state; + + resume_state = msm_spi_pm_get_sync(dd->dev); if (resume_state < 0) - goto spi_finalize; - if (dd->suspended) { - resume_state = -EBUSY; - goto spi_finalize; + return resume_state; + + return 0; +} + +static int msm_spi_unprepare_message(struct spi_master *master, + struct spi_message *spi_msg) +{ + struct msm_spi *dd = spi_master_get_devdata(master); + int ret; + + ret = msm_spi_pm_put_sync(dd->dev); + if (ret < 0) + return ret; + + return 0; +} + +static int msm_spi_prepare_transfer_hardware(struct spi_master *master) +{ + struct msm_spi *dd = spi_master_get_devdata(master); + int resume_state; + + if (!dd->pdata->shared_ee) { + resume_state = msm_spi_pm_get_sync(dd->dev); + if (resume_state < 0) + goto spi_finalize; + + if (dd->suspended) { + resume_state = -EBUSY; + goto spi_finalize; + } } + return 0; spi_finalize: @@ -1735,9 +1789,14 @@ static int msm_spi_prepare_transfer_hardware(struct spi_master *master) static int msm_spi_unprepare_transfer_hardware(struct spi_master *master) { struct msm_spi *dd = spi_master_get_devdata(master); + int ret; + + if (!dd->pdata->shared_ee) { + ret = msm_spi_pm_put_sync(dd->dev); + if (ret < 0) + return ret; + } - pm_runtime_mark_last_busy(dd->dev); - pm_runtime_put_autosuspend(dd->dev); return 0; } @@ -2233,6 +2292,8 @@ static struct msm_spi_platform_data *msm_spi_dt_to_pdata( &pdata->rt_priority, DT_OPT, DT_BOOL, 0}, {"qcom,shared", &pdata->is_shared, DT_OPT, DT_BOOL, 0}, + {"qcom,shared_ee", + &pdata->shared_ee, DT_OPT, DT_BOOL, 0}, {NULL, NULL, 0, 0, 0}, }; @@ -2558,6 +2619,12 @@ static int msm_spi_probe(struct platform_device *pdev) goto err_probe_reqmem; } + /* This property is required for Dual EE use case of spi */ + if (dd->pdata->shared_ee) { + master->prepare_message = msm_spi_prepare_message; + master->unprepare_message = msm_spi_unprepare_message; + } + pm_runtime_set_autosuspend_delay(&pdev->dev, MSEC_PER_SEC); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/include/linux/spi/qcom-spi.h b/include/linux/spi/qcom-spi.h index 099ad965fc8b..137fc66be6e8 100644 --- a/include/linux/spi/qcom-spi.h +++ b/include/linux/spi/qcom-spi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, 2020 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 @@ -34,7 +34,10 @@ * @bam_producer_pipe_index BAM producer pipe * @rt_priority true if RT thread * @use_pinctrl true if pinctrl library is used - * @is_shared true when qup is shared between ee's + * @is_shared true when qup is shared between ee's and client driver is not + in control of spi pm_runtime_get_sync/put_sync. + * @shared_ee true when qup is shared between ee's and client driver is in + control of spi pm_runtime_get_sync/put_sync. */ struct msm_spi_platform_data { u32 max_clock_speed; @@ -53,4 +56,5 @@ struct msm_spi_platform_data { bool rt_priority; bool use_pinctrl; bool is_shared; + bool shared_ee; }; -- GitLab From 0b015f84c5756d778e1c72dce86489d1f69ccf29 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Wed, 10 Jun 2020 16:54:51 +0530 Subject: [PATCH 1054/1055] wcnss: Register wlan driver ops for SMD notification Register wlan driver ops for SMD notification to handle driver recovery during ssr. Change-Id: Ib2026a5913ccbed92582846262fc98fe8a016040 Signed-off-by: Govind Singh --- drivers/soc/qcom/wcnss/wcnss_wlan.c | 70 +++++++++++++++++++++++++++++ include/linux/wcnss_wlan.h | 13 ++++++ 2 files changed, 83 insertions(+) diff --git a/drivers/soc/qcom/wcnss/wcnss_wlan.c b/drivers/soc/qcom/wcnss/wcnss_wlan.c index a7c809d710ce..2ec29350f6f8 100644 --- a/drivers/soc/qcom/wcnss/wcnss_wlan.c +++ b/drivers/soc/qcom/wcnss/wcnss_wlan.c @@ -476,6 +476,8 @@ static struct { dev_t dev_ctrl, dev_node; struct class *node_class; struct cdev ctrl_dev, node_dev; + unsigned long state; + struct wcnss_driver_ops *ops; } *penv = NULL; static void *wcnss_ipc_log; @@ -1564,6 +1566,8 @@ static int wcnss_ctrl_probe(struct rpmsg_device *rpdev) if (penv->wlan_config.is_pronto_vadc && penv->adc_channel) schedule_work(&penv->wcnss_vadc_work); + penv->state = WCNSS_SMD_OPEN; + return 0; } @@ -1583,6 +1587,8 @@ static int wcnss_rpmsg_resource_init(void) INIT_LIST_HEAD(&penv->event_list); spin_lock_init(&penv->event_lock); + penv->state = WCNSS_SMD_CLOSE; + return 0; } @@ -1698,6 +1704,58 @@ int wcnss_wlan_get_dxe_rx_irq(struct device *dev) } EXPORT_SYMBOL(wcnss_wlan_get_dxe_rx_irq); +int wcnss_register_driver(struct wcnss_driver_ops *ops, void *priv) +{ + int ret = 0; + + if (!penv || !penv->pdev) { + ret = -ENODEV; + goto out; + } + + wcnss_log(ERR, "Registering driver, state: 0x%lx\n", penv->state); + + if (penv->ops) { + wcnss_log(ERR, "Driver already registered\n"); + ret = -EEXIST; + goto out; + } + + penv->ops = ops; + penv->ops->priv_data = priv; + + if (penv->state == WCNSS_SMD_OPEN) + ops->driver_state(ops->priv_data, WCNSS_SMD_OPEN); + +out: + return ret; +} +EXPORT_SYMBOL(wcnss_register_driver); + +int wcnss_unregister_driver(struct wcnss_driver_ops *ops) +{ + int ret; + + if (!penv || !penv->pdev) { + ret = -ENODEV; + goto out; + } + + wcnss_log(ERR, "Unregistering driver, state: 0x%lx\n", penv->state); + + if (!penv->ops) { + wcnss_log(ERR, "Driver not registered\n"); + ret = -ENOENT; + goto out; + } + + penv->ops = NULL; + +out: + return ret; +} +EXPORT_SYMBOL(wcnss_unregister_driver); + void wcnss_wlan_register_pm_ops(struct device *dev, const struct dev_pm_ops *pm_ops) { @@ -2319,6 +2377,11 @@ static void wcnss_process_smd_msg(void *buf, int len) nvresp->status); if (nvresp->status != WAIT_FOR_CBC_IND) penv->is_cbc_done = 1; + + if (penv->ops) + penv->ops->driver_state(penv->ops->priv_data, + WCNSS_SMD_OPEN); + wcnss_setup_vbat_monitoring(); break; @@ -3407,6 +3470,7 @@ static int wcnss_notif_cb(struct notifier_block *this, unsigned long code, struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config(); struct notif_data *data = (struct notif_data *)ss_handle; int ret, xo_mode; + void *priv; if (!(code >= SUBSYS_NOTIF_MIN_INDEX) && (code <= SUBSYS_NOTIF_MAX_INDEX)) { @@ -3442,6 +3506,12 @@ static int wcnss_notif_cb(struct notifier_block *this, unsigned long code, schedule_delayed_work(&penv->wcnss_pm_qos_del_req, msecs_to_jiffies(WCNSS_PM_QOS_TIMEOUT)); penv->is_shutdown = 1; + + if (penv->ops) { + priv = penv->ops->priv_data; + penv->ops->driver_state(priv, WCNSS_SMD_CLOSE); + } + wcnss_log_debug_regs_on_bite(); } else if (code == SUBSYS_POWERUP_FAILURE) { if (pdev && pwlanconfig) diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index 678a65f8baba..4d814a42e0e2 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -100,11 +100,24 @@ enum wcnss_log_type { #define PRONTO_PMU_OFFSET 0x1004 #define WCNSS_PMU_CFG_GC_BUS_MUX_SEL_TOP BIT(5) +enum wcnss_driver_state { + WCNSS_SMD_OPEN, + WCNSS_SMD_CLOSE, +}; + +struct wcnss_driver_ops { + char *name; + void *priv_data; + int (*driver_state)(void *priv, enum wcnss_driver_state state); +}; + struct device *wcnss_wlan_get_device(void); void wcnss_get_monotonic_boottime(struct timespec *ts); struct resource *wcnss_wlan_get_memory_map(struct device *dev); int wcnss_wlan_get_dxe_tx_irq(struct device *dev); int wcnss_wlan_get_dxe_rx_irq(struct device *dev); +int wcnss_register_driver(struct wcnss_driver_ops *ops, void *priv); +int wcnss_unregister_driver(struct wcnss_driver_ops *ops); void wcnss_wlan_register_pm_ops(struct device *dev, const struct dev_pm_ops *pm_ops); void wcnss_wlan_unregister_pm_ops(struct device *dev, -- GitLab From 6b42a54e382c9d101eae6093c1f210cc519e785f Mon Sep 17 00:00:00 2001 From: Rishi Gupta Date: Sat, 11 Jul 2020 20:08:13 +0530 Subject: [PATCH 1055/1055] defconfig: sa2150p: enable helper APIs for sideband notifications This commit enables driver which provides helper APIs so that transport layer drivers like USB can talk to sideband driver using kernel notifiers mechanism. Change-Id: I25bd6544807ec81bba489450dfe323b508c5d25f Signed-off-by: Rishi Gupta --- arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig | 1 + arch/arm64/configs/vendor/sa2150p-nand_defconfig | 1 + arch/arm64/configs/vendor/sa2150p-perf_defconfig | 1 + arch/arm64/configs/vendor/sa2150p_defconfig | 1 + 4 files changed, 4 insertions(+) diff --git a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig index fa2267ccc887..8949cf9519a0 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand-perf_defconfig @@ -406,6 +406,7 @@ CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_DCC_V2=y CONFIG_SDX_EXT_IPC=y +CONFIG_QTI_NOTIFY_SIDEBAND=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y diff --git a/arch/arm64/configs/vendor/sa2150p-nand_defconfig b/arch/arm64/configs/vendor/sa2150p-nand_defconfig index a93cdf7d2a70..1f8ddc2423f6 100644 --- a/arch/arm64/configs/vendor/sa2150p-nand_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-nand_defconfig @@ -424,6 +424,7 @@ CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_DCC_V2=y CONFIG_SDX_EXT_IPC=y +CONFIG_QTI_NOTIFY_SIDEBAND=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y diff --git a/arch/arm64/configs/vendor/sa2150p-perf_defconfig b/arch/arm64/configs/vendor/sa2150p-perf_defconfig index 8ccd6b3f09a6..8999e9e723b1 100644 --- a/arch/arm64/configs/vendor/sa2150p-perf_defconfig +++ b/arch/arm64/configs/vendor/sa2150p-perf_defconfig @@ -418,6 +418,7 @@ CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_QCOM_DCC_V2=y CONFIG_SDX_EXT_IPC=y +CONFIG_QTI_NOTIFY_SIDEBAND=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y diff --git a/arch/arm64/configs/vendor/sa2150p_defconfig b/arch/arm64/configs/vendor/sa2150p_defconfig index c5b2630d9bd5..dc423314434c 100644 --- a/arch/arm64/configs/vendor/sa2150p_defconfig +++ b/arch/arm64/configs/vendor/sa2150p_defconfig @@ -436,6 +436,7 @@ CONFIG_MSM_BOOT_TIME_MARKER=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_DCC_V2=y CONFIG_SDX_EXT_IPC=y +CONFIG_QTI_NOTIFY_SIDEBAND=y CONFIG_QCOM_BUS_SCALING=y CONFIG_MSM_TZ_SMMU=y CONFIG_QCOM_GLINK=y -- GitLab